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;
   }