/* * 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.recommendation; import io.seldon.recommendation.combiner.AlgorithmResultsCombiner; import java.math.BigDecimal; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import org.apache.commons.lang.math.NumberRange; import org.apache.commons.lang.math.Range; import org.apache.mahout.math.MurmurHash; /** * Client strategy for testing different lists of algorithm strategies against each other. Different users get shown * different strategies but a given user will always be shown the same set. * @author firemanphil * Date: 02/12/14 * Time: 14:16 */ public class VariationTestingClientStrategy implements ClientStrategy { private final Map<Range, ClientStrategy> strategyMap; private static final int HASH_SEED = 5795; private VariationTestingClientStrategy(Map<Range, ClientStrategy> strategyMap) { this.strategyMap = strategyMap; } @Override public Double getDiversityLevel(String userId,String recTag) { return sample(userId).getDiversityLevel(userId, recTag); } @Override public List<AlgorithmStrategy> getAlgorithms(String userId, String recTag) { return sample(userId).getAlgorithms(userId, recTag); } @Override public AlgorithmResultsCombiner getAlgorithmResultsCombiner(String userId,String recTag) { return sample(userId).getAlgorithmResultsCombiner(userId, recTag); } @Override public String getName(String userId, String recTag) { return sample(userId).getName(userId, recTag); } @Override public Map<Integer, Double> getActionsWeights(String userId, String recTag) { return sample(userId).getActionsWeights(userId, recTag); } public ClientStrategy sample(String userId) { Integer hash = MurmurHash.hash(userId.getBytes(), HASH_SEED); int sample = Math.abs(hash % 100) + 1; BigDecimal sampleDec = BigDecimal.valueOf(sample).divide(BigDecimal.valueOf(100)); for (Range range : strategyMap.keySet()) { if (range.containsNumber(sampleDec)) { return strategyMap.get(range); } } return null; } public static VariationTestingClientStrategy build(List<Variation> variations){ Map<Range, ClientStrategy> strategyMap = new LinkedHashMap<>(); BigDecimal ratioTotal = BigDecimal.ZERO; for (Variation var : variations){ ratioTotal = ratioTotal.add(var.ratio); } BigDecimal currentMax = BigDecimal.ZERO; for(Variation var : variations){ NumberRange range = new NumberRange(currentMax, currentMax.add(var.ratio.divide(ratioTotal, 5, BigDecimal.ROUND_UP))); strategyMap.put(range,var.variationStrategy); currentMax = currentMax.add(var.ratio); } return new VariationTestingClientStrategy(strategyMap); } public static class Variation{ public final ClientStrategy variationStrategy; public final BigDecimal ratio; public Variation(ClientStrategy variationStrategy, BigDecimal ratio) { this.variationStrategy = variationStrategy; this.ratio = ratio; } } }