io.seldon.clustering.recommender.RecommendationContext.java Source code

Java tutorial

Introduction

Here is the source code for io.seldon.clustering.recommender.RecommendationContext.java

Source

/*
 * 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.clustering.recommender;

import io.seldon.api.state.options.DefaultOptions;
import io.seldon.recommendation.AlgorithmStrategy;
import io.seldon.recommendation.ItemFilter;
import io.seldon.recommendation.ItemIncluder;
import io.seldon.recommendation.filters.FilteredItems;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang3.BooleanUtils;
import org.apache.log4j.Logger;

/**
 *
 * Information that the Item Recommendation algorithms require to calculate what they should recommend. The main concept
 * is the 'mode'. Inclusion mode means that the context items are a set of items to recommend from, where as exclusion
 * mode means that they context items are a set of items to exclude from the recommendations.
 *
 * @author firemanphil
 *         Date: 25/11/14
 *         Time: 16:06
 */
public class RecommendationContext {

    private static final String ITEMS_PER_INCLUDER_OPTION_NAME = "io.seldon.algorithm.inclusion.itemsperincluder";
    private static Logger logger = Logger.getLogger(RecommendationContext.class.getName());
    private final String lastRecListUUID;

    private final OptionsHolder optsHolder;

    public enum MODE {
        INCLUSION, EXCLUSION, NONE
    }

    private final MODE mode;
    private final Set<Long> contextItems;
    private final Set<Long> exclusionItems;
    private final List<String> inclusionKeys;
    private final Long currentItem;

    public RecommendationContext(MODE mode, Set<Long> contextItems, Set<Long> exclusionItems,
            List<String> inclusionKeys, Long currentItem, String lastRecListUUID, OptionsHolder optsHolder) {
        if (logger.isDebugEnabled())
            logger.debug("Built new rec context object in mode " + mode.name());

        this.mode = mode;
        this.contextItems = contextItems;
        this.exclusionItems = exclusionItems;
        this.currentItem = currentItem;
        this.inclusionKeys = inclusionKeys;
        this.lastRecListUUID = lastRecListUUID;
        this.optsHolder = optsHolder;
    }

    public String getLastRecListUUID() {
        return lastRecListUUID;
    }

    public MODE getMode() {
        return mode;
    }

    public Set<Long> getContextItems() {
        return contextItems;
    }

    public Set<Long> getExclusionItems() {
        return exclusionItems;
    }

    public List<String> getInclusionKeys() {
        return inclusionKeys;
    }

    public Long getCurrentItem() {
        return currentItem;
    }

    public OptionsHolder getOptsHolder() {
        return optsHolder;
    }

    public static RecommendationContext buildContext(String client, AlgorithmStrategy strategy, Long user,
            String clientUserId, Long currentItem, Set<Integer> dimensions, String lastRecListUUID,
            int numRecommendations, DefaultOptions defaultOptions, FilteredItems includedItems) {

        OptionsHolder optsHolder = new OptionsHolder(defaultOptions, strategy.config);
        List<String> inclusionKeys = new ArrayList<String>();
        Set<Long> contextItems = new HashSet<>();

        if (includedItems != null) {
            contextItems.addAll(includedItems.getItems());
            inclusionKeys.add(includedItems.getCachingKey());
            return new RecommendationContext(MODE.INCLUSION, contextItems, Collections.<Long>emptySet(),
                    inclusionKeys, currentItem, lastRecListUUID, optsHolder);
        }

        Set<ItemIncluder> inclusionProducers = strategy.includers;
        Set<ItemFilter> itemFilters = strategy.filters;
        if (inclusionProducers == null || inclusionProducers.size() == 0) {
            if (itemFilters == null || itemFilters.size() == 0) {
                logger.warn("No filters or includers present in strategy");
                return new RecommendationContext(MODE.NONE, Collections.<Long>emptySet(),
                        Collections.<Long>emptySet(), Collections.<String>emptyList(), currentItem, lastRecListUUID,
                        optsHolder);
            }
            for (ItemFilter filter : itemFilters) {
                contextItems.addAll(filter.produceExcludedItems(client, user, clientUserId, optsHolder, currentItem,
                        lastRecListUUID, numRecommendations));
            }
            return new RecommendationContext(MODE.EXCLUSION, contextItems, contextItems, inclusionKeys, currentItem,
                    lastRecListUUID, optsHolder);
        }

        Integer itemsPerIncluder = optsHolder.getIntegerOption(ITEMS_PER_INCLUDER_OPTION_NAME);
        if (itemFilters == null || itemFilters.size() == 0) {
            for (ItemIncluder producer : inclusionProducers) {
                FilteredItems filteredItems = producer.generateIncludedItems(client, dimensions, itemsPerIncluder);
                contextItems.addAll(filteredItems.getItems());
                inclusionKeys.add(filteredItems.getCachingKey());
            }
            return new RecommendationContext(MODE.INCLUSION, contextItems, Collections.<Long>emptySet(),
                    inclusionKeys, currentItem, lastRecListUUID, optsHolder);
        }

        Set<Long> included = new HashSet<>();
        Set<Long> excluded = new HashSet<>();
        for (ItemFilter filter : itemFilters) {
            excluded.addAll(filter.produceExcludedItems(client, user, clientUserId, optsHolder, currentItem,
                    lastRecListUUID, numRecommendations));
        }
        for (ItemIncluder producer : inclusionProducers) {
            FilteredItems filteredItems = producer.generateIncludedItems(client, dimensions, itemsPerIncluder);
            included.addAll(filteredItems.getItems());
            inclusionKeys.add(filteredItems.getCachingKey());
        }
        included.removeAll(excluded); // ok to do this as the excluded items that weren't in "included" will never
                                      // be recommended

        return new RecommendationContext(MODE.INCLUSION, included, excluded, inclusionKeys, currentItem,
                lastRecListUUID, optsHolder);
    }

    public static class OptionsHolder {

        private final DefaultOptions defaultOptions;
        private final Map<String, String> options;

        public OptionsHolder(DefaultOptions options, Map<String, String> perStrategyOptions) {
            this.defaultOptions = options;
            this.options = perStrategyOptions;
        }

        public String getStringOption(String optionName) {
            if (options.containsKey(optionName))
                return options.get(optionName);
            return defaultOptions.getOption(optionName);
        }

        public boolean getBooleanOption(String optionName) {

            if (options.containsKey(optionName))
                return BooleanUtils.toBoolean(options.get(optionName));
            else
                return BooleanUtils.toBoolean(defaultOptions.getOption(optionName));

        }

        public Double getDoubleOption(String optionName) {
            try {
                if (options.containsKey(optionName))
                    return Double.parseDouble(options.get(optionName));
                else
                    return Double.parseDouble(defaultOptions.getOption(optionName));
            } catch (NumberFormatException | NullPointerException e) {
                logger.error("Couldn't get algorithm option " + optionName, e);
                return 0.0D;
            }
        }

        public Integer getIntegerOption(String optionName) {
            try {
                if (options.containsKey(optionName))
                    return Integer.parseInt(options.get(optionName));
                else
                    return Integer.parseInt(defaultOptions.getOption(optionName));
            } catch (NumberFormatException | NullPointerException e) {
                logger.error("Couldn't get algorithm option " + optionName, e);
                return 0;
            }
        }

    }

}