Java tutorial
/* * 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.Constants; import io.seldon.api.Util; import io.seldon.api.resource.ConsumerBean; import io.seldon.api.resource.service.ItemService; import io.seldon.general.ItemPeer; import io.seldon.memcache.DogpileHandler; import io.seldon.memcache.MemCacheKeys; import io.seldon.memcache.MemCachePeer; import io.seldon.memcache.UpdateRetriever; import io.seldon.recommendation.RecommendationUtils; import io.seldon.util.CollectionTools; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; public class CountRecommender { private static Logger logger = Logger.getLogger(CountRecommender.class.getName()); UserClusterStore userClusters; ClusterCountStore clusterCounts; IClusterFromReferrer clusterFromReferrer; String client; boolean fillInZerosWithMostPopular = true; String referrer; private static int EXPIRE_COUNTS = 300; private static int EXPIRE_USER_CLUSTERS = 600; public static final int BUCKET_CLUSTER_ID = -1; public CountRecommender(String client, UserClusterStore userClusters, ClusterCountStore clusterCounts, IClusterFromReferrer clusterFromReferrer) { this.userClusters = userClusters; this.clusterCounts = clusterCounts; this.client = client; this.clusterFromReferrer = clusterFromReferrer; } public String getReferrer() { return referrer; } public void setReferrer(String referrer) { this.referrer = referrer; } private Set<Integer> getReferrerClusters() { if (referrer != null) { if (clusterFromReferrer != null) return clusterFromReferrer.getClusters(referrer); else return null; } else return null; } /** * * @param userId * @param itemId * @param time - in secs */ public void addCount(long userId, long itemId, long time, boolean useBucketCluster, Double actionWeight) { if (actionWeight == null) actionWeight = 1.0D; List<UserCluster> clusters = getClusters(userId, null); if (clusters != null && clusters.size() > 0) { for (UserCluster cluster : clusters) clusterCounts.add(cluster.getCluster(), itemId, cluster.getWeight() * actionWeight, cluster.getTimeStamp(), time); } else if (useBucketCluster) { clusterCounts.add(BUCKET_CLUSTER_ID, itemId, actionWeight, 0, time); } Set<Integer> referrerClusters = getReferrerClusters(); if (referrerClusters != null) { for (Integer cluster : referrerClusters) { clusterCounts.add(cluster, itemId, actionWeight, 0, time); } } } public void addCount(long userId, long itemId, boolean useBucketCluster, Double actionWeight) { if (actionWeight == null) actionWeight = 1.0D; List<UserCluster> clusters = getClusters(userId, null); if (clusters != null && clusters.size() > 0) { for (UserCluster cluster : clusters) clusterCounts.add(cluster.getCluster(), itemId, cluster.getWeight() * actionWeight, cluster.getTimeStamp()); } else if (useBucketCluster) { clusterCounts.add(BUCKET_CLUSTER_ID, itemId, actionWeight, 0); } Set<Integer> referrerClusters = getReferrerClusters(); if (referrerClusters != null) { for (Integer cluster : referrerClusters) { clusterCounts.add(cluster, itemId, actionWeight, 0); } } } public Map<Long, Double> recommendUsingTag(Map<String, Float> tagWeights, int tagAttrId, Set<Integer> dimensions, Integer dimension2, int numRecommendations, Set<Long> exclusions, double decay, int minNumItems) { boolean checkDimension = !(dimensions.isEmpty() || (dimensions.size() == 1 && dimensions.iterator().next() == Constants.DEFAULT_DIMENSION)); int minAllowed = minNumItems < numRecommendations ? minNumItems : numRecommendations; Map<Long, Double> counts = new HashMap<>(); int numTopCounts = numRecommendations * 2; // number of counts to get - defaults to twice the final number recommendations to return for (Map.Entry<String, Float> e : tagWeights.entrySet()) { updateTagCounts(e.getKey(), e.getValue(), tagAttrId, dimensions, dimension2, checkDimension, numTopCounts, exclusions, counts, decay); } if (counts.keySet().size() < minAllowed) { if (logger.isDebugEnabled()) logger.debug("Number of tag items found " + counts.keySet().size() + " is less than " + minAllowed + " so returning empty recommendation for cluster tag item recommender"); return new HashMap<>(); } else if (logger.isDebugEnabled()) logger.debug("Number of tag items found " + counts.keySet().size()); return RecommendationUtils.rescaleScoresToOne(counts, numRecommendations); } private void updateTagCounts(String tag, Float tagWeight, int tagAttrId, Set<Integer> dimensions, Integer dimension2, boolean checkDimension, int limit, Set<Long> exclusions, Map<Long, Double> counts, double decay) { Map<Long, Double> itemCounts = null; boolean localDimensionCheckNeeded = false; if (checkDimension) { try { itemCounts = getClusterTopCountsForTagAndDimensions(tag, tagAttrId, dimensions, dimension2, limit, decay); } catch (ClusterCountNoImplementationException e) { localDimensionCheckNeeded = true; } } if (itemCounts == null) { try { itemCounts = getClusterTopCountsForTag(tag, tagAttrId, limit, decay); } catch (ClusterCountNoImplementationException e) { logger.error("Failed to get cluster counts as method not implemented", e); itemCounts = new HashMap<>(); } } double maxCount = 0; for (Map.Entry<Long, Double> itemCount : itemCounts.entrySet()) if (itemCount.getValue() > maxCount) maxCount = itemCount.getValue(); if (maxCount > 0) { for (Map.Entry<Long, Double> itemCount : itemCounts.entrySet()) { Long item = itemCount.getKey(); if (checkDimension && localDimensionCheckNeeded) { Collection<Integer> dims = ItemService.getItemDimensions(new ConsumerBean(client), item); dims.retainAll(dimensions); if (dims.isEmpty()) continue; } if (!exclusions.contains(item)) { Double count = (itemCount.getValue() / maxCount) * tagWeight; Double existing = counts.get(item); if (existing != null) count = count + existing; counts.put(item, count); } } } } public Map<Long, Double> recommendUsingItem(String recommenderType, long itemId, Set<Integer> dimensions, int numRecommendations, Set<Long> exclusions, double decay, String clusterAlg, int minNumItems) { boolean checkDimension = !(dimensions.isEmpty() || (dimensions.size() == 1 && dimensions.iterator().next() == Constants.DEFAULT_DIMENSION)); int minAllowed = minNumItems < numRecommendations ? minNumItems : numRecommendations; if (logger.isDebugEnabled()) logger.debug("Recommend using items - dimension " + StringUtils.join(dimensions, ",") + " num recomendations " + numRecommendations + " itemId " + itemId + " minAllowed:" + minAllowed + " client " + client); Map<Long, Double> res = new HashMap<>(); if (clusterAlg != null) { //get the cluster id from the item if possibl List<UserCluster> clusters = new ArrayList<>(); switch (clusterAlg) { case "NONE": case "LDA_USER": break; case "DIMENSION": //get dimension for item Collection<Integer> dims = ItemService.getItemDimensions(new ConsumerBean(client), itemId); if (dims != null) for (Integer d : dims) clusters.add(new UserCluster(0, d, 1.0D, 0, 0)); break; case "LDA_ITEM": //get cluster from item_clusters table Integer dim = ItemService.getItemCluster(new ConsumerBean(client), itemId); if (dim != null) clusters.add(new UserCluster(0, dim, 1.0D, 0, 0)); break; } if (clusters.size() > 0) { Map<Long, Double> counts = new HashMap<>(); int numTopCounts = numRecommendations * 2; // number of counts to get - defaults to twice the final number recommendations to return for (UserCluster cluster : clusters) { updateCounts(recommenderType, 0, cluster, dimensions, checkDimension, numTopCounts, exclusions, counts, 1.0D, decay, null); } if (counts.keySet().size() < minAllowed) { if (logger.isDebugEnabled()) logger.debug("Number of items found " + counts.keySet().size() + " is less than " + minAllowed + " so returning empty recommendation for cluster item recommender for item " + itemId); return new HashMap<>(); } res = RecommendationUtils.rescaleScoresToOne(counts, numRecommendations); } else if (logger.isDebugEnabled()) logger.debug("No clusters for item " + itemId + " so returning empty results for item cluster count recommender"); } return res; } private void updateCounts(String recommenderType, long userId, UserCluster cluster, Set<Integer> dimensions, boolean checkDimension, int numTopCounts, Set<Long> exclusions, Map<Long, Double> counts, double clusterWeight, double decay, Integer dim2) { Map<Long, Double> itemCounts = null; boolean localDimensionCheckNeeded = false; if (checkDimension) { try { itemCounts = getClusterTopCountsForDimension(recommenderType, cluster.getCluster(), dimensions, cluster.getTimeStamp(), numTopCounts, decay, dim2); } catch (ClusterCountNoImplementationException e) { localDimensionCheckNeeded = true; } } if (itemCounts == null) { try { itemCounts = getClusterTopCounts(cluster.getCluster(), cluster.getTimeStamp(), numTopCounts, decay); } catch (ClusterCountNoImplementationException e) { logger.error("Failed to get cluster counts as method not implemented", e); itemCounts = new HashMap<>(); } } double maxCount = 0; for (Map.Entry<Long, Double> itemCount : itemCounts.entrySet()) if (itemCount.getValue() > maxCount) maxCount = itemCount.getValue(); if (maxCount > 0) { ItemPeer iPeer = null; if (localDimensionCheckNeeded) iPeer = Util.getItemPeer(client); for (Map.Entry<Long, Double> itemCount : itemCounts.entrySet()) { Long item = itemCount.getKey(); if (checkDimension && localDimensionCheckNeeded) { Collection<Integer> dims = ItemService.getItemDimensions(new ConsumerBean(client), item); dims.retainAll(dimensions); if (dims.isEmpty()) continue; } if (!exclusions.contains(item)) { Double count = (itemCount.getValue() / maxCount) * cluster.getWeight() * clusterWeight; // weight cluster count by user weight for cluster and long term weight if (logger.isDebugEnabled()) logger.debug( "Adding long term count " + count + " for item " + item + " for user " + userId); Double existing = counts.get(item); if (existing != null) count = count + existing; counts.put(item, count); } else if (logger.isDebugEnabled()) logger.debug("Ignoring excluded long term item in cluster recommendation " + item + " for user " + userId); } } } public Map<Long, Double> recommendGlobal(Set<Integer> dimensions, int numRecommendations, Set<Long> exclusions, double decay, Integer dimension2) { boolean checkDimension = !(dimensions.isEmpty() || (dimensions.size() == 1 && dimensions.iterator().next() == Constants.DEFAULT_DIMENSION)); int numTopCounts = numRecommendations * 5; Map<Long, Double> itemCounts = null; boolean localDimensionCheckNeeded = false; if (checkDimension) { try { itemCounts = getClusterTopCountsForDimension(dimensions, numTopCounts, decay, dimension2); } catch (ClusterCountNoImplementationException e) { localDimensionCheckNeeded = true; } } if (itemCounts == null) { try { itemCounts = getClusterTopCounts(numTopCounts, decay); if (itemCounts == null) { logger.warn("Got null itemcounts"); itemCounts = new HashMap<>(); } } catch (ClusterCountNoImplementationException e) { logger.error("Failed to get cluster counts as method not implemented", e); itemCounts = new HashMap<>(); } } int excluded = 0; for (Iterator<Map.Entry<Long, Double>> i = itemCounts.entrySet().iterator(); i.hasNext();) { Map.Entry<Long, Double> e = i.next(); Long item = e.getKey(); if (checkDimension && localDimensionCheckNeeded) { Collection<Integer> dims = ItemService.getItemDimensions(new ConsumerBean(client), item); dims.retainAll(dimensions); if (dims.isEmpty()) { i.remove(); excluded++; } } else if (exclusions.contains(item)) { i.remove(); excluded++; } } if (logger.isDebugEnabled()) logger.debug("Recommend global for dimension " + StringUtils.join(dimensions, ",") + " numRecs " + numRecommendations + " decay " + decay + " #in map " + itemCounts.size() + " excluded " + excluded + " client " + client); return RecommendationUtils.rescaleScoresToOne(itemCounts, numRecommendations); } /** * Provide a set of recommendations for a user using the counts from their clusters * @param userId * @param group * @param numRecommendations * @param includeShortTermClusters * @param longTermWeight * @param shortTermWeight * @return */ public Map<Long, Double> recommend(String recommenderType, long userId, Integer group, Set<Integer> dimensions, int numRecommendations, Set<Long> exclusions, boolean includeShortTermClusters, double longTermWeight, double shortTermWeight, double decay, int minNumItems, Integer dim2) { boolean checkDimension = !(dimensions.isEmpty() || (dimensions.size() == 1 && dimensions.iterator().next() == Constants.DEFAULT_DIMENSION)); int minAllowed = minNumItems < numRecommendations ? minNumItems : numRecommendations; if (logger.isDebugEnabled()) logger.debug("Recommend for user clusters - dimension " + StringUtils.join(dimensions, ",") + " num recomendations " + numRecommendations + "minAllowed:" + minAllowed + " client " + client + " user " + userId); // get user clusters pruned by group List<UserCluster> clusters; List<UserCluster> shortTermClusters; if (userId == Constants.ANONYMOUS_USER) { clusters = new ArrayList<>(); shortTermClusters = new ArrayList<>(); } else { clusters = getClusters(userId, group); if (includeShortTermClusters) shortTermClusters = getShortTermClusters(userId, group); else shortTermClusters = new ArrayList<>(); } // fail early Set<Integer> referrerClusters = getReferrerClusters(); if (referrerClusters == null || referrerClusters.size() == 0) { if (!includeShortTermClusters && clusters.size() == 0) { logger.debug( "User has no long term clusters and we are not including short term clusters - so returning empty recommendations"); return new HashMap<>(); } else if (includeShortTermClusters && clusters.size() == 0 && shortTermClusters.size() == 0) { logger.debug("User has no long or short term clusters - so returning empty recommendations"); return new HashMap<>(); } } List<Long> res = null; Map<Long, Double> counts = new HashMap<>(); int numTopCounts = numRecommendations * 5; // number of counts to get - defaults to twice the final number recommendations to return if (logger.isDebugEnabled()) logger.debug("recommending using long term cluster weight of " + longTermWeight + " and short term cluster weight " + shortTermWeight + " decay " + decay); for (UserCluster cluster : clusters) { updateCounts(recommenderType, userId, cluster, dimensions, checkDimension, numTopCounts, exclusions, counts, longTermWeight, decay, dim2); } for (UserCluster cluster : shortTermClusters) { updateCounts(recommenderType, userId, cluster, dimensions, checkDimension, numTopCounts, exclusions, counts, shortTermWeight, decay, dim2); } if (referrerClusters != null) { if (logger.isDebugEnabled()) logger.debug("Adding " + referrerClusters.size() + " referrer clusters to counts for user " + userId + " client " + client); for (Integer c : referrerClusters) { UserCluster uc = new UserCluster(userId, c, 1.0, 0, 0); updateCounts(recommenderType, userId, uc, dimensions, checkDimension, numTopCounts, exclusions, counts, longTermWeight, decay, dim2); } } if (counts.keySet().size() < minAllowed) { if (logger.isDebugEnabled()) logger.debug("Number of items found " + counts.keySet().size() + " is less than " + minAllowed + " so returning empty recommendation for user " + userId + " client " + client); return new HashMap<>(); } return RecommendationUtils.rescaleScoresToOne(counts, numRecommendations); } public List<Long> sort(long userId, List<Long> items, Integer group) { return this.sort(userId, items, group, false, 1.0D, 1.0D); } public List<Long> sort(long userId, List<Long> items, Integer group, boolean includeShortTermClusters, double longTermWeight, double shortTermWeight) { // get user clusters pruned by group List<UserCluster> clusters = getClusters(userId, group); List<UserCluster> shortTermClusters; if (includeShortTermClusters) shortTermClusters = getShortTermClusters(userId, group); else shortTermClusters = new ArrayList<>(); if (!includeShortTermClusters && clusters.size() == 0) { logger.debug( "User has no long term clusters and we are not including short term clusters - so returning empty recommendations"); return new ArrayList<>(); } else if (includeShortTermClusters && clusters.size() == 0 && shortTermClusters.size() == 0) { logger.debug("User has no long or short term clusters - so returning empty recommendations"); return new ArrayList<>(); } List<Long> res = null; Map<Long, Double> counts = new HashMap<>(); for (long item : items) // initialise counts to zero counts.put(item, 0D); for (UserCluster cluster : clusters) { Map<Long, Double> itemCounts = getClusterCounts(cluster.getCluster(), cluster.getTimeStamp(), items); double maxCount = 0; for (Map.Entry<Long, Double> itemCount : itemCounts.entrySet()) if (itemCount.getValue() > maxCount) maxCount = itemCount.getValue(); if (maxCount > 0) for (Map.Entry<Long, Double> itemCount : itemCounts.entrySet()) { Long item = itemCount.getKey(); Double count = (itemCount.getValue() / maxCount) * cluster.getWeight() * longTermWeight; // weight cluster count by user weight for cluster and long term weight if (logger.isDebugEnabled()) logger.debug( "Adding long term count " + count + " for item " + item + " for user " + userId); counts.put(item, counts.get(item) + count); } } for (UserCluster cluster : shortTermClusters) { Map<Long, Double> itemCounts = getClusterCounts(cluster.getCluster(), cluster.getTimeStamp(), items); double maxCount = 0; for (Map.Entry<Long, Double> itemCount : itemCounts.entrySet()) if (itemCount.getValue() > maxCount) maxCount = itemCount.getValue(); if (maxCount > 0) for (Map.Entry<Long, Double> itemCount : itemCounts.entrySet()) { Long item = itemCount.getKey(); Double count = (itemCount.getValue() / maxCount) * cluster.getWeight() * shortTermWeight; // weight cluster count by user weight for cluster and short term weight if (logger.isDebugEnabled()) logger.debug( "Adding short term count " + count + " for item " + item + " for user " + userId); counts.put(item, counts.get(item) + count); } } if (this.fillInZerosWithMostPopular) { res = new ArrayList<>(); List<Long> cRes = CollectionTools.sortMapAndLimitToList(counts, items.size()); for (Long item : cRes) if (counts.get(item) > 0) res.add(item); else break; } else res = CollectionTools.sortMapAndLimitToList(counts, items.size()); return res; } private List<UserCluster> getShortTermClusters(long userId, Integer group) { //Get Dynamic short-term clusters List<UserCluster> clusters = (List<UserCluster>) MemCachePeer .get(MemCacheKeys.getShortTermClustersForUser(client, userId)); if (clusters != null) { if (logger.isDebugEnabled()) logger.debug("Got " + clusters.size() + " short term clusters for user " + userId); } else { if (logger.isDebugEnabled()) logger.debug("Got 0 short term clusters for user " + userId); clusters = new ArrayList<>(); } return clusters; } private List<UserCluster> getClusters(long userId, Integer group) { if (userClusters == null) return null; List<UserCluster> clusters = null; String memcacheKey = null; if (userClusters.needsExternalCaching()) { memcacheKey = MemCacheKeys.getClustersForUser(client, userId); clusters = (List<UserCluster>) MemCachePeer.get(memcacheKey); } if (clusters == null) { clusters = userClusters.getClusters(userId); if (userClusters.needsExternalCaching()) MemCachePeer.put(memcacheKey, clusters, EXPIRE_USER_CLUSTERS); } //prune clusters not in desired group if (group != null) { for (Iterator<UserCluster> i = clusters.iterator(); i.hasNext();) { if (!group.equals(i.next().getGroup())) i.remove(); } } return clusters; } private Map<Long, Double> getClusterTopCountsForDimension(final Set<Integer> dimensions, final int limit, final double decay, final Integer dimension2) throws ClusterCountNoImplementationException { if (dimension2 != null) return getClusterCounts( MemCacheKeys.getTopClusterCountsForTwoDimensions(client, dimensions, dimension2, limit), new UpdateRetriever<ClustersCounts>() { @Override public ClustersCounts retrieve() throws Exception { if (logger.isDebugEnabled()) logger.debug("Trying to get top counts for dimension from db : for client " + client + " dimension:" + StringUtils.join(dimensions, ",") + " dimension2:" + dimension2); Map<Long, Double> itemMap = clusterCounts.getTopCountsByTwoDimensions(dimensions, dimension2, limit, decay); return new ClustersCounts(itemMap, 0); } }); else { return getClusterCounts(MemCacheKeys.getTopClusterCountsForDimension(client, dimensions, limit), new UpdateRetriever<ClustersCounts>() { @Override public ClustersCounts retrieve() throws Exception { if (logger.isDebugEnabled()) logger.debug( "Trying to get top counts for dimension from db : testMode is for client " + client + " dimension:" + StringUtils.join(dimensions, ",")); Map<Long, Double> itemMap = clusterCounts.getTopCountsByDimension(dimensions, limit, decay); return new ClustersCounts(itemMap, 0); } }); } } private Map<Long, Double> getClusterTopCountsForTag(final String tag, final int tagAttrId, final int limit, final double decay) throws ClusterCountNoImplementationException { return getClusterCounts(MemCacheKeys.getTopClusterCountsForTag(client, tag, tagAttrId, limit), new UpdateRetriever<ClustersCounts>() { @Override public ClustersCounts retrieve() throws Exception { if (logger.isDebugEnabled()) logger.debug( "Trying to get top counts for tag and dimension from db : testMode is for client " + client); Map<Long, Double> itemMap = clusterCounts.getTopCountsByTag(tag, tagAttrId, limit, decay); return new ClustersCounts(itemMap, 0); } }); } private Map<Long, Double> getClusterTopCountsForTagAndDimensions(final String tag, final int tagAttrId, final Set<Integer> dimensions, final Integer dimension2, final int limit, final double decay) throws ClusterCountNoImplementationException { if (dimension2 != null) { return getClusterCounts(MemCacheKeys.getTopClusterCountsForTagAndTwoDimensions(client, tag, tagAttrId, dimensions, dimension2, limit), new UpdateRetriever<ClustersCounts>() { @Override public ClustersCounts retrieve() throws Exception { if (logger.isDebugEnabled()) logger.debug( "Trying to get top counts for tag and two dimensions from db : testMode is for client " + client + " dimension1:" + StringUtils.join(dimensions, ",") + " dimension2:" + dimension2); Map<Long, Double> itemMap = clusterCounts.getTopCountsByTagAndTwoDimensions(tag, tagAttrId, dimensions, dimension2, limit, decay); return new ClustersCounts(itemMap, 0); } }); } else { return getClusterCounts( MemCacheKeys.getTopClusterCountsForTagAndDimension(client, tag, tagAttrId, dimensions, limit), new UpdateRetriever<ClustersCounts>() { @Override public ClustersCounts retrieve() throws Exception { if (logger.isDebugEnabled()) logger.debug( "Trying to get top counts for tag and dimension from db : testMode is for client " + client + " dimension:" + StringUtils.join(dimensions, ",")); Map<Long, Double> itemMap = clusterCounts.getTopCountsByTagAndDimension(tag, tagAttrId, dimensions, limit, decay); return new ClustersCounts(itemMap, 0); } }); } } private Map<Long, Double> getClusterCounts(String memcacheKey, UpdateRetriever<ClustersCounts> retriever) throws ClusterCountNoImplementationException { if (clusterCounts.needsExternalCaching()) { ClustersCounts itemCounts = (ClustersCounts) MemCachePeer.get(memcacheKey); ClustersCounts newItemCounts = null; try { newItemCounts = DogpileHandler.get().retrieveUpdateIfRequired(memcacheKey, itemCounts, retriever, EXPIRE_COUNTS); } catch (Exception e) { if (e instanceof ClusterCountNoImplementationException) { throw (ClusterCountNoImplementationException) e; } else { logger.error("Unknown exception:", e); } } if (newItemCounts != null) { MemCachePeer.put(memcacheKey, newItemCounts, EXPIRE_COUNTS); return newItemCounts.getItemCounts(); } else { if (itemCounts == null) { logger.warn("Couldn't get cluster counts from store or memcache. Returning null"); return new HashMap<Long, Double>(); } else { return itemCounts.getItemCounts(); } } } else { try { return retriever.retrieve().getItemCounts(); } catch (Exception e) { if (e instanceof ClusterCountNoImplementationException) { throw (ClusterCountNoImplementationException) e; } else { logger.error("Unknown exception:", e); return new HashMap<Long, Double>(); } } } } private Map<Long, Double> getClusterTopCountsForDimension(String recommenderType, final int clusterId, final Set<Integer> dimensions, final long timestamp, final int limit, final double decay, final Integer dim2) throws ClusterCountNoImplementationException { switch (recommenderType) { case "CLUSTER_COUNTS_SIGNIFICANT": return getClusterCounts(MemCacheKeys.getTopClusterCountsForDimensionAlg(client, recommenderType, clusterId, dimensions, limit), new UpdateRetriever<ClustersCounts>() { @Override public ClustersCounts retrieve() throws Exception { if (logger.isDebugEnabled()) logger.debug("Trying to get top counts from db : testMode is for client " + client + " cluster id:" + clusterId + " dimension:" + StringUtils.join(dimensions, ",") + " limit:" + limit); Map<Long, Double> itemMap = clusterCounts.getTopSignificantCountsByDimension(clusterId, dimensions, timestamp, limit, decay); return new ClustersCounts(itemMap, timestamp); } }); default: { if (dim2 != null) { return getClusterCounts(MemCacheKeys.getTopClusterCountsForTwoDimensions(client, clusterId, dimensions, dim2, limit), new UpdateRetriever<ClustersCounts>() { @Override public ClustersCounts retrieve() throws Exception { if (logger.isDebugEnabled()) logger.debug("Trying to get top counts from db : testMode is for client " + client + " cluster id:" + clusterId + " dimension:" + StringUtils.join(dimensions, ",") + "dim2: " + dim2 + " limit:" + limit); Map<Long, Double> itemMap = clusterCounts.getTopCountsByTwoDimensions(clusterId, dimensions, dim2, timestamp, limit, decay); return new ClustersCounts(itemMap, timestamp); } }); } else { return getClusterCounts( MemCacheKeys.getTopClusterCountsForDimension(client, clusterId, dimensions, limit), new UpdateRetriever<ClustersCounts>() { @Override public ClustersCounts retrieve() throws Exception { if (logger.isDebugEnabled()) logger.debug("Trying to get top counts from db : testMode is for client " + client + " cluster id:" + clusterId + " dimension:" + StringUtils.join(dimensions, ",") + " limit:" + limit); Map<Long, Double> itemMap = clusterCounts.getTopCountsByDimension(clusterId, dimensions, timestamp, limit, decay); return new ClustersCounts(itemMap, timestamp); } }); } } } } private Map<Long, Double> getClusterTopCounts(final int limit, final double decay) throws ClusterCountNoImplementationException { return getClusterCounts(MemCacheKeys.getTopClusterCounts(client, limit), new UpdateRetriever<ClustersCounts>() { @Override public ClustersCounts retrieve() throws Exception { Map<Long, Double> itemMap = clusterCounts.getTopCounts(limit, decay); return new ClustersCounts(itemMap, 0); } }); } private Map<Long, Double> getClusterTopCounts(final int clusterId, final long timestamp, final int limit, final double decay) throws ClusterCountNoImplementationException { return getClusterCounts(MemCacheKeys.getTopClusterCounts(client, clusterId, limit), new UpdateRetriever<ClustersCounts>() { @Override public ClustersCounts retrieve() throws Exception { Map<Long, Double> itemMap = clusterCounts.getTopCounts(clusterId, timestamp, limit, decay); return new ClustersCounts(itemMap, timestamp); } }); } private Map<Long, Double> getClusterCounts(final int clusterId, final long timestamp, final List<Long> items) { try { return getClusterCounts(MemCacheKeys.getClusterCountForItems(client, clusterId, items, timestamp), new UpdateRetriever<ClustersCounts>() { @Override public ClustersCounts retrieve() throws Exception { Map<Long, Double> itemMap = new HashMap<>(); for (Long itemId : items) { double count = clusterCounts.getCount(clusterId, itemId, timestamp); itemMap.put(itemId, count); } return new ClustersCounts(itemMap, timestamp); } }); } catch (ClusterCountNoImplementationException e) { // can't happen return null; } } }