You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mahout.apache.org by sr...@apache.org on 2009/08/04 02:06:50 UTC
svn commit: r800634 [3/7] - in /lucene/mahout/trunk:
core/src/main/java/org/apache/mahout/cf/taste/hadoop/
core/src/main/java/org/apache/mahout/cf/taste/impl/common/
core/src/main/java/org/apache/mahout/cf/taste/impl/common/jdbc/
core/src/main/java/org...
Modified: lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/neighborhood/CachingUserNeighborhood.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/neighborhood/CachingUserNeighborhood.java?rev=800634&r1=800633&r2=800634&view=diff
==============================================================================
--- lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/neighborhood/CachingUserNeighborhood.java (original)
+++ lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/neighborhood/CachingUserNeighborhood.java Tue Aug 4 00:06:46 2009
@@ -23,7 +23,6 @@
import org.apache.mahout.cf.taste.impl.common.RefreshHelper;
import org.apache.mahout.cf.taste.impl.common.Retriever;
import org.apache.mahout.cf.taste.model.DataModel;
-import org.apache.mahout.cf.taste.model.User;
import org.apache.mahout.cf.taste.neighborhood.UserNeighborhood;
import java.util.Collection;
@@ -32,7 +31,7 @@
public final class CachingUserNeighborhood implements UserNeighborhood {
private final UserNeighborhood neighborhood;
- private final Cache<Comparable<?>, Collection<User>> neighborhoodCache;
+ private final Cache<Comparable<?>, Collection<Comparable<?>>> neighborhoodCache;
public CachingUserNeighborhood(UserNeighborhood neighborhood, DataModel dataModel) throws TasteException {
if (neighborhood == null) {
@@ -40,12 +39,12 @@
}
this.neighborhood = neighborhood;
int maxCacheSize = dataModel.getNumUsers(); // just a dumb heuristic for sizing
- this.neighborhoodCache = new Cache<Comparable<?>, Collection<User>>(
+ this.neighborhoodCache = new Cache<Comparable<?>, Collection<Comparable<?>>>(
new NeighborhoodRetriever(neighborhood), maxCacheSize);
}
@Override
- public Collection<User> getUserNeighborhood(Comparable<?> userID) throws TasteException {
+ public Collection<Comparable<?>> getUserNeighborhood(Comparable<?> userID) throws TasteException {
return neighborhoodCache.get(userID);
}
@@ -56,7 +55,7 @@
RefreshHelper.maybeRefresh(alreadyRefreshed, neighborhood);
}
- private static final class NeighborhoodRetriever implements Retriever<Comparable<?>, Collection<User>> {
+ private static final class NeighborhoodRetriever implements Retriever<Comparable<?>, Collection<Comparable<?>>> {
private final UserNeighborhood neighborhood;
private NeighborhoodRetriever(UserNeighborhood neighborhood) {
@@ -64,7 +63,7 @@
}
@Override
- public Collection<User> get(Comparable<?> key) throws TasteException {
+ public Collection<Comparable<?>> get(Comparable<?> key) throws TasteException {
return neighborhood.getUserNeighborhood(key);
}
}
Modified: lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/neighborhood/NearestNUserNeighborhood.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/neighborhood/NearestNUserNeighborhood.java?rev=800634&r1=800633&r2=800634&view=diff
==============================================================================
--- lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/neighborhood/NearestNUserNeighborhood.java (original)
+++ lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/neighborhood/NearestNUserNeighborhood.java Tue Aug 4 00:06:46 2009
@@ -21,7 +21,6 @@
import org.apache.mahout.cf.taste.impl.common.SamplingIterable;
import org.apache.mahout.cf.taste.impl.recommender.TopItems;
import org.apache.mahout.cf.taste.model.DataModel;
-import org.apache.mahout.cf.taste.model.User;
import org.apache.mahout.cf.taste.similarity.UserSimilarity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -31,7 +30,7 @@
import java.util.List;
/**
- * <p>Computes a neighborhood consisting of the nearest n {@link User}s to a given {@link User}. "Nearest" is defined by
+ * <p>Computes a neighborhood consisting of the nearest n users to a given user. "Nearest" is defined by
* the given {@link UserSimilarity}.</p>
*/
public final class NearestNUserNeighborhood extends AbstractUserNeighborhood {
@@ -90,17 +89,16 @@
}
@Override
- public Collection<User> getUserNeighborhood(Comparable<?> userID) throws TasteException {
+ public Collection<Comparable<?>> getUserNeighborhood(Comparable<?> userID) throws TasteException {
log.trace("Computing neighborhood around user ID '{}'", userID);
DataModel dataModel = getDataModel();
- User theUser = dataModel.getUser(userID);
UserSimilarity userSimilarityImpl = getUserSimilarity();
- TopItems.Estimator<User> estimator = new Estimator(userSimilarityImpl, theUser, minSimilarity);
+ TopItems.Estimator<Comparable<?>> estimator = new Estimator(userSimilarityImpl, userID, minSimilarity);
- Iterable<? extends User> users = SamplingIterable.maybeWrapIterable(dataModel.getUsers(), getSamplingRate());
- List<User> neighborhood = TopItems.getTopUsers(n, users, null, estimator);
+ Iterable<Comparable<?>> users = SamplingIterable.maybeWrapIterable(dataModel.getUserIDs(), getSamplingRate());
+ List<Comparable<?>> neighborhood = TopItems.getTopUsers(n, users, null, estimator);
log.trace("UserNeighborhood around user ID '{}' is: {}", userID, neighborhood);
@@ -112,23 +110,23 @@
return "NearestNUserNeighborhood";
}
- private static class Estimator implements TopItems.Estimator<User> {
+ private static class Estimator implements TopItems.Estimator<Comparable<?>> {
private final UserSimilarity userSimilarityImpl;
- private final User theUser;
+ private final Comparable<?> theUserID;
private final double minSim;
- private Estimator(UserSimilarity userSimilarityImpl, User theUser, double minSim) {
+ private Estimator(UserSimilarity userSimilarityImpl, Comparable<?> theUserID, double minSim) {
this.userSimilarityImpl = userSimilarityImpl;
- this.theUser = theUser;
+ this.theUserID = theUserID;
this.minSim = minSim;
}
@Override
- public double estimate(User user) throws TasteException {
- if (user.equals(theUser)) {
+ public double estimate(Comparable<?> user) throws TasteException {
+ if (user.equals(theUserID)) {
return Double.NaN;
}
- double sim = userSimilarityImpl.userSimilarity(theUser, user);
+ double sim = userSimilarityImpl.userSimilarity(theUserID, user);
return (sim >= minSim) ? sim : Double.NaN;
}
}
Modified: lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/neighborhood/ThresholdUserNeighborhood.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/neighborhood/ThresholdUserNeighborhood.java?rev=800634&r1=800633&r2=800634&view=diff
==============================================================================
--- lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/neighborhood/ThresholdUserNeighborhood.java (original)
+++ lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/neighborhood/ThresholdUserNeighborhood.java Tue Aug 4 00:06:46 2009
@@ -20,7 +20,6 @@
import org.apache.mahout.cf.taste.common.TasteException;
import org.apache.mahout.cf.taste.impl.common.SamplingIterable;
import org.apache.mahout.cf.taste.model.DataModel;
-import org.apache.mahout.cf.taste.model.User;
import org.apache.mahout.cf.taste.similarity.UserSimilarity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -32,7 +31,7 @@
import java.util.List;
/**
- * <p>Computes a neigbhorhood consisting of all {@link User}s whose similarity to the given {@link User} meets or
+ * <p>Computes a neigbhorhood consisting of all users whose similarity to the given user meets or
* exceeds a certain threshold. Similarity is defined by the given {@link UserSimilarity}.</p>
*/
public final class ThresholdUserNeighborhood extends AbstractUserNeighborhood {
@@ -76,23 +75,22 @@
}
@Override
- public Collection<User> getUserNeighborhood(Comparable<?> userID) throws TasteException {
+ public Collection<Comparable<?>> getUserNeighborhood(Comparable<?> userID) throws TasteException {
log.trace("Computing neighborhood around user ID '{}'", userID);
DataModel dataModel = getDataModel();
- User theUser = dataModel.getUser(userID);
- List<User> neighborhood = new ArrayList<User>();
- Iterable<? extends User> usersIterable =
- SamplingIterable.maybeWrapIterable(dataModel.getUsers(), getSamplingRate());
- Iterator<? extends User> users = usersIterable.iterator();
+ List<Comparable<?>> neighborhood = new ArrayList<Comparable<?>>();
+ Iterable<Comparable<?>> usersIterable =
+ SamplingIterable.maybeWrapIterable(dataModel.getUserIDs(), getSamplingRate());
+ Iterator<Comparable<?>> users = usersIterable.iterator();
UserSimilarity userSimilarityImpl = getUserSimilarity();
while (users.hasNext()) {
- User user = users.next();
- if (!userID.equals(user.getID())) {
- double theSimilarity = userSimilarityImpl.userSimilarity(theUser, user);
+ Comparable<?> otherUserID = users.next();
+ if (!userID.equals(otherUserID)) {
+ double theSimilarity = userSimilarityImpl.userSimilarity(userID, otherUserID);
if (!Double.isNaN(theSimilarity) && theSimilarity >= threshold) {
- neighborhood.add(user);
+ neighborhood.add(otherUserID);
}
}
}
Modified: lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/AbstractRecommender.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/AbstractRecommender.java?rev=800634&r1=800633&r2=800634&view=diff
==============================================================================
--- lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/AbstractRecommender.java (original)
+++ lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/AbstractRecommender.java Tue Aug 4 00:06:46 2009
@@ -20,7 +20,7 @@
import org.apache.mahout.cf.taste.common.TasteException;
import org.apache.mahout.cf.taste.impl.common.FastSet;
import org.apache.mahout.cf.taste.model.DataModel;
-import org.apache.mahout.cf.taste.model.User;
+import org.apache.mahout.cf.taste.model.PreferenceArray;
import org.apache.mahout.cf.taste.recommender.RecommendedItem;
import org.apache.mahout.cf.taste.recommender.Recommender;
import org.slf4j.Logger;
@@ -53,21 +53,19 @@
}
/**
- * <p>Default implementation which just calls {@link DataModel#setPreference(Comparable, Comparable, double)}.</p>
+ * <p>Default implementation which just calls {@link DataModel#setPreference(Comparable, Comparable, float)}.</p>
*
* @throws IllegalArgumentException if userID or itemID is <code>null</code>, or if value is {@link Double#NaN}
*/
@Override
- public void setPreference(Comparable<?> userID, Comparable<?> itemID, double value) throws TasteException {
+ public void setPreference(Comparable<?> userID, Comparable<?> itemID, float value) throws TasteException {
if (userID == null || itemID == null) {
throw new IllegalArgumentException("userID or itemID is null");
}
if (Double.isNaN(value)) {
throw new IllegalArgumentException("Invalid value: " + value);
}
- if (log.isDebugEnabled()) {
- log.debug("Setting preference for user '" + userID + "', item '" + itemID + "', value " + value);
- }
+ log.debug("Setting preference for user {}, item {}", userID, itemID);
dataModel.setPreference(userID, itemID, value);
}
@@ -92,20 +90,19 @@
}
/**
- * @param theUser {@link User} being evaluated
- * @return all items in the {@link DataModel} for which the {@link User} has not expressed a preference
+ * @param theUserID ID of user being evaluated
+ * @return all items in the {@link DataModel} for which the user has not expressed a preference
* @throws TasteException if an error occurs while listing items
*/
- protected Set<Comparable<?>> getAllOtherItems(User theUser) throws TasteException {
- if (theUser == null) {
- throw new IllegalArgumentException("theUser is null");
- }
+ protected Set<Comparable<?>> getAllOtherItems(Comparable<?> theUserID) throws TasteException {
Set<Comparable<?>> allItemIDs = new FastSet<Comparable<?>>(dataModel.getNumItems());
for (Comparable<?> itemID : dataModel.getItemIDs()) {
- // If not already preferred by the user, add it
- if (theUser.getPreferenceFor(itemID) == null) {
- allItemIDs.add(itemID);
- }
+ allItemIDs.add(itemID);
+ }
+ PreferenceArray prefs = dataModel.getPreferencesFromUser(theUserID);
+ int size = prefs.length();
+ for (int i = 0; i < size; i++) {
+ allItemIDs.remove(prefs.getItemID(i));
}
return allItemIDs;
}
Modified: lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/CachingRecommender.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/CachingRecommender.java?rev=800634&r1=800633&r2=800634&view=diff
==============================================================================
--- lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/CachingRecommender.java (original)
+++ lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/CachingRecommender.java Tue Aug 4 00:06:46 2009
@@ -48,7 +48,7 @@
private final Recommender recommender;
private final AtomicInteger maxHowMany;
private final Cache<Comparable<?>, Recommendations> recommendationCache;
- private final Cache<Pair<Comparable<?>, Comparable<?>>, Double> estimatedPrefCache;
+ private final Cache<Pair<Comparable<?>, Comparable<?>>, Float> estimatedPrefCache;
private final RefreshHelper refreshHelper;
private Rescorer<Comparable<?>> currentRescorer;
@@ -63,7 +63,7 @@
this.recommendationCache =
new Cache<Comparable<?>, Recommendations>(new RecommendationRetriever(this.recommender), numUsers);
this.estimatedPrefCache =
- new Cache<Pair<Comparable<?>, Comparable<?>>, Double>(new EstimatedPrefRetriever(this.recommender), numUsers);
+ new Cache<Pair<Comparable<?>, Comparable<?>>, Float>(new EstimatedPrefRetriever(this.recommender), numUsers);
this.refreshHelper = new RefreshHelper(new Callable<Object>() {
@Override
public Object call() {
@@ -131,12 +131,12 @@
}
@Override
- public double estimatePreference(Comparable<?> userID, Comparable<?> itemID) throws TasteException {
+ public float estimatePreference(Comparable<?> userID, Comparable<?> itemID) throws TasteException {
return estimatedPrefCache.get(new Pair<Comparable<?>, Comparable<?>>(userID, itemID));
}
@Override
- public void setPreference(Comparable<?> userID, Comparable<?> itemID, double value) throws TasteException {
+ public void setPreference(Comparable<?> userID, Comparable<?> itemID, float value) throws TasteException {
recommender.setPreference(userID, itemID, value);
clear(userID);
}
@@ -198,7 +198,7 @@
}
}
- private static final class EstimatedPrefRetriever implements Retriever<Pair<Comparable<?>, Comparable<?>>, Double> {
+ private static final class EstimatedPrefRetriever implements Retriever<Pair<Comparable<?>, Comparable<?>>, Float> {
private final Recommender recommender;
@@ -207,7 +207,7 @@
}
@Override
- public Double get(Pair<Comparable<?>, Comparable<?>> key) throws TasteException {
+ public Float get(Pair<Comparable<?>, Comparable<?>> key) throws TasteException {
Comparable<?> userID = key.getFirst();
Comparable<?> itemID = key.getSecond();
log.debug("Retrieving estimated preference for user ID '{}' and item ID '{}'", userID, itemID);
Modified: lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/ClusterSimilarity.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/ClusterSimilarity.java?rev=800634&r1=800633&r2=800634&view=diff
==============================================================================
--- lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/ClusterSimilarity.java (original)
+++ lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/ClusterSimilarity.java Tue Aug 4 00:06:46 2009
@@ -19,7 +19,6 @@
import org.apache.mahout.cf.taste.common.Refreshable;
import org.apache.mahout.cf.taste.common.TasteException;
-import org.apache.mahout.cf.taste.model.User;
import java.util.Collection;
@@ -32,13 +31,13 @@
public interface ClusterSimilarity extends Refreshable {
/**
- * @param cluster1 first cluster of {@link User}s
- * @param cluster2 second cluste rof {@link User}s
- * @return "distance" between clusters; a positiv
+ * @param cluster1 first cluster of user IDs
+ * @param cluster2 second cluster of user IDs
+ * @return "distance" between clusters; a bigger value means less similarity
* @throws TasteException if an error occurs while computing similarity, such as errors accessing an
* underlying {@link org.apache.mahout.cf.taste.model.DataModel}
* @throws IllegalArgumentException if either argument is null or empty
*/
- double getSimilarity(Collection<User> cluster1, Collection<User> cluster2) throws TasteException;
+ double getSimilarity(Collection<Comparable<?>> cluster1, Collection<Comparable<?>> cluster2) throws TasteException;
}
Modified: lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/FarthestNeighborClusterSimilarity.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/FarthestNeighborClusterSimilarity.java?rev=800634&r1=800633&r2=800634&view=diff
==============================================================================
--- lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/FarthestNeighborClusterSimilarity.java (original)
+++ lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/FarthestNeighborClusterSimilarity.java Tue Aug 4 00:06:46 2009
@@ -21,13 +21,12 @@
import org.apache.mahout.cf.taste.common.TasteException;
import org.apache.mahout.cf.taste.impl.common.RefreshHelper;
import org.apache.mahout.cf.taste.impl.common.SamplingIterable;
-import org.apache.mahout.cf.taste.model.User;
import org.apache.mahout.cf.taste.similarity.UserSimilarity;
import java.util.Collection;
/**
- * <p>Defines cluster similarity as the <em>smallest</em> similarity between any two {@link User}s in the clusters --
+ * <p>Defines cluster similarity as the <em>smallest</em> similarity between any two users in the clusters --
* that is, it says that clusters are close when <em>all pairs</em> of their members have relatively high
* similarity.</p>
*/
@@ -61,16 +60,16 @@
}
@Override
- public double getSimilarity(Collection<User> cluster1,
- Collection<User> cluster2) throws TasteException {
+ public double getSimilarity(Collection<Comparable<?>> cluster1,
+ Collection<Comparable<?>> cluster2) throws TasteException {
if (cluster1.isEmpty() || cluster2.isEmpty()) {
return Double.NaN;
}
double leastSimilarity = Double.POSITIVE_INFINITY;
- Iterable<User> someUsers = SamplingIterable.maybeWrapIterable(cluster1, samplingRate);
- for (User user1 : someUsers) {
- for (User user2 : cluster2) {
- double theSimilarity = similarity.userSimilarity(user1, user2);
+ Iterable<Comparable<?>> someUsers = SamplingIterable.maybeWrapIterable(cluster1, samplingRate);
+ for (Comparable<?> userID1 : someUsers) {
+ for (Comparable<?> userID2 : cluster2) {
+ double theSimilarity = similarity.userSimilarity(userID1, userID2);
if (theSimilarity < leastSimilarity) {
leastSimilarity = theSimilarity;
}
Copied: lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/GenericBooleanPrefUserBasedRecommender.java (from r797487, lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/BooleanUserGenericUserBasedRecommender.java)
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/GenericBooleanPrefUserBasedRecommender.java?p2=lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/GenericBooleanPrefUserBasedRecommender.java&p1=lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/BooleanUserGenericUserBasedRecommender.java&r1=797487&r2=800634&rev=800634&view=diff
==============================================================================
--- lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/BooleanUserGenericUserBasedRecommender.java (original)
+++ lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/GenericBooleanPrefUserBasedRecommender.java Tue Aug 4 00:06:46 2009
@@ -17,156 +17,25 @@
package org.apache.mahout.cf.taste.impl.recommender;
-import org.apache.mahout.cf.taste.common.Refreshable;
import org.apache.mahout.cf.taste.common.TasteException;
import org.apache.mahout.cf.taste.impl.common.FastSet;
-import org.apache.mahout.cf.taste.impl.common.Pair;
-import org.apache.mahout.cf.taste.impl.common.RefreshHelper;
-import org.apache.mahout.cf.taste.impl.model.BooleanPrefUser;
import org.apache.mahout.cf.taste.model.DataModel;
-import org.apache.mahout.cf.taste.model.Preference;
-import org.apache.mahout.cf.taste.model.User;
import org.apache.mahout.cf.taste.neighborhood.UserNeighborhood;
-import org.apache.mahout.cf.taste.recommender.RecommendedItem;
-import org.apache.mahout.cf.taste.recommender.Rescorer;
-import org.apache.mahout.cf.taste.recommender.UserBasedRecommender;
import org.apache.mahout.cf.taste.similarity.UserSimilarity;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import java.util.ArrayList;
import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.PriorityQueue;
-import java.util.Queue;
import java.util.Set;
/**
- * A variant on {@link GenericUserBasedRecommender} which is appropriate for use with "boolean" classes like {@link
- * org.apache.mahout.cf.taste.impl.model.BooleanPrefUser}.
+ * A variant on {@link GenericUserBasedRecommender} which is appropriate for use when no notion of
+ * preference value exists in the data.
*/
-public final class BooleanUserGenericUserBasedRecommender extends AbstractRecommender implements UserBasedRecommender {
+public final class GenericBooleanPrefUserBasedRecommender extends GenericUserBasedRecommender {
- private static final Logger log = LoggerFactory.getLogger(BooleanUserGenericUserBasedRecommender.class);
-
- private final UserNeighborhood neighborhood;
- private final UserSimilarity similarity;
- private final RefreshHelper refreshHelper;
-
- public BooleanUserGenericUserBasedRecommender(DataModel dataModel,
+ public GenericBooleanPrefUserBasedRecommender(DataModel dataModel,
UserNeighborhood neighborhood,
UserSimilarity similarity) {
- super(dataModel);
- if (neighborhood == null) {
- throw new IllegalArgumentException("neighborhood is null");
- }
- this.neighborhood = neighborhood;
- this.similarity = similarity;
- this.refreshHelper = new RefreshHelper(null);
- refreshHelper.addDependency(dataModel);
- refreshHelper.addDependency(similarity);
- refreshHelper.addDependency(neighborhood);
- }
-
- @Override
- public List<RecommendedItem> recommend(Comparable<?> userID, int howMany, Rescorer<Comparable<?>> rescorer)
- throws TasteException {
- if (userID == null) {
- throw new IllegalArgumentException("userID is null");
- }
- if (howMany < 1) {
- throw new IllegalArgumentException("howMany must be at least 1");
- }
-
- log.debug("Recommending items for user ID '{}'", userID);
-
- User theUser = getDataModel().getUser(userID);
- Collection<User> theNeighborhood = neighborhood.getUserNeighborhood(userID);
- log.trace("UserNeighborhood is: {}", neighborhood);
-
- if (theNeighborhood.isEmpty()) {
- return Collections.emptyList();
- }
-
- Set<Comparable<?>> allItemIDs = getAllOtherItems(theNeighborhood, theUser);
- log.trace("Items in neighborhood which user doesn't prefer already are: {}", allItemIDs);
-
- TopItems.Estimator<Comparable<?>> estimator = new Estimator(theUser, theNeighborhood);
-
- List<RecommendedItem> topItems = getTopItems(howMany, allItemIDs, rescorer, estimator);
-
- log.debug("Recommendations are: {}", topItems);
- return topItems;
- }
-
- public static List<RecommendedItem> getTopItems(int howMany,
- Iterable<Comparable<?>> allItemIDs,
- Rescorer<Comparable<?>> rescorer,
- TopItems.Estimator<Comparable<?>> estimator) throws TasteException {
- if (allItemIDs == null || estimator == null) {
- throw new IllegalArgumentException("argument is null");
- }
- Queue<RecommendedItem> topItems = new PriorityQueue<RecommendedItem>(howMany + 1, Collections.reverseOrder());
- boolean full = false;
- double lowestTopValue = Double.NEGATIVE_INFINITY;
- for (Comparable<?> itemID : allItemIDs) {
- double preference = estimator.estimate(itemID);
- double rescoredPref = rescorer == null ? preference : rescorer.rescore(itemID, preference);
- if (!Double.isNaN(rescoredPref) && (!full || rescoredPref > lowestTopValue)) {
- topItems.add(new GenericRecommendedItem(itemID, rescoredPref));
- if (full) {
- topItems.poll();
- } else if (topItems.size() > howMany) {
- full = true;
- topItems.poll();
- }
- lowestTopValue = topItems.peek().getValue();
- }
- }
- List<RecommendedItem> result = new ArrayList<RecommendedItem>(topItems.size());
- result.addAll(topItems);
- Collections.sort(result);
- return result;
- }
-
- @Override
- public double estimatePreference(Comparable<?> userID, Comparable<?> itemID) throws TasteException {
- DataModel model = getDataModel();
- User theUser = model.getUser(userID);
- Preference actualPref = theUser.getPreferenceFor(itemID);
- if (actualPref != null) {
- return actualPref.getValue();
- }
- Collection<User> theNeighborhood = neighborhood.getUserNeighborhood(userID);
- return doEstimatePreference(theUser, theNeighborhood, itemID);
- }
-
- @Override
- public List<User> mostSimilarUsers(Comparable<?> userID, int howMany) throws TasteException {
- return mostSimilarUsers(userID, howMany, null);
- }
-
- @Override
- public List<User> mostSimilarUsers(Comparable<?> userID,
- int howMany,
- Rescorer<Pair<User, User>> rescorer) throws TasteException {
- User toUser = getDataModel().getUser(userID);
- TopItems.Estimator<User> estimator = new MostSimilarEstimator(toUser, similarity, rescorer);
- return doMostSimilarUsers(userID, howMany, estimator);
- }
-
- private List<User> doMostSimilarUsers(Comparable<?> userID,
- int howMany,
- TopItems.Estimator<User> estimator) throws TasteException {
- DataModel model = getDataModel();
- User toUser = model.getUser(userID);
- Collection<User> allUsers = new FastSet<User>(model.getNumUsers());
- for (User user : model.getUsers()) {
- allUsers.add(user);
- }
- allUsers.remove(toUser);
- return TopItems.getTopUsers(howMany, allUsers, null, estimator);
+ super(dataModel, neighborhood, similarity);
}
/**
@@ -175,82 +44,46 @@
* it means results can't be ranked by preference value (all are 1). So instead this returns a sum of similarities to
* any other user in the neighborhood who has also rated the item.
*/
- private double doEstimatePreference(User theUser, Collection<User> theNeighborhood, Comparable<?> itemID)
+ @Override
+ protected float doEstimatePreference(Comparable<?> theUserID,
+ Collection<Comparable<?>> theNeighborhood,
+ Comparable<?> itemID)
throws TasteException {
if (theNeighborhood.isEmpty()) {
- return Double.NaN;
+ return Float.NaN;
}
- double totalSimilarity = 0.0;
+ DataModel dataModel = getDataModel();
+ UserSimilarity similarity = getSimilarity();
+ float totalSimilarity = 0.0f;
boolean foundAPref = false;
- for (User user : theNeighborhood) {
- if (!user.equals(theUser)) {
+ for (Comparable<?> userID : theNeighborhood) {
+ if (!userID.equals(theUserID)) {
// See GenericItemBasedRecommender.doEstimatePreference() too
- if (user.getPreferenceFor(itemID) != null) {
+ if (dataModel.getPreferenceValue(userID, itemID) != null) {
foundAPref = true;
- totalSimilarity += similarity.userSimilarity(theUser, user);
+ totalSimilarity += similarity.userSimilarity(theUserID, userID);
}
}
}
- return foundAPref ? totalSimilarity : Double.NaN;
+ return foundAPref ? totalSimilarity : Float.NaN;
}
- private static Set<Comparable<?>> getAllOtherItems(Iterable<User> theNeighborhood, User theUser) {
+ @Override
+ protected Set<Comparable<?>> getAllOtherItems(Iterable<Comparable<?>> theNeighborhood, Comparable<?> theUserID)
+ throws TasteException {
+ DataModel dataModel = getDataModel();
Set<Comparable<?>> allItemIDs = new FastSet<Comparable<?>>();
- for (User user : theNeighborhood) {
- allItemIDs.addAll(((BooleanPrefUser) user).getItemIDs());
+ for (Comparable<?> userID : theNeighborhood) {
+ allItemIDs.addAll(dataModel.getItemIDsFromUser(userID));
}
- allItemIDs.removeAll(((BooleanPrefUser) theUser).getItemIDs());
+ allItemIDs.removeAll(dataModel.getItemIDsFromUser(theUserID));
return allItemIDs;
}
- @Override
- public void refresh(Collection<Refreshable> alreadyRefreshed) {
- refreshHelper.refresh(alreadyRefreshed);
- }
@Override
public String toString() {
- return "BooleanUserGenericUserBasedRecommender[neighborhood:" + neighborhood + ']';
+ return "GenericBooleanPrefUserBasedRecommender";
}
- private static class MostSimilarEstimator implements TopItems.Estimator<User> {
-
- private final User toUser;
- private final UserSimilarity similarity;
- private final Rescorer<Pair<User, User>> rescorer;
-
- private MostSimilarEstimator(User toUser,
- UserSimilarity similarity,
- Rescorer<Pair<User, User>> rescorer) {
- this.toUser = toUser;
- this.similarity = similarity;
- this.rescorer = rescorer;
- }
-
- @Override
- public double estimate(User user) throws TasteException {
- Pair<User, User> pair = new Pair<User, User>(toUser, user);
- if (rescorer != null && rescorer.isFiltered(pair)) {
- return Double.NaN;
- }
- double originalEstimate = similarity.userSimilarity(toUser, user);
- return rescorer == null ? originalEstimate : rescorer.rescore(pair, originalEstimate);
- }
- }
-
- private final class Estimator implements TopItems.Estimator<Comparable<?>> {
-
- private final User theUser;
- private final Collection<User> theNeighborhood;
-
- Estimator(User theUser, Collection<User> theNeighborhood) {
- this.theUser = theUser;
- this.theNeighborhood = theNeighborhood;
- }
-
- @Override
- public double estimate(Comparable<?> itemID) throws TasteException {
- return doEstimatePreference(theUser, theNeighborhood, itemID);
- }
- }
}
Modified: lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/GenericItemBasedRecommender.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/GenericItemBasedRecommender.java?rev=800634&r1=800633&r2=800634&view=diff
==============================================================================
--- lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/GenericItemBasedRecommender.java (original)
+++ lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/GenericItemBasedRecommender.java Tue Aug 4 00:06:46 2009
@@ -25,8 +25,7 @@
import org.apache.mahout.cf.taste.impl.common.RefreshHelper;
import org.apache.mahout.cf.taste.impl.common.RunningAverage;
import org.apache.mahout.cf.taste.model.DataModel;
-import org.apache.mahout.cf.taste.model.Preference;
-import org.apache.mahout.cf.taste.model.User;
+import org.apache.mahout.cf.taste.model.PreferenceArray;
import org.apache.mahout.cf.taste.recommender.ItemBasedRecommender;
import org.apache.mahout.cf.taste.recommender.RecommendedItem;
import org.apache.mahout.cf.taste.recommender.Rescorer;
@@ -34,7 +33,6 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
@@ -90,14 +88,13 @@
log.debug("Recommending items for user ID '{}'", userID);
- User theUser = getDataModel().getUser(userID);
- if (getNumPreferences(theUser) == 0) {
+ if (getNumPreferences(userID) == 0) {
return Collections.emptyList();
}
- Set<Comparable<?>> allItemIDs = getAllOtherItems(theUser);
+ Set<Comparable<?>> allItemIDs = getAllOtherItems(userID);
- TopItems.Estimator<Comparable<?>> estimator = new Estimator(theUser);
+ TopItems.Estimator<Comparable<?>> estimator = new Estimator(userID);
List<RecommendedItem> topItems = TopItems.getTopItems(howMany, allItemIDs, rescorer, estimator);
@@ -106,14 +103,13 @@
}
@Override
- public double estimatePreference(Comparable<?> userID, Comparable<?> itemID) throws TasteException {
+ public float estimatePreference(Comparable<?> userID, Comparable<?> itemID) throws TasteException {
DataModel model = getDataModel();
- User theUser = model.getUser(userID);
- Preference actualPref = theUser.getPreferenceFor(itemID);
+ Float actualPref = model.getPreferenceValue(userID, itemID);
if (actualPref != null) {
- return actualPref.getValue();
+ return actualPref;
}
- return doEstimatePreference(theUser, itemID);
+ return doEstimatePreference(userID, itemID);
}
@Override
@@ -163,13 +159,13 @@
}
DataModel model = getDataModel();
- User user = model.getUser(userID);
- TopItems.Estimator<Comparable<?>> estimator = new RecommendedBecauseEstimator(user, itemID, similarity);
+ TopItems.Estimator<Comparable<?>> estimator = new RecommendedBecauseEstimator(userID, itemID, similarity);
Collection<Comparable<?>> allUserItems = new FastSet<Comparable<?>>();
- Preference[] prefs = user.getPreferencesAsArray();
- for (Preference pref : prefs) {
- allUserItems.add(pref.getItemID());
+ PreferenceArray prefs = model.getPreferencesFromUser(userID);
+ int size = prefs.length();
+ for (int i = 0; i < size; i++) {
+ allUserItems.add(prefs.getItemID(i));
}
allUserItems.remove(itemID);
@@ -188,26 +184,27 @@
return TopItems.getTopItems(howMany, allItemIDs, null, estimator);
}
- protected double doEstimatePreference(User theUser, Comparable<?> itemID) throws TasteException {
+ protected float doEstimatePreference(Comparable<?> userID, Comparable<?> itemID) throws TasteException {
double preference = 0.0;
double totalSimilarity = 0.0;
- Preference[] prefs = theUser.getPreferencesAsArray();
- for (Preference pref : prefs) {
- double theSimilarity = similarity.itemSimilarity(itemID, pref.getItemID());
+ PreferenceArray prefs = getDataModel().getPreferencesFromUser(userID);
+ int size = prefs.length();
+ for (int i = 0; i < size; i++) {
+ double theSimilarity = similarity.itemSimilarity(itemID, prefs.getItemID(i));
if (!Double.isNaN(theSimilarity)) {
// Why + 1.0? similarity ranges from -1.0 to 1.0, and we want to use it as a simple
// weight. To avoid negative values, we add 1.0 to put it in
// the [0.0,2.0] range which is reasonable for weights
theSimilarity += 1.0;
- preference += theSimilarity * pref.getValue();
+ preference += theSimilarity * prefs.getValue(i);
totalSimilarity += theSimilarity;
}
}
- return totalSimilarity == 0.0 ? Double.NaN : preference / totalSimilarity;
+ return totalSimilarity == 0.0 ? Float.NaN : (float) (preference / totalSimilarity);
}
- private static int getNumPreferences(User theUser) {
- return theUser.getPreferencesAsArray().length;
+ private int getNumPreferences(Comparable<?> userID) throws TasteException {
+ return getDataModel().getPreferencesFromUser(userID).length();
}
@Override
@@ -247,15 +244,15 @@
private final class Estimator implements TopItems.Estimator<Comparable<?>> {
- private final User theUser;
+ private final Comparable<?> userID;
- private Estimator(User theUser) {
- this.theUser = theUser;
+ private Estimator(Comparable<?> userID) {
+ this.userID = userID;
}
@Override
public double estimate(Comparable<?> itemID) throws TasteException {
- return doEstimatePreference(theUser, itemID);
+ return doEstimatePreference(userID, itemID);
}
}
@@ -291,28 +288,28 @@
}
}
- private static class RecommendedBecauseEstimator implements TopItems.Estimator<Comparable<?>> {
+ private class RecommendedBecauseEstimator implements TopItems.Estimator<Comparable<?>> {
- private final User user;
+ private final Comparable<?> userID;
private final Comparable<?> recommendedItemID;
private final ItemSimilarity similarity;
- private RecommendedBecauseEstimator(User user,
+ private RecommendedBecauseEstimator(Comparable<?> userID,
Comparable<?> recommendedItemID,
ItemSimilarity similarity) {
- this.user = user;
+ this.userID = userID;
this.recommendedItemID = recommendedItemID;
this.similarity = similarity;
}
@Override
public double estimate(Comparable<?> itemID) throws TasteException {
- Preference pref = user.getPreferenceFor(itemID);
+ Float pref = getDataModel().getPreferenceValue(userID, itemID);
if (pref == null) {
- return Double.NaN;
+ return Float.NaN;
}
double similarityValue = similarity.itemSimilarity(recommendedItemID, itemID);
- return (1.0 + similarityValue) * pref.getValue();
+ return (1.0 + similarityValue) * pref;
}
}
Modified: lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/GenericRecommendedItem.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/GenericRecommendedItem.java?rev=800634&r1=800633&r2=800634&view=diff
==============================================================================
--- lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/GenericRecommendedItem.java (original)
+++ lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/GenericRecommendedItem.java Tue Aug 4 00:06:46 2009
@@ -26,14 +26,14 @@
public final class GenericRecommendedItem implements RecommendedItem, Serializable {
private final Comparable<?> itemID;
- private final double value;
+ private final float value;
/** @throws IllegalArgumentException if item is null or value is NaN */
- public GenericRecommendedItem(Comparable<?> itemID, double value) {
+ public GenericRecommendedItem(Comparable<?> itemID, float value) {
if (itemID == null) {
throw new IllegalArgumentException("item is null");
}
- if (Double.isNaN(value)) {
+ if (Float.isNaN(value)) {
throw new IllegalArgumentException("value is NaN");
}
this.itemID = itemID;
@@ -46,7 +46,7 @@
}
@Override
- public double getValue() {
+ public float getValue() {
return value;
}
@@ -57,7 +57,7 @@
@Override
public int hashCode() {
- return itemID.hashCode() ^ RandomUtils.hashDouble(value);
+ return itemID.hashCode() ^ RandomUtils.hashFloat(value);
}
@Override
@@ -76,7 +76,7 @@
*/
@Override
public int compareTo(RecommendedItem other) {
- double otherValue = other.getValue();
+ float otherValue = other.getValue();
return value > otherValue ? -1 : value < otherValue ? 1 : 0;
}
Modified: lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/GenericUserBasedRecommender.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/GenericUserBasedRecommender.java?rev=800634&r1=800633&r2=800634&view=diff
==============================================================================
--- lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/GenericUserBasedRecommender.java (original)
+++ lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/GenericUserBasedRecommender.java Tue Aug 4 00:06:46 2009
@@ -23,8 +23,7 @@
import org.apache.mahout.cf.taste.impl.common.Pair;
import org.apache.mahout.cf.taste.impl.common.RefreshHelper;
import org.apache.mahout.cf.taste.model.DataModel;
-import org.apache.mahout.cf.taste.model.Preference;
-import org.apache.mahout.cf.taste.model.User;
+import org.apache.mahout.cf.taste.model.PreferenceArray;
import org.apache.mahout.cf.taste.neighborhood.UserNeighborhood;
import org.apache.mahout.cf.taste.recommender.RecommendedItem;
import org.apache.mahout.cf.taste.recommender.Recommender;
@@ -43,7 +42,7 @@
* <p>A simple {@link Recommender} which uses a given {@link DataModel} and {@link UserNeighborhood} to produce
* recommendations.</p>
*/
-public final class GenericUserBasedRecommender extends AbstractRecommender implements UserBasedRecommender {
+public class GenericUserBasedRecommender extends AbstractRecommender implements UserBasedRecommender {
private static final Logger log = LoggerFactory.getLogger(GenericUserBasedRecommender.class);
@@ -66,6 +65,10 @@
refreshHelper.addDependency(neighborhood);
}
+ public UserSimilarity getSimilarity() {
+ return similarity;
+ }
+
@Override
public List<RecommendedItem> recommend(Comparable<?> userID, int howMany, Rescorer<Comparable<?>> rescorer)
throws TasteException {
@@ -78,18 +81,17 @@
log.debug("Recommending items for user ID '{}'", userID);
- User theUser = getDataModel().getUser(userID);
- Collection<User> theNeighborhood = neighborhood.getUserNeighborhood(userID);
+ Collection<Comparable<?>> theNeighborhood = neighborhood.getUserNeighborhood(userID);
log.trace("UserNeighborhood is: {}", neighborhood);
if (theNeighborhood.isEmpty()) {
return Collections.emptyList();
}
- Set<Comparable<?>> allItemIDs = getAllOtherItems(theNeighborhood, theUser);
+ Set<Comparable<?>> allItemIDs = getAllOtherItems(theNeighborhood, userID);
log.trace("Items in neighborhood which user doesn't prefer already are: {}", allItemIDs);
- TopItems.Estimator<Comparable<?>> estimator = new Estimator(theUser, theNeighborhood);
+ TopItems.Estimator<Comparable<?>> estimator = new Estimator(userID, theNeighborhood);
List<RecommendedItem> topItems = TopItems.getTopItems(howMany, allItemIDs, rescorer, estimator);
@@ -98,69 +100,74 @@
}
@Override
- public double estimatePreference(Comparable<?> userID, Comparable<?> itemID) throws TasteException {
+ public float estimatePreference(Comparable<?> userID, Comparable<?> itemID) throws TasteException {
DataModel model = getDataModel();
- User theUser = model.getUser(userID);
- Preference actualPref = theUser.getPreferenceFor(itemID);
+ Float actualPref = model.getPreferenceValue(userID, itemID);
if (actualPref != null) {
- return actualPref.getValue();
+ return actualPref;
}
- Collection<User> theNeighborhood = neighborhood.getUserNeighborhood(userID);
- return doEstimatePreference(theUser, theNeighborhood, itemID);
+ Collection<Comparable<?>> theNeighborhood = neighborhood.getUserNeighborhood(userID);
+ return doEstimatePreference(userID, theNeighborhood, itemID);
}
@Override
- public List<User> mostSimilarUsers(Comparable<?> userID, int howMany) throws TasteException {
- return mostSimilarUsers(userID, howMany, null);
+ public List<Comparable<?>> mostSimilarUserIDs(Comparable<?> userID, int howMany) throws TasteException {
+ return mostSimilarUserIDs(userID, howMany, null);
}
@Override
- public List<User> mostSimilarUsers(Comparable<?> userID,
- int howMany,
- Rescorer<Pair<User, User>> rescorer) throws TasteException {
- User toUser = getDataModel().getUser(userID);
- TopItems.Estimator<User> estimator = new MostSimilarEstimator(toUser, similarity, rescorer);
+ public List<Comparable<?>> mostSimilarUserIDs(Comparable<?> userID,
+ int howMany,
+ Rescorer<Pair<Comparable<?>, Comparable<?>>> rescorer)
+ throws TasteException {
+ TopItems.Estimator<Comparable<?>> estimator = new MostSimilarEstimator(userID, similarity, rescorer);
return doMostSimilarUsers(howMany, estimator);
}
- private List<User> doMostSimilarUsers(int howMany,
- TopItems.Estimator<User> estimator) throws TasteException {
+ private List<Comparable<?>> doMostSimilarUsers(int howMany,
+ TopItems.Estimator<Comparable<?>> estimator) throws TasteException {
DataModel model = getDataModel();
- return TopItems.getTopUsers(howMany, model.getUsers(), null, estimator);
+ return TopItems.getTopUsers(howMany, model.getUserIDs(), null, estimator);
}
- private double doEstimatePreference(User theUser, Collection<User> theNeighborhood, Comparable<?> itemID)
+ protected float doEstimatePreference(Comparable<?> theUserID,
+ Collection<Comparable<?>> theNeighborhood,
+ Comparable<?> itemID)
throws TasteException {
if (theNeighborhood.isEmpty()) {
- return Double.NaN;
+ return Float.NaN;
}
+ DataModel dataModel = getDataModel();
double preference = 0.0;
double totalSimilarity = 0.0;
- for (User user : theNeighborhood) {
- if (!user.equals(theUser)) {
+ for (Comparable<?> userID : theNeighborhood) {
+ if (!userID.equals(theUserID)) {
// See GenericItemBasedRecommender.doEstimatePreference() too
- Preference pref = user.getPreferenceFor(itemID);
+ Float pref = dataModel.getPreferenceValue(userID, itemID);
if (pref != null) {
- double theSimilarity = similarity.userSimilarity(theUser, user) + 1.0;
+ double theSimilarity = similarity.userSimilarity(theUserID, userID) + 1.0;
// Similarity should not be NaN or else the user should never have showed up
// in the neighborhood. Adding 1.0 puts this in the range [0,2] which is
// more appropriate for weights
- preference += theSimilarity * pref.getValue();
+ preference += theSimilarity * pref;
totalSimilarity += theSimilarity;
}
}
}
- return totalSimilarity == 0.0 ? Double.NaN : preference / totalSimilarity;
+ return totalSimilarity == 0.0 ? Float.NaN : (float) (preference / totalSimilarity);
}
- private static Set<Comparable<?>> getAllOtherItems(Iterable<User> theNeighborhood, User theUser) {
+ protected Set<Comparable<?>> getAllOtherItems(Iterable<Comparable<?>> theNeighborhood, Comparable<?> theUserID)
+ throws TasteException {
+ DataModel dataModel = getDataModel();
Set<Comparable<?>> allItemIDs = new FastSet<Comparable<?>>();
- for (User user : theNeighborhood) {
- Preference[] prefs = user.getPreferencesAsArray();
- for (Preference pref : prefs) {
- Comparable<?> itemID = pref.getItemID();
+ for (Comparable<?> userID : theNeighborhood) {
+ PreferenceArray prefs = dataModel.getPreferencesFromUser(userID);
+ int size = prefs.length();
+ for (int i = 0; i < size; i++) {
+ Comparable<?> itemID = prefs.getItemID(i);
// If not already preferred by the user, add it
- if (theUser.getPreferenceFor(itemID) == null) {
+ if (dataModel.getPreferenceValue(theUserID, itemID) == null) {
allItemIDs.add(itemID);
}
}
@@ -178,48 +185,52 @@
return "GenericUserBasedRecommender[neighborhood:" + neighborhood + ']';
}
- private static class MostSimilarEstimator implements TopItems.Estimator<User> {
+ private static class MostSimilarEstimator implements TopItems.Estimator<Comparable<?>> {
- private final User toUser;
+ private final Comparable<?> toUserID;
private final UserSimilarity similarity;
- private final Rescorer<Pair<User, User>> rescorer;
+ private final Rescorer<Pair<Comparable<?>, Comparable<?>>> rescorer;
- private MostSimilarEstimator(User toUser,
+ private MostSimilarEstimator(Comparable<?> toUserID,
UserSimilarity similarity,
- Rescorer<Pair<User, User>> rescorer) {
- this.toUser = toUser;
+ Rescorer<Pair<Comparable<?>, Comparable<?>>> rescorer) {
+ this.toUserID = toUserID;
this.similarity = similarity;
this.rescorer = rescorer;
}
@Override
- public double estimate(User user) throws TasteException {
+ public double estimate(Comparable<?> userID) throws TasteException {
// Don't consider the user itself as a possible most similar user
- if (user.equals(toUser)) {
+ if (userID.equals(toUserID)) {
return Double.NaN;
}
- Pair<User, User> pair = new Pair<User, User>(toUser, user);
- if (rescorer != null && rescorer.isFiltered(pair)) {
- return Double.NaN;
+ if (rescorer == null) {
+ return similarity.userSimilarity(toUserID, userID);
+ } else {
+ Pair<Comparable<?>, Comparable<?>> pair = new Pair<Comparable<?>, Comparable<?>>(toUserID, userID);
+ if (rescorer.isFiltered(pair)) {
+ return Double.NaN;
+ }
+ double originalEstimate = similarity.userSimilarity(toUserID, userID);
+ return rescorer.rescore(pair, originalEstimate);
}
- double originalEstimate = similarity.userSimilarity(toUser, user);
- return rescorer == null ? originalEstimate : rescorer.rescore(pair, originalEstimate);
}
}
private final class Estimator implements TopItems.Estimator<Comparable<?>> {
- private final User theUser;
- private final Collection<User> theNeighborhood;
+ private final Comparable<?> theUserUD;
+ private final Collection<Comparable<?>> theNeighborhood;
- Estimator(User theUser, Collection<User> theNeighborhood) {
- this.theUser = theUser;
+ Estimator(Comparable<?> theUserUD, Collection<Comparable<?>> theNeighborhood) {
+ this.theUserUD = theUserUD;
this.theNeighborhood = theNeighborhood;
}
@Override
public double estimate(Comparable<?> itemID) throws TasteException {
- return doEstimatePreference(theUser, theNeighborhood, itemID);
+ return doEstimatePreference(theUserUD, theNeighborhood, itemID);
}
}
}
Modified: lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/ItemAverageRecommender.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/ItemAverageRecommender.java?rev=800634&r1=800633&r2=800634&view=diff
==============================================================================
--- lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/ItemAverageRecommender.java (original)
+++ lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/ItemAverageRecommender.java Tue Aug 4 00:06:46 2009
@@ -25,8 +25,7 @@
import org.apache.mahout.cf.taste.impl.common.RefreshHelper;
import org.apache.mahout.cf.taste.impl.common.RunningAverage;
import org.apache.mahout.cf.taste.model.DataModel;
-import org.apache.mahout.cf.taste.model.Preference;
-import org.apache.mahout.cf.taste.model.User;
+import org.apache.mahout.cf.taste.model.PreferenceArray;
import org.apache.mahout.cf.taste.recommender.RecommendedItem;
import org.apache.mahout.cf.taste.recommender.Rescorer;
import org.slf4j.Logger;
@@ -42,7 +41,7 @@
/**
* <p>A simple recommender that always estimates preference for an item to be the average of all known
- * preference values for that item. No information about {@link User}s is taken into account. This
+ * preference values for that item. No information about users is taken into account. This
* implementation is provided for experimentation; while simple and fast, it may not produce very good
* recommendations.</p>
*/
@@ -81,8 +80,7 @@
log.debug("Recommending items for user ID '{}'", userID);
checkAverageDiffsBuilt();
- User theUser = getDataModel().getUser(userID);
- Set<Comparable<?>> allItemIDs = getAllOtherItems(theUser);
+ Set<Comparable<?>> allItemIDs = getAllOtherItems(userID);
TopItems.Estimator<Comparable<?>> estimator = new Estimator();
@@ -93,22 +91,21 @@
}
@Override
- public double estimatePreference(Comparable<?> userID, Comparable<?> itemID) throws TasteException {
- DataModel model = getDataModel();
- User theUser = model.getUser(userID);
- Preference actualPref = theUser.getPreferenceFor(itemID);
+ public float estimatePreference(Comparable<?> userID, Comparable<?> itemID) throws TasteException {
+ DataModel dataModel = getDataModel();
+ Float actualPref = dataModel.getPreferenceValue(userID, itemID);
if (actualPref != null) {
- return actualPref.getValue();
+ return actualPref;
}
checkAverageDiffsBuilt();
return doEstimatePreference(itemID);
}
- private double doEstimatePreference(Comparable<?> itemID) {
+ private float doEstimatePreference(Comparable<?> itemID) {
buildAveragesLock.readLock().lock();
try {
RunningAverage average = itemAverages.get(itemID);
- return average == null ? Double.NaN : average.getAverage();
+ return average == null ? Float.NaN : (float) average.getAverage();
} finally {
buildAveragesLock.readLock().unlock();
}
@@ -124,16 +121,17 @@
try {
buildAveragesLock.writeLock().lock();
DataModel dataModel = getDataModel();
- for (User user : dataModel.getUsers()) {
- Preference[] prefs = user.getPreferencesAsArray();
- for (Preference pref : prefs) {
- Comparable<?> itemID = pref.getItemID();
+ for (Comparable<?> userID : dataModel.getUserIDs()) {
+ PreferenceArray prefs = dataModel.getPreferencesFromUser(userID);
+ int size = prefs.length();
+ for (int i = 0; i < size; i++) {
+ Comparable<?> itemID = prefs.getItemID(i);
RunningAverage average = itemAverages.get(itemID);
if (average == null) {
average = new FullRunningAverage();
itemAverages.put(itemID, average);
}
- average.addDatum(pref.getValue());
+ average.addDatum(prefs.getValue(i));
}
}
averagesBuilt = true;
@@ -143,13 +141,12 @@
}
@Override
- public void setPreference(Comparable<?> userID, Comparable<?> itemID, double value) throws TasteException {
+ public void setPreference(Comparable<?> userID, Comparable<?> itemID, float value) throws TasteException {
DataModel dataModel = getDataModel();
double prefDelta;
try {
- User theUser = dataModel.getUser(userID);
- Preference oldPref = theUser.getPreferenceFor(itemID);
- prefDelta = oldPref == null ? value : value - oldPref.getValue();
+ Float oldPref = dataModel.getPreferenceValue(userID, itemID);
+ prefDelta = oldPref == null ? value : value - oldPref;
} catch (NoSuchUserException nsee) {
prefDelta = value;
}
@@ -172,8 +169,7 @@
@Override
public void removePreference(Comparable<?> userID, Comparable<?> itemID) throws TasteException {
DataModel dataModel = getDataModel();
- User theUser = dataModel.getUser(userID);
- Preference oldPref = theUser.getPreferenceFor(itemID);
+ Float oldPref = dataModel.getPreferenceValue(userID, itemID);
super.removePreference(userID, itemID);
if (oldPref != null) {
try {
@@ -182,7 +178,7 @@
if (average == null) {
throw new IllegalStateException("No preferences exist for item ID: " + itemID);
} else {
- average.removeDatum(oldPref.getValue());
+ average.removeDatum(oldPref);
}
} finally {
buildAveragesLock.writeLock().unlock();
Modified: lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/ItemUserAverageRecommender.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/ItemUserAverageRecommender.java?rev=800634&r1=800633&r2=800634&view=diff
==============================================================================
--- lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/ItemUserAverageRecommender.java (original)
+++ lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/ItemUserAverageRecommender.java Tue Aug 4 00:06:46 2009
@@ -25,8 +25,7 @@
import org.apache.mahout.cf.taste.impl.common.RefreshHelper;
import org.apache.mahout.cf.taste.impl.common.RunningAverage;
import org.apache.mahout.cf.taste.model.DataModel;
-import org.apache.mahout.cf.taste.model.Preference;
-import org.apache.mahout.cf.taste.model.User;
+import org.apache.mahout.cf.taste.model.PreferenceArray;
import org.apache.mahout.cf.taste.recommender.RecommendedItem;
import org.apache.mahout.cf.taste.recommender.Rescorer;
import org.slf4j.Logger;
@@ -41,7 +40,7 @@
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
- * <p>Like {@link ItemAverageRecommender}, except that estimated preferences are adjusted for the {@link User}s' average
+ * <p>Like {@link ItemAverageRecommender}, except that estimated preferences are adjusted for the users' average
* preference value. For example, say user X has not rated item Y. Item Y's average preference value is 3.5. User X's
* average preference value is 4.2, and the average over all preference values is 4.0. User X prefers items 0.2 higher
* on average, so, the estimated preference for user X, item Y is 3.5 + 0.2 = 3.7.</p>
@@ -85,8 +84,7 @@
log.debug("Recommending items for user ID '{}'", userID);
checkAverageDiffsBuilt();
- User theUser = getDataModel().getUser(userID);
- Set<Comparable<?>> allItemIDs = getAllOtherItems(theUser);
+ Set<Comparable<?>> allItemIDs = getAllOtherItems(userID);
TopItems.Estimator<Comparable<?>> estimator = new Estimator(userID);
@@ -97,30 +95,29 @@
}
@Override
- public double estimatePreference(Comparable<?> userID, Comparable<?> itemID) throws TasteException {
- DataModel model = getDataModel();
- User theUser = model.getUser(userID);
- Preference actualPref = theUser.getPreferenceFor(itemID);
+ public float estimatePreference(Comparable<?> userID, Comparable<?> itemID) throws TasteException {
+ DataModel dataModel = getDataModel();
+ Float actualPref = dataModel.getPreferenceValue(userID, itemID);
if (actualPref != null) {
- return actualPref.getValue();
+ return actualPref;
}
checkAverageDiffsBuilt();
return doEstimatePreference(userID, itemID);
}
- private double doEstimatePreference(Comparable<?> userID, Comparable<?> itemID) {
+ private float doEstimatePreference(Comparable<?> userID, Comparable<?> itemID) {
buildAveragesLock.readLock().lock();
try {
RunningAverage itemAverage = itemAverages.get(itemID);
if (itemAverage == null) {
- return Double.NaN;
+ return Float.NaN;
}
RunningAverage userAverage = userAverages.get(userID);
if (userAverage == null) {
- return Double.NaN;
+ return Float.NaN;
}
double userDiff = userAverage.getAverage() - overallAveragePrefValue.getAverage();
- return itemAverage.getAverage() + userDiff;
+ return (float) (itemAverage.getAverage() + userDiff);
} finally {
buildAveragesLock.readLock().unlock();
}
@@ -136,14 +133,14 @@
try {
buildAveragesLock.writeLock().lock();
DataModel dataModel = getDataModel();
- for (User user : dataModel.getUsers()) {
- Comparable<?> userID = user.getID();
- Preference[] prefs = user.getPreferencesAsArray();
- for (Preference pref : prefs) {
- Comparable<?> itemID = pref.getItemID();
- double value = pref.getValue();
- addDatumAndCrateIfNeeded(itemID, value, itemAverages);
- addDatumAndCrateIfNeeded(userID, value, userAverages);
+ for (Comparable<?> userID : dataModel.getUserIDs()) {
+ PreferenceArray prefs = dataModel.getPreferencesFromUser(userID);
+ int size = prefs.length();
+ for (int i = 0; i < size; i++) {
+ Comparable<?> itemID = prefs.getItemID(i);
+ float value = prefs.getValue(i);
+ addDatumAndCreateIfNeeded(itemID, value, itemAverages);
+ addDatumAndCreateIfNeeded(userID, value, userAverages);
overallAveragePrefValue.addDatum(value);
}
}
@@ -153,9 +150,9 @@
}
}
- private static void addDatumAndCrateIfNeeded(Comparable<?> itemID,
- double value,
- Map<Comparable<?>, RunningAverage> averages) {
+ private static void addDatumAndCreateIfNeeded(Comparable<?> itemID,
+ float value,
+ Map<Comparable<?>, RunningAverage> averages) {
RunningAverage itemAverage = averages.get(itemID);
if (itemAverage == null) {
itemAverage = new FullRunningAverage();
@@ -165,13 +162,12 @@
}
@Override
- public void setPreference(Comparable<?> userID, Comparable<?> itemID, double value) throws TasteException {
+ public void setPreference(Comparable<?> userID, Comparable<?> itemID, float value) throws TasteException {
DataModel dataModel = getDataModel();
double prefDelta;
try {
- User theUser = dataModel.getUser(userID);
- Preference oldPref = theUser.getPreferenceFor(itemID);
- prefDelta = oldPref == null ? value : value - oldPref.getValue();
+ Float oldPref = dataModel.getPreferenceValue(userID, itemID);
+ prefDelta = oldPref == null ? value : value - oldPref;
} catch (NoSuchUserException nsee) {
prefDelta = value;
}
@@ -203,11 +199,10 @@
@Override
public void removePreference(Comparable<?> userID, Comparable<?> itemID) throws TasteException {
DataModel dataModel = getDataModel();
- User theUser = dataModel.getUser(userID);
- Preference oldPref = theUser.getPreferenceFor(itemID);
+ Float oldPref = dataModel.getPreferenceValue(userID, itemID);
super.removePreference(userID, itemID);
if (oldPref != null) {
- double value = oldPref.getValue();
+ double value = oldPref;
try {
buildAveragesLock.writeLock().lock();
RunningAverage itemAverage = itemAverages.get(itemID);
Modified: lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/NearestNeighborClusterSimilarity.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/NearestNeighborClusterSimilarity.java?rev=800634&r1=800633&r2=800634&view=diff
==============================================================================
--- lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/NearestNeighborClusterSimilarity.java (original)
+++ lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/NearestNeighborClusterSimilarity.java Tue Aug 4 00:06:46 2009
@@ -21,13 +21,12 @@
import org.apache.mahout.cf.taste.common.TasteException;
import org.apache.mahout.cf.taste.impl.common.RefreshHelper;
import org.apache.mahout.cf.taste.impl.common.SamplingIterable;
-import org.apache.mahout.cf.taste.model.User;
import org.apache.mahout.cf.taste.similarity.UserSimilarity;
import java.util.Collection;
/**
- * <p>Defines cluster similarity as the <em>largest</em> similarity between any two {@link User}s in the clusters --
+ * <p>Defines cluster similarity as the <em>largest</em> similarity between any two users in the clusters --
* that is, it says that clusters are close when <em>some pair</em> of their members has high similarity.</p>
*/
public final class NearestNeighborClusterSimilarity implements ClusterSimilarity {
@@ -60,16 +59,16 @@
}
@Override
- public double getSimilarity(Collection<User> cluster1,
- Collection<User> cluster2) throws TasteException {
+ public double getSimilarity(Collection<Comparable<?>> cluster1,
+ Collection<Comparable<?>> cluster2) throws TasteException {
if (cluster1.isEmpty() || cluster2.isEmpty()) {
return Double.NaN;
}
- Iterable<User> someUsers = SamplingIterable.maybeWrapIterable(cluster1, samplingRate);
+ Iterable<Comparable<?>> someUsers = SamplingIterable.maybeWrapIterable(cluster1, samplingRate);
double greatestSimilarity = Double.NEGATIVE_INFINITY;
- for (User user1 : someUsers) {
- for (User user2 : cluster2) {
- double theSimilarity = similarity.userSimilarity(user1, user2);
+ for (Comparable<?> userID1 : someUsers) {
+ for (Comparable<?> userID2 : cluster2) {
+ double theSimilarity = similarity.userSimilarity(userID1, userID2);
if (theSimilarity > greatestSimilarity) {
greatestSimilarity = theSimilarity;
}
Modified: lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/NullRescorer.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/NullRescorer.java?rev=800634&r1=800633&r2=800634&view=diff
==============================================================================
--- lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/NullRescorer.java (original)
+++ lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/NullRescorer.java Tue Aug 4 00:06:46 2009
@@ -18,31 +18,30 @@
package org.apache.mahout.cf.taste.impl.recommender;
import org.apache.mahout.cf.taste.impl.common.Pair;
-import org.apache.mahout.cf.taste.model.User;
import org.apache.mahout.cf.taste.recommender.Rescorer;
/** <p>A simple {@link Rescorer} which always returns the original score.</p> */
public final class NullRescorer<T> implements Rescorer<T> {
- private static final Rescorer<Comparable<?>> itemInstance = new NullRescorer<Comparable<?>>();
- private static final Rescorer<User> userInstance = new NullRescorer<User>();
+ private static final Rescorer<Comparable<?>> userOrItemInstance = new NullRescorer<Comparable<?>>();
private static final Rescorer<Pair<Comparable<?>, Comparable<?>>> itemItemPairInstance =
new NullRescorer<Pair<Comparable<?>, Comparable<?>>>();
- private static final Rescorer<Pair<User, User>> userUserPairInstance = new NullRescorer<Pair<User, User>>();
+ private static final Rescorer<Pair<Comparable<?>, Comparable<?>>> userUserPairInstance =
+ new NullRescorer<Pair<Comparable<?>, Comparable<?>>>();
public static Rescorer<Comparable<?>> getItemInstance() {
- return itemInstance;
+ return userOrItemInstance;
}
- public static Rescorer<User> getUserInstance() {
- return userInstance;
+ public static Rescorer<Comparable<?>> getUserInstance() {
+ return userOrItemInstance;
}
public static Rescorer<Pair<Comparable<?>, Comparable<?>>> getItemItemPairInstance() {
return itemItemPairInstance;
}
- public static Rescorer<Pair<User, User>> getUserUserPairInstance() {
+ public static Rescorer<Pair<Comparable<?>, Comparable<?>>> getUserUserPairInstance() {
return userUserPairInstance;
}
Modified: lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/SimilarUser.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/SimilarUser.java?rev=800634&r1=800633&r2=800634&view=diff
==============================================================================
--- lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/SimilarUser.java (original)
+++ lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/SimilarUser.java Tue Aug 4 00:06:46 2009
@@ -18,21 +18,20 @@
package org.apache.mahout.cf.taste.impl.recommender;
import org.apache.mahout.cf.taste.impl.common.RandomUtils;
-import org.apache.mahout.cf.taste.model.User;
-/** Simply encapsulates a {@link User} and a similarity value. */
+/** Simply encapsulates a user and a similarity value. */
public final class SimilarUser implements Comparable<SimilarUser> {
- private final User user;
+ private final Comparable<?> userID;
private final double similarity;
- public SimilarUser(User user, double similarity) {
- this.user = user;
+ public SimilarUser(Comparable<?> userID, double similarity) {
+ this.userID = userID;
this.similarity = similarity;
}
- User getUser() {
- return user;
+ Comparable<?> getUserID() {
+ return userID;
}
double getSimilarity() {
@@ -41,7 +40,7 @@
@Override
public int hashCode() {
- return user.hashCode() ^ RandomUtils.hashDouble(similarity);
+ return userID.hashCode() ^ RandomUtils.hashDouble(similarity);
}
@Override
@@ -50,12 +49,12 @@
return false;
}
SimilarUser other = (SimilarUser) o;
- return user.equals(other.user) && similarity == other.similarity;
+ return userID.equals(other.userID) && similarity == other.similarity;
}
@Override
public String toString() {
- return "SimilarUser[user:" + user + ", similarity:" + similarity + ']';
+ return "SimilarUser[user:" + userID + ", similarity:" + similarity + ']';
}
/** Defines an ordering from most similar to least similar. */
Modified: lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/TopItems.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/TopItems.java?rev=800634&r1=800633&r2=800634&view=diff
==============================================================================
--- lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/TopItems.java (original)
+++ lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/TopItems.java Tue Aug 4 00:06:46 2009
@@ -20,7 +20,6 @@
import org.apache.mahout.cf.taste.common.TasteException;
import org.apache.mahout.cf.taste.impl.similarity.GenericItemSimilarity;
import org.apache.mahout.cf.taste.impl.similarity.GenericUserSimilarity;
-import org.apache.mahout.cf.taste.model.User;
import org.apache.mahout.cf.taste.recommender.RecommendedItem;
import org.apache.mahout.cf.taste.recommender.Rescorer;
@@ -51,7 +50,7 @@
double preference = estimator.estimate(itemID);
double rescoredPref = rescorer == null ? preference : rescorer.rescore(itemID, preference);
if (!Double.isNaN(rescoredPref) && (!full || rescoredPref > lowestTopValue)) {
- topItems.add(new GenericRecommendedItem(itemID, rescoredPref));
+ topItems.add(new GenericRecommendedItem(itemID, (float) rescoredPref));
if (full) {
topItems.poll();
} else if (topItems.size() > howMany) {
@@ -68,21 +67,21 @@
return result;
}
- public static List<User> getTopUsers(int howMany,
- Iterable<? extends User> allUsers,
- Rescorer<User> rescorer,
- Estimator<User> estimator) throws TasteException {
+ public static List<Comparable<?>> getTopUsers(int howMany,
+ Iterable<? extends Comparable<?>> allUserIDs,
+ Rescorer<Comparable<?>> rescorer,
+ Estimator<Comparable<?>> estimator) throws TasteException {
Queue<SimilarUser> topUsers = new PriorityQueue<SimilarUser>(howMany + 1, Collections.reverseOrder());
boolean full = false;
double lowestTopValue = Double.NEGATIVE_INFINITY;
- for (User user : allUsers) {
- if (rescorer != null && rescorer.isFiltered(user)) {
+ for (Comparable<?> userID : allUserIDs) {
+ if (rescorer != null && rescorer.isFiltered(userID)) {
continue;
}
- double similarity = estimator.estimate(user);
- double rescoredSimilarity = rescorer == null ? similarity : rescorer.rescore(user, similarity);
+ double similarity = estimator.estimate(userID);
+ double rescoredSimilarity = rescorer == null ? similarity : rescorer.rescore(userID, similarity);
if (!Double.isNaN(rescoredSimilarity) && (!full || rescoredSimilarity > lowestTopValue)) {
- topUsers.add(new SimilarUser(user, similarity));
+ topUsers.add(new SimilarUser(userID, similarity));
if (full) {
topUsers.poll();
} else if (topUsers.size() > howMany) {
@@ -95,9 +94,9 @@
List<SimilarUser> sorted = new ArrayList<SimilarUser>(topUsers.size());
sorted.addAll(topUsers);
Collections.sort(sorted);
- List<User> result = new ArrayList<User>(sorted.size());
+ List<Comparable<?>> result = new ArrayList<Comparable<?>>(sorted.size());
for (SimilarUser similarUser : sorted) {
- result.add(similarUser.getUser());
+ result.add(similarUser.getUserID());
}
return result;
}