/*
* Seldon -- open source prediction engine
* =======================================
*
* Copyright 2011-2015 Seldon Technologies Ltd and Rummble Ltd (http://www.seldon.io/)
*
* ********************************************************************************************
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ********************************************************************************************
*/
package io.seldon.api.service;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import io.seldon.memcache.MemCacheKeys;
import io.seldon.memcache.MemCachePeer;
import io.seldon.recommendation.CFAlgorithm;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
public class ABTestingServer {
private static Logger logger = Logger.getLogger(ABTestingServer.class.getName());
private static Map<String,ABTest> tests = new ConcurrentHashMap<>();
//max period for the a/b testing
private final static int CACHING_TIME = 86400;
private static String getABTestKey(String consumer,String recTag)
{
return recTag == null ? consumer : consumer+":"+recTag;
}
//GET ALGORITHM FOR A USER
public static CFAlgorithm getUserTest(String consumer, String recTag,String clientUserId) {
CFAlgorithm res = null;
final String abTestKey = getABTestKey(consumer, recTag);
ABTest abTest = tests.get(abTestKey);
if (abTest != null)
{
String mKey = MemCacheKeys.getABTestingUser(abTestKey, clientUserId, abTest.getAlgorithm().getAbTestingKey());
Boolean inTest = (Boolean) MemCachePeer.get(mKey);
if (inTest == null)
{
// decide whether this user should be in test and store in memcache
if (Math.random() <= abTest.getPercentage())
{
MemCachePeer.put(mKey, new Boolean(true),CACHING_TIME);
res = abTest.getAlgorithm();
}
else
{
//Store the fact this user is not in the test
MemCachePeer.put(mKey, new Boolean(false),CACHING_TIME);
}
}
else if (inTest)
{
res = abTest.getAlgorithm();
}
}
return res;
}
public static void setABTest(String consumer, ABTest abTest)
{
if (abTest == null)
{
logger.error("Attempt to store null abTest for consumer "+consumer);
}
else if (abTest.getAlgorithm() == null)
{
logger.error("Attempt to store null algorithm for consumer "+consumer);
}
else if (StringUtils.isEmpty(abTest.getAlgorithm().getAbTestingKey()))
{
logger.error("Empty AB Test key for consumer "+consumer);
}
else
{
final String abTestKey = getABTestKey(consumer, abTest.getAlgorithm().getRecTag());
logger.info("Adding new AB Test for consumer "+abTestKey+" with key "+abTest.getAlgorithm().getAbTestingKey()+" Algoritm:"+abTest.getAlgorithm().toString());
tests.put(abTestKey, abTest);
}
}
public static ABTest getABTest(String consumer,String recTag)
{
final String abTestKey = getABTestKey(consumer, recTag);
return tests.get(abTestKey);
}
}