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/11 14:04:38 UTC

svn commit: r803081 [4/7] - in /lucene/mahout/trunk: core/src/main/java/org/apache/mahout/cf/taste/eval/ 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/maho...

Modified: lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/TreeClusteringRecommender.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/TreeClusteringRecommender.java?rev=803081&r1=803080&r2=803081&view=diff
==============================================================================
--- lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/TreeClusteringRecommender.java (original)
+++ lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/TreeClusteringRecommender.java Tue Aug 11 12:04:35 2009
@@ -19,9 +19,10 @@
 
 import org.apache.mahout.cf.taste.common.Refreshable;
 import org.apache.mahout.cf.taste.common.TasteException;
-import org.apache.mahout.cf.taste.impl.common.FastMap;
-import org.apache.mahout.cf.taste.impl.common.FastSet;
+import org.apache.mahout.cf.taste.impl.common.FastByIDMap;
+import org.apache.mahout.cf.taste.impl.common.FastIDSet;
 import org.apache.mahout.cf.taste.impl.common.FullRunningAverage;
+import org.apache.mahout.cf.taste.impl.common.LongPrimitiveIterator;
 import org.apache.mahout.cf.taste.impl.common.Pair;
 import org.apache.mahout.cf.taste.impl.common.RandomUtils;
 import org.apache.mahout.cf.taste.impl.common.RefreshHelper;
@@ -38,7 +39,6 @@
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
-import java.util.Map;
 import java.util.Random;
 import java.util.concurrent.Callable;
 import java.util.concurrent.locks.ReentrantLock;
@@ -52,7 +52,7 @@
  *
  * <ul>
  * <li>For all users in a cluster, recommendations will be the same</li>
- * <li>{@link #estimatePreference(Comparable, Comparable)} may well return {@link Double#NaN};
+ * <li>{@link #estimatePreference(long, long)} may well return {@link Double#NaN};
  *  it does so when asked to estimate preference for an item for
  *  which no preference is expressed in the users in the cluster.</li>
  * </ul>
@@ -68,9 +68,9 @@
   private final double clusteringThreshold;
   private final boolean clusteringByThreshold;
   private final double samplingRate;
-  private Map<Comparable<?>, List<RecommendedItem>> topRecsByUserID;
-  private Collection<Collection<Comparable<?>>> allClusters;
-  private Map<Comparable<?>, Collection<Comparable<?>>> clustersByUserID;
+  private FastByIDMap<List<RecommendedItem>> topRecsByUserID;
+  private FastIDSet[] allClusters;
+  private FastByIDMap<FastIDSet> clustersByUserID;
   private boolean clustersBuilt;
   private final ReentrantLock buildClustersLock;
   private final RefreshHelper refreshHelper;
@@ -185,11 +185,8 @@
   }
 
   @Override
-  public List<RecommendedItem> recommend(Comparable<?> userID, int howMany, Rescorer<Comparable<?>> rescorer)
+  public List<RecommendedItem> recommend(long userID, int howMany, Rescorer<Long> rescorer)
       throws TasteException {
-    if (userID == null) {
-      throw new IllegalArgumentException("userID is null");
-    }
     if (howMany < 1) {
       throw new IllegalArgumentException("howMany must be at least 1");
     }
@@ -207,7 +204,7 @@
     // Only add items the user doesn't already have a preference for.
     // And that the rescorer doesn't "reject".
     for (RecommendedItem recommendedItem : recommended) {
-      Comparable<?> itemID = recommendedItem.getItemID();
+      long itemID = recommendedItem.getItemID();
       if (rescorer != null && rescorer.isFiltered(itemID)) {
         continue;
       }
@@ -222,10 +219,7 @@
   }
 
   @Override
-  public float estimatePreference(Comparable<?> userID, Comparable<?> itemID) throws TasteException {
-    if (userID == null || itemID == null) {
-      throw new IllegalArgumentException("userID or itemID is null");
-    }
+  public float estimatePreference(long userID, long itemID) throws TasteException {
     DataModel model = getDataModel();
     Float actualPref = model.getPreferenceValue(userID, itemID);
     if (actualPref != null) {
@@ -235,7 +229,7 @@
     List<RecommendedItem> topRecsForUser = topRecsByUserID.get(userID);
     if (topRecsForUser != null) {
       for (RecommendedItem item : topRecsForUser) {
-        if (itemID.equals(item.getItemID())) {
+        if (itemID == item.getItemID()) {
           return item.getValue();
         }
       }
@@ -245,17 +239,14 @@
   }
 
   @Override
-  public Collection<Comparable<?>> getCluster(Comparable<?> userID) throws TasteException {
-    if (userID == null) {
-      throw new IllegalArgumentException("userID is null");
-    }
+  public FastIDSet getCluster(long userID) throws TasteException {
     checkClustersBuilt();
-    Collection<Comparable<?>> cluster = clustersByUserID.get(userID);
-    return cluster == null ? Collections.<Comparable<?>>emptyList() : cluster;
+    FastIDSet cluster = clustersByUserID.get(userID);
+    return cluster == null ? new FastIDSet() : cluster;
   }
 
   @Override
-  public Collection<Collection<Comparable<?>>> getClusters() throws TasteException {
+  public FastIDSet[] getClusters() throws TasteException {
     checkClustersBuilt();
     return allClusters;
   }
@@ -272,11 +263,12 @@
       DataModel model = getDataModel();
       int numUsers = model.getNumUsers();
       if (numUsers > 0) {
-        List<Collection<Comparable<?>>> newClusters = new ArrayList<Collection<Comparable<?>>>(numUsers);
+        List<FastIDSet> newClusters = new ArrayList<FastIDSet>(numUsers);
         // Begin with a cluster for each user:
-        for (Comparable<?> userID : model.getUserIDs()) {
-          Collection<Comparable<?>> newCluster = new FastSet<Comparable<?>>();
-          newCluster.add(userID);
+        LongPrimitiveIterator it = model.getUserIDs();
+        while (it.hasNext()) {
+          FastIDSet newCluster = new FastIDSet();
+          newCluster.add(it.nextLong());
           newClusters.add(newCluster);
         }
         if (numUsers > 1) {
@@ -284,11 +276,11 @@
         }
         topRecsByUserID = computeTopRecsPerUserID(newClusters);
         clustersByUserID = computeClustersPerUserID(newClusters);
-        allClusters = newClusters;
+        allClusters = newClusters.toArray(new FastIDSet[newClusters.size()]);
       } else {
-        topRecsByUserID = Collections.emptyMap();
-        clustersByUserID = Collections.emptyMap();
-        allClusters = Collections.emptySet();
+        topRecsByUserID = new FastByIDMap<List<RecommendedItem>>();
+        clustersByUserID = new FastByIDMap<FastIDSet>();
+        allClusters = new FastIDSet[0];
       }
       clustersBuilt = true;
     } finally {
@@ -296,16 +288,16 @@
     }
   }
 
-  private void findClusters(List<Collection<Comparable<?>>> newClusters) throws TasteException {
+  private void findClusters(List<FastIDSet> newClusters) throws TasteException {
     if (clusteringByThreshold) {
-      Pair<Collection<Comparable<?>>, Collection<Comparable<?>>> nearestPair = findNearestClusters(newClusters);
+      Pair<FastIDSet, FastIDSet> nearestPair = findNearestClusters(newClusters);
       if (nearestPair != null) {
-        Collection<Comparable<?>> cluster1 = nearestPair.getFirst();
-        Collection<Comparable<?>> cluster2 = nearestPair.getSecond();
+        FastIDSet cluster1 = nearestPair.getFirst();
+        FastIDSet cluster2 = nearestPair.getSecond();
         while (clusterSimilarity.getSimilarity(cluster1, cluster2) >= clusteringThreshold) {
           newClusters.remove(cluster1);
           newClusters.remove(cluster2);
-          Collection<Comparable<?>> merged = new FastSet<Comparable<?>>(cluster1.size() + cluster2.size());
+          FastIDSet merged = new FastIDSet(cluster1.size() + cluster2.size());
           merged.addAll(cluster1);
           merged.addAll(cluster2);
           newClusters.add(merged);
@@ -319,16 +311,15 @@
       }
     } else {
       while (newClusters.size() > numClusters) {
-        Pair<Collection<Comparable<?>>, Collection<Comparable<?>>> nearestPair =
-            findNearestClusters(newClusters);
+        Pair<FastIDSet, FastIDSet> nearestPair = findNearestClusters(newClusters);
         if (nearestPair == null) {
           break;
         }
-        Collection<Comparable<?>> cluster1 = nearestPair.getFirst();
-        Collection<Comparable<?>> cluster2 = nearestPair.getSecond();
+        FastIDSet cluster1 = nearestPair.getFirst();
+        FastIDSet cluster2 = nearestPair.getSecond();
         newClusters.remove(cluster1);
         newClusters.remove(cluster2);
-        Collection<Comparable<?>> merged = new FastSet<Comparable<?>>(cluster1.size() + cluster2.size());
+        FastIDSet merged = new FastIDSet(cluster1.size() + cluster2.size());
         merged.addAll(cluster1);
         merged.addAll(cluster2);
         newClusters.add(merged);
@@ -336,20 +327,19 @@
     }
   }
 
-  private Pair<Collection<Comparable<?>>, Collection<Comparable<?>>>
-      findNearestClusters(List<Collection<Comparable<?>>> clusters) throws TasteException {
+  private Pair<FastIDSet, FastIDSet> findNearestClusters(List<FastIDSet> clusters) throws TasteException {
     int size = clusters.size();
-    Pair<Collection<Comparable<?>>, Collection<Comparable<?>>> nearestPair = null;
+    Pair<FastIDSet, FastIDSet> nearestPair = null;
     double bestSimilarity = Double.NEGATIVE_INFINITY;
     for (int i = 0; i < size; i++) {
-      Collection<Comparable<?>> cluster1 = clusters.get(i);
+      FastIDSet cluster1 = clusters.get(i);
       for (int j = i + 1; j < size; j++) {
         if (samplingRate >= 1.0 || r.nextDouble() < samplingRate) {
-          Collection<Comparable<?>> cluster2 = clusters.get(j);
+          FastIDSet cluster2 = clusters.get(j);
           double similarity = clusterSimilarity.getSimilarity(cluster1, cluster2);
           if (!Double.isNaN(similarity) && similarity > bestSimilarity) {
             bestSimilarity = similarity;
-            nearestPair = new Pair<Collection<Comparable<?>>, Collection<Comparable<?>>>(cluster1, cluster2);
+            nearestPair = new Pair<FastIDSet, FastIDSet>(cluster1, cluster2);
           }
         }
       }
@@ -357,46 +347,46 @@
     return nearestPair;
   }
 
-  private Map<Comparable<?>, List<RecommendedItem>> computeTopRecsPerUserID(
-      Iterable<Collection<Comparable<?>>> clusters) throws TasteException {
-    Map<Comparable<?>, List<RecommendedItem>> recsPerUser = new FastMap<Comparable<?>, List<RecommendedItem>>();
-    for (Collection<Comparable<?>> cluster : clusters) {
+  private FastByIDMap<List<RecommendedItem>> computeTopRecsPerUserID(List<FastIDSet> clusters) throws TasteException {
+    FastByIDMap<List<RecommendedItem>> recsPerUser = new FastByIDMap<List<RecommendedItem>>();
+    for (FastIDSet cluster : clusters) {
       List<RecommendedItem> recs = computeTopRecsForCluster(cluster);
-      for (Comparable<?> userID : cluster) {
-        recsPerUser.put(userID, recs);
+      LongPrimitiveIterator it = cluster.iterator();
+      while (it.hasNext()) {
+        recsPerUser.put(it.next(), recs);
       }
     }
-    return Collections.unmodifiableMap(recsPerUser);
+    return recsPerUser;
   }
 
-  private List<RecommendedItem> computeTopRecsForCluster(Collection<Comparable<?>> cluster)
+  private List<RecommendedItem> computeTopRecsForCluster(FastIDSet cluster)
       throws TasteException {
     DataModel dataModel = getDataModel();
-    Collection<Comparable<?>> allItemIDs = new FastSet<Comparable<?>>();
-    for (Comparable<?> userID : cluster) {
-      PreferenceArray prefs = dataModel.getPreferencesFromUser(userID);
+    FastIDSet allItemIDs = new FastIDSet();
+    LongPrimitiveIterator it = cluster.iterator();
+    while (it.hasNext()) {
+      PreferenceArray prefs = dataModel.getPreferencesFromUser(it.next());
       int size = prefs.length();
       for (int i = 0; i < size; i++) {
         allItemIDs.add(prefs.getItemID(i));
       }
     }
 
-    TopItems.Estimator<Comparable<?>> estimator = new Estimator(cluster);
+    TopItems.Estimator<Long> estimator = new Estimator(cluster);
 
     // TODO don't hardcode 100, figure out some reasonable value
-    List<RecommendedItem> topItems = TopItems.getTopItems(100, allItemIDs, null, estimator);
+    List<RecommendedItem> topItems = TopItems.getTopItems(100, allItemIDs.iterator(), null, estimator);
 
     log.debug("Recommendations are: {}", topItems);
     return Collections.unmodifiableList(topItems);
   }
 
-  private static Map<Comparable<?>, Collection<Comparable<?>>>
-      computeClustersPerUserID(Collection<Collection<Comparable<?>>> clusters) {
-    Map<Comparable<?>, Collection<Comparable<?>>> clustersPerUser =
-            new FastMap<Comparable<?>, Collection<Comparable<?>>>(clusters.size());
-    for (Collection<Comparable<?>> cluster : clusters) {
-      for (Comparable<?> userID : cluster) {
-        clustersPerUser.put(userID, cluster);
+  private static FastByIDMap<FastIDSet> computeClustersPerUserID(List<FastIDSet> clusters) {
+    FastByIDMap<FastIDSet> clustersPerUser = new FastByIDMap<FastIDSet>(clusters.size());
+    for (FastIDSet cluster : clusters) {
+      LongPrimitiveIterator it = cluster.iterator();
+      while (it.hasNext()) {
+        clustersPerUser.put(it.next(), cluster);
       }
     }
     return clustersPerUser;
@@ -412,20 +402,21 @@
     return "TreeClusteringRecommender[clusterSimilarity:" + clusterSimilarity + ']';
   }
 
-  private class Estimator implements TopItems.Estimator<Comparable<?>> {
+  private class Estimator implements TopItems.Estimator<Long> {
 
-    private final Collection<Comparable<?>> cluster;
+    private final FastIDSet cluster;
 
-    private Estimator(Collection<Comparable<?>> cluster) {
+    private Estimator(FastIDSet cluster) {
       this.cluster = cluster;
     }
 
     @Override
-    public double estimate(Comparable<?> itemID) throws TasteException {
+    public double estimate(Long itemID) throws TasteException {
       DataModel dataModel = getDataModel();
       RunningAverage average = new FullRunningAverage();
-      for (Comparable<?> userID : cluster) {
-        Float pref = dataModel.getPreferenceValue(userID, itemID);
+      LongPrimitiveIterator it = cluster.iterator();
+      while (it.hasNext()) {
+        Float pref = dataModel.getPreferenceValue(it.next(), itemID);
         if (pref != null) {
           average.addDatum(pref);
         }

Modified: lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/TreeClusteringRecommender2.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/TreeClusteringRecommender2.java?rev=803081&r1=803080&r2=803081&view=diff
==============================================================================
--- lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/TreeClusteringRecommender2.java (original)
+++ lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/TreeClusteringRecommender2.java Tue Aug 11 12:04:35 2009
@@ -19,9 +19,10 @@
 
 import org.apache.mahout.cf.taste.common.Refreshable;
 import org.apache.mahout.cf.taste.common.TasteException;
-import org.apache.mahout.cf.taste.impl.common.FastMap;
-import org.apache.mahout.cf.taste.impl.common.FastSet;
+import org.apache.mahout.cf.taste.impl.common.FastByIDMap;
+import org.apache.mahout.cf.taste.impl.common.FastIDSet;
 import org.apache.mahout.cf.taste.impl.common.FullRunningAverage;
+import org.apache.mahout.cf.taste.impl.common.LongPrimitiveIterator;
 import org.apache.mahout.cf.taste.impl.common.RandomUtils;
 import org.apache.mahout.cf.taste.impl.common.RefreshHelper;
 import org.apache.mahout.cf.taste.impl.common.RunningAverage;
@@ -40,7 +41,6 @@
 import java.util.LinkedList;
 import java.util.List;
 import java.util.ListIterator;
-import java.util.Map;
 import java.util.concurrent.Callable;
 import java.util.concurrent.locks.ReentrantLock;
 
@@ -52,7 +52,7 @@
  *
  * <p>This {@link org.apache.mahout.cf.taste.recommender.Recommender} therefore has a few properties to note:</p> <ul>
  * <li>For all users in a cluster, recommendations will be the same</li>
- * <li>{@link #estimatePreference(Comparable, Comparable)} may well return {@link Double#NaN}; it does so
+ * <li>{@link #estimatePreference(long, long)} may well return {@link Double#NaN}; it does so
  * when asked to estimate preference for an item for which no preference is expressed in the
  * users in the cluster.</li> </ul>
  *
@@ -69,9 +69,9 @@
   private final int numClusters;
   private final double clusteringThreshold;
   private final boolean clusteringByThreshold;
-  private Map<Comparable<?>, List<RecommendedItem>> topRecsByUserID;
-  private Collection<Collection<Comparable<?>>> allClusters;
-  private Map<Comparable<?>, Collection<Comparable<?>>> clustersByUserID;
+  private FastByIDMap<List<RecommendedItem>> topRecsByUserID;
+  private FastIDSet[] allClusters;
+  private FastByIDMap<FastIDSet> clustersByUserID;
   private boolean clustersBuilt;
   private final ReentrantLock buildClustersLock;
   private final RefreshHelper refreshHelper;
@@ -145,11 +145,8 @@
   }
 
   @Override
-  public List<RecommendedItem> recommend(Comparable<?> userID, int howMany, Rescorer<Comparable<?>> rescorer)
+  public List<RecommendedItem> recommend(long userID, int howMany, Rescorer<Long> rescorer)
       throws TasteException {
-    if (userID == null) {
-      throw new IllegalArgumentException("userID is null");
-    }
     if (howMany < 1) {
       throw new IllegalArgumentException("howMany must be at least 1");
     }
@@ -167,7 +164,7 @@
     // Only add items the user doesn't already have a preference for.
     // And that the rescorer doesn't "reject".
     for (RecommendedItem recommendedItem : recommended) {
-      Comparable<?> itemID = recommendedItem.getItemID();
+      long itemID = recommendedItem.getItemID();
       if (rescorer != null && rescorer.isFiltered(itemID)) {
         continue;
       }
@@ -182,11 +179,7 @@
   }
 
   @Override
-  public float estimatePreference(Comparable<?> userID, Comparable<?> itemID) throws TasteException {
-    if (userID == null || itemID == null) {
-      throw new IllegalArgumentException("userID or itemID is null");
-    }
-    DataModel model = getDataModel();
+  public float estimatePreference(long userID, long itemID) throws TasteException {
     Float actualPref = getDataModel().getPreferenceValue(userID, itemID);
     if (actualPref != null) {
       return actualPref;
@@ -195,7 +188,7 @@
     List<RecommendedItem> topRecsForUser = topRecsByUserID.get(userID);
     if (topRecsForUser != null) {
       for (RecommendedItem item : topRecsForUser) {
-        if (itemID.equals(item.getItemID())) {
+        if (itemID == item.getItemID()) {
           return item.getValue();
         }
       }
@@ -205,17 +198,14 @@
   }
 
   @Override
-  public Collection<Comparable<?>> getCluster(Comparable<?> userID) throws TasteException {
-    if (userID == null) {
-      throw new IllegalArgumentException("userID is null");
-    }
+  public FastIDSet getCluster(long userID) throws TasteException {
     checkClustersBuilt();
-    Collection<Comparable<?>> cluster = clustersByUserID.get(userID);
-    return cluster == null ? Collections.<Comparable<?>>emptyList() : cluster;
+    FastIDSet cluster = clustersByUserID.get(userID);
+    return cluster == null ? new FastIDSet() : cluster;
   }
 
   @Override
-  public Collection<Collection<Comparable<?>>> getClusters() throws TasteException {
+  public FastIDSet[] getClusters() throws TasteException {
     checkClustersBuilt();
     return allClusters;
   }
@@ -228,23 +218,23 @@
 
   private static final class ClusterClusterPair implements Comparable<ClusterClusterPair> {
 
-    private final Collection<Comparable<?>> cluster1;
-    private final Collection<Comparable<?>> cluster2;
+    private final FastIDSet cluster1;
+    private final FastIDSet cluster2;
     private final double similarity;
 
-    private ClusterClusterPair(Collection<Comparable<?>> cluster1,
-                               Collection<Comparable<?>> cluster2,
+    private ClusterClusterPair(FastIDSet cluster1,
+                               FastIDSet cluster2,
                                double similarity) {
       this.cluster1 = cluster1;
       this.cluster2 = cluster2;
       this.similarity = similarity;
     }
 
-    private Collection<Comparable<?>> getCluster1() {
+    private FastIDSet getCluster1() {
       return cluster1;
     }
 
-    private Collection<Comparable<?>> getCluster2() {
+    private FastIDSet getCluster2() {
       return cluster2;
     }
 
@@ -290,16 +280,17 @@
 
       if (numUsers == 0) {
 
-        topRecsByUserID = Collections.emptyMap();
-        clustersByUserID = Collections.emptyMap();
+        topRecsByUserID = new FastByIDMap<List<RecommendedItem>>();
+        clustersByUserID = new FastByIDMap<FastIDSet>();
 
       } else {
 
-        List<Collection<Comparable<?>>> clusters = new LinkedList<Collection<Comparable<?>>>();
+        List<FastIDSet> clusters = new LinkedList<FastIDSet>();
         // Begin with a cluster for each user:
-        for (Comparable<?> userID : model.getUserIDs()) {
-          Collection<Comparable<?>> newCluster = new FastSet<Comparable<?>>();
-          newCluster.add(userID);
+        LongPrimitiveIterator it = model.getUserIDs();
+        while (it.hasNext()) {
+          FastIDSet newCluster = new FastIDSet();
+          newCluster.add(it.nextLong());
           clusters.add(newCluster);
         }
 
@@ -310,7 +301,7 @@
 
         topRecsByUserID = computeTopRecsPerUserID(clusters);
         clustersByUserID = computeClustersPerUserID(clusters);
-        allClusters = clusters;
+        allClusters = clusters.toArray(new FastIDSet[clusters.size()]);
 
       }
 
@@ -320,7 +311,7 @@
     }
   }
 
-  private boolean mergeClosestClusters(int numUsers, List<Collection<Comparable<?>>> clusters, boolean done)
+  private boolean mergeClosestClusters(int numUsers, List<FastIDSet> clusters, boolean done)
       throws TasteException {
     // We find a certain number of closest clusters...
     LinkedList<ClusterClusterPair> queue = findClosestClusters(numUsers, clusters);
@@ -344,15 +335,15 @@
         break;
       }
 
-      Collection<Comparable<?>> cluster1 = top.getCluster1();
-      Collection<Comparable<?>> cluster2 = top.getCluster2();
+      FastIDSet cluster1 = top.getCluster1();
+      FastIDSet cluster2 = top.getCluster2();
 
       // Pull out current two clusters from clusters
-      Iterator<Collection<Comparable<?>>> clusterIterator = clusters.iterator();
+      Iterator<FastIDSet> clusterIterator = clusters.iterator();
       boolean removed1 = false;
       boolean removed2 = false;
       while (clusterIterator.hasNext() && !(removed1 && removed2)) {
-        Collection<Comparable<?>> current = clusterIterator.next();
+        FastIDSet current = clusterIterator.next();
         // Yes, use == here
         if (!removed1 && cluster1 == current) {
           clusterIterator.remove();
@@ -368,22 +359,22 @@
       for (Iterator<ClusterClusterPair> queueIterator = queue.iterator();
            queueIterator.hasNext();) {
         ClusterClusterPair pair = queueIterator.next();
-        Collection<Comparable<?>> pair1 = pair.getCluster1();
-        Collection<Comparable<?>> pair2 = pair.getCluster2();
+        FastIDSet pair1 = pair.getCluster1();
+        FastIDSet pair2 = pair.getCluster2();
         if (pair1 == cluster1 || pair1 == cluster2 || pair2 == cluster1 || pair2 == cluster2) {
           queueIterator.remove();
         }
       }
 
       // Make new merged cluster
-      Collection<Comparable<?>> merged = new FastSet<Comparable<?>>(cluster1.size() + cluster2.size());
+      FastIDSet merged = new FastIDSet(cluster1.size() + cluster2.size());
       merged.addAll(cluster1);
       merged.addAll(cluster2);
 
       // Compare against other clusters; update queue if needed
       // That new pair we're just adding might be pretty close to something else, so
       // catch that case here and put it back into our queue
-      for (Collection<Comparable<?>> cluster : clusters) {
+      for (FastIDSet cluster : clusters) {
         double similarity = clusterSimilarity.getSimilarity(merged, cluster);
         if (similarity > queue.getLast().getSimilarity()) {
           ListIterator<ClusterClusterPair> queueIterator = queue.listIterator();
@@ -404,16 +395,16 @@
     return done;
   }
 
-  private LinkedList<ClusterClusterPair> findClosestClusters(int numUsers, List<Collection<Comparable<?>>> clusters)
+  private LinkedList<ClusterClusterPair> findClosestClusters(int numUsers, List<FastIDSet> clusters)
       throws TasteException {
     boolean full = false;
     LinkedList<ClusterClusterPair> queue = new LinkedList<ClusterClusterPair>();
     int i = 0;
-    for (Collection<Comparable<?>> cluster1 : clusters) {
+    for (FastIDSet cluster1 : clusters) {
       i++;
-      ListIterator<Collection<Comparable<?>>> it2 = clusters.listIterator(i);
+      ListIterator<FastIDSet> it2 = clusters.listIterator(i);
       while (it2.hasNext()) {
-        Collection<Comparable<?>> cluster2 = it2.next();
+        FastIDSet cluster2 = it2.next();
         double similarity = clusterSimilarity.getSimilarity(cluster1, cluster2);
         if (!Double.isNaN(similarity) &&
             (!full || similarity > queue.getLast().getSimilarity())) {
@@ -438,47 +429,49 @@
     return queue;
   }
 
-  private Map<Comparable<?>, List<RecommendedItem>>
-      computeTopRecsPerUserID(Iterable<Collection<Comparable<?>>> clusters) throws TasteException {
-    Map<Comparable<?>, List<RecommendedItem>> recsPerUser = new FastMap<Comparable<?>, List<RecommendedItem>>();
-    for (Collection<Comparable<?>> cluster : clusters) {
+  private FastByIDMap<List<RecommendedItem>> computeTopRecsPerUserID(Iterable<FastIDSet> clusters) throws TasteException {
+    FastByIDMap<List<RecommendedItem>> recsPerUser = new FastByIDMap<List<RecommendedItem>>();
+    for (FastIDSet cluster : clusters) {
       List<RecommendedItem> recs = computeTopRecsForCluster(cluster);
-      for (Comparable<?> userID : cluster) {
-        recsPerUser.put(userID, recs);
+      LongPrimitiveIterator it = cluster.iterator();
+      while (it.hasNext()) {
+        recsPerUser.put(it.next(), recs);
       }
     }
-    return Collections.unmodifiableMap(recsPerUser);
+    return recsPerUser;
   }
 
-  private List<RecommendedItem> computeTopRecsForCluster(Collection<Comparable<?>> cluster)
+  private List<RecommendedItem> computeTopRecsForCluster(FastIDSet cluster)
       throws TasteException {
 
     DataModel dataModel = getDataModel();
-    Collection<Comparable<?>> allItemIDs = new FastSet<Comparable<?>>();
-    for (Comparable<?> userID : cluster) {
-      PreferenceArray prefs = dataModel.getPreferencesFromUser(userID);
+    FastIDSet allItemIDs = new FastIDSet();
+    LongPrimitiveIterator it = cluster.iterator();
+    while (it.hasNext()) {
+      PreferenceArray prefs = dataModel.getPreferencesFromUser(it.next());
       int size = prefs.length();
       for (int i = 0; i < size; i++) {
         allItemIDs.add(prefs.getItemID(i));
       }
     }
 
-    TopItems.Estimator<Comparable<?>> estimator = new Estimator(cluster);
+    TopItems.Estimator<Long> estimator = new Estimator(cluster);
 
     List<RecommendedItem> topItems =
-        TopItems.getTopItems(Integer.MAX_VALUE, allItemIDs, null, estimator);
+        TopItems.getTopItems(Integer.MAX_VALUE, allItemIDs.iterator(), null, estimator);
 
     log.debug("Recommendations are: {}", topItems);
     return Collections.unmodifiableList(topItems);
   }
 
-  private static Map<Comparable<?>, Collection<Comparable<?>>>
-      computeClustersPerUserID(Collection<Collection<Comparable<?>>> clusters) {
-    Map<Comparable<?>, Collection<Comparable<?>>> clustersPerUser =
-            new FastMap<Comparable<?>, Collection<Comparable<?>>>(clusters.size());
-    for (Collection<Comparable<?>> cluster : clusters) {
-      for (Comparable<?> userID : cluster) {
-        clustersPerUser.put(userID, cluster);
+  private static FastByIDMap<FastIDSet>
+      computeClustersPerUserID(Collection<FastIDSet> clusters) {
+    FastByIDMap<FastIDSet> clustersPerUser =
+            new FastByIDMap<FastIDSet>(clusters.size());
+    for (FastIDSet cluster : clusters) {
+      LongPrimitiveIterator it = cluster.iterator();
+      while (it.hasNext()) {
+        clustersPerUser.put(it.next(), cluster);
       }
     }
     return clustersPerUser;
@@ -494,20 +487,21 @@
     return "TreeClusteringRecommender2[clusterSimilarity:" + clusterSimilarity + ']';
   }
 
-  private class Estimator implements TopItems.Estimator<Comparable<?>> {
+  private class Estimator implements TopItems.Estimator<Long> {
 
-    private final Collection<Comparable<?>> cluster;
+    private final FastIDSet cluster;
 
-    private Estimator(Collection<Comparable<?>> cluster) {
+    private Estimator(FastIDSet cluster) {
       this.cluster = cluster;
     }
 
     @Override
-    public double estimate(Comparable<?> itemID) throws TasteException {
+    public double estimate(Long itemID) throws TasteException {
       DataModel dataModel = getDataModel();
       RunningAverage average = new FullRunningAverage();
-      for (Comparable<?> userID : cluster) {
-        Float pref = dataModel.getPreferenceValue(userID, itemID);
+      LongPrimitiveIterator it = cluster.iterator();
+      while (it.hasNext()) {
+        Float pref = dataModel.getPreferenceValue(it.next(), itemID);
         if (pref != null) {
           average.addDatum(pref);
         }

Modified: lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/knn/KnnItemBasedRecommender.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/knn/KnnItemBasedRecommender.java?rev=803081&r1=803080&r2=803081&view=diff
==============================================================================
--- lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/knn/KnnItemBasedRecommender.java (original)
+++ lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/knn/KnnItemBasedRecommender.java Tue Aug 11 12:04:35 2009
@@ -18,8 +18,9 @@
 package org.apache.mahout.cf.taste.impl.recommender.knn;
 
 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.FastIDSet;
+import org.apache.mahout.cf.taste.impl.common.LongPair;
+import org.apache.mahout.cf.taste.impl.common.LongPrimitiveIterator;
 import org.apache.mahout.cf.taste.impl.recommender.GenericItemBasedRecommender;
 import org.apache.mahout.cf.taste.impl.recommender.TopItems;
 import org.apache.mahout.cf.taste.model.DataModel;
@@ -28,8 +29,6 @@
 import org.apache.mahout.cf.taste.recommender.Rescorer;
 import org.apache.mahout.cf.taste.similarity.ItemSimilarity;
 
-import java.util.ArrayList;
-import java.util.Collection;
 import java.util.List;
 
 /**
@@ -50,20 +49,20 @@
     this.neighborhoodSize = neighborhoodSize;
   }
 
-  private List<RecommendedItem> mostSimilarItems(Comparable<?> itemID,
-                                                 Iterable<Comparable<?>> allItemIDs,
+  private List<RecommendedItem> mostSimilarItems(long itemID,
+                                                 LongPrimitiveIterator allItemIDs,
                                                  int howMany,
-                                                 Rescorer<Pair<Comparable<?>, Comparable<?>>> rescorer)
+                                                 Rescorer<LongPair> rescorer)
           throws TasteException {
-    TopItems.Estimator<Comparable<?>> estimator = new MostSimilarEstimator(itemID, getSimilarity(), rescorer);
+    TopItems.Estimator<Long> estimator = new MostSimilarEstimator(itemID, getSimilarity(), rescorer);
     return TopItems.getTopItems(howMany, allItemIDs, null, estimator);
   }
 
 
-  private double[] getInterpolations(Comparable<?> itemID, Comparable<?> userID, List<Comparable<?>> itemNeighborhood)
+  private double[] getInterpolations(long itemID, long userID, long[] itemNeighborhood)
           throws TasteException {
 
-    int k = itemNeighborhood.size();
+    int k = itemNeighborhood.length;
     double[][] A = new double[k][k];
     double[] b = new double[k];
     int i = 0;
@@ -71,15 +70,15 @@
     DataModel dataModel = getDataModel();
 
     int numUsers = getDataModel().getNumUsers();
-    for (Comparable<?> iitem : itemNeighborhood) {
+    for (long iitem : itemNeighborhood) {
       PreferenceArray iPrefs = getDataModel().getPreferencesForItem(iitem);
       int iSize = iPrefs.length();
       int j = 0;
-      for (Comparable<?> jitem : itemNeighborhood) {
+      for (long jitem : itemNeighborhood) {
         double value = 0.0;
         for (int pi = 0; pi < iSize; pi++) {
-          Comparable<?> v = iPrefs.getUserID(pi);
-          if (v.equals(userID)) {
+          long v = iPrefs.getUserID(pi);
+          if (v == userID) {
             continue;
           }
           Float pj = dataModel.getPreferenceValue(userID, jitem);
@@ -96,11 +95,11 @@
     PreferenceArray iPrefs = getDataModel().getPreferencesForItem(itemID);
     int iSize = iPrefs.length();
     i = 0;
-    for (Comparable<?> jitem : itemNeighborhood) {
+    for (long jitem : itemNeighborhood) {
       double value = 0.0;
       for (int pi = 0; pi < iSize; pi++) {
-        Comparable<?> v = iPrefs.getUserID(pi);
-        if (v.equals(userID)) {
+        long v = iPrefs.getUserID(pi);
+        if (v == userID) {
           continue;
         }
         Float pj = dataModel.getPreferenceValue(userID, jitem);
@@ -116,10 +115,10 @@
   }
 
   @Override
-  protected float doEstimatePreference(Comparable<?> theUserID, Comparable<?> itemID) throws TasteException {
+  protected float doEstimatePreference(long theUserID, long itemID) throws TasteException {
 
     DataModel dataModel = getDataModel();
-    Collection<Comparable<?>> allItemIDs = new FastSet<Comparable<?>>();
+    FastIDSet allItemIDs = new FastIDSet();
     PreferenceArray prefs = dataModel.getPreferencesFromUser(theUserID);
     int size = prefs.length();
     for (int i = 0; i < size; i++) {
@@ -127,19 +126,19 @@
     }
     allItemIDs.remove(itemID);
 
-    List<RecommendedItem> mostSimilar = mostSimilarItems(itemID, allItemIDs, neighborhoodSize, null);
-    List<Comparable<?>> theNeighborhood = new ArrayList<Comparable<?>>(mostSimilar.size());
+    List<RecommendedItem> mostSimilar = mostSimilarItems(itemID, allItemIDs.iterator(), neighborhoodSize, null);
+    long[] theNeighborhood = new long[mostSimilar.size()];
+    int nOffset = 0;
     for (RecommendedItem rec : mostSimilar) {
-      theNeighborhood.add(rec.getItemID());
+      theNeighborhood[nOffset++] = rec.getItemID();
     }
 
-
     double[] weights = getInterpolations(itemID, theUserID, theNeighborhood);
 
     int i = 0;
     double preference = 0.0;
     double totalSimilarity = 0.0;
-    for (Comparable<?> jitem : theNeighborhood) {
+    for (long jitem : theNeighborhood) {
 
       Float pref = dataModel.getPreferenceValue(theUserID, jitem);
 

Modified: lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/slopeone/MemoryDiffStorage.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/slopeone/MemoryDiffStorage.java?rev=803081&r1=803080&r2=803081&view=diff
==============================================================================
--- lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/slopeone/MemoryDiffStorage.java (original)
+++ lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/slopeone/MemoryDiffStorage.java Tue Aug 11 12:04:35 2009
@@ -22,10 +22,11 @@
 import org.apache.mahout.cf.taste.common.Weighting;
 import org.apache.mahout.cf.taste.impl.common.CompactRunningAverage;
 import org.apache.mahout.cf.taste.impl.common.CompactRunningAverageAndStdDev;
-import org.apache.mahout.cf.taste.impl.common.FastMap;
-import org.apache.mahout.cf.taste.impl.common.FastSet;
+import org.apache.mahout.cf.taste.impl.common.FastByIDMap;
+import org.apache.mahout.cf.taste.impl.common.FastIDSet;
 import org.apache.mahout.cf.taste.impl.common.FullRunningAverage;
 import org.apache.mahout.cf.taste.impl.common.FullRunningAverageAndStdDev;
+import org.apache.mahout.cf.taste.impl.common.LongPrimitiveIterator;
 import org.apache.mahout.cf.taste.impl.common.RefreshHelper;
 import org.apache.mahout.cf.taste.impl.common.RunningAverage;
 import org.apache.mahout.cf.taste.impl.common.RunningAverageAndStdDev;
@@ -38,7 +39,6 @@
 import java.util.Collection;
 import java.util.Iterator;
 import java.util.Map;
-import java.util.Set;
 import java.util.concurrent.Callable;
 import java.util.concurrent.locks.ReadWriteLock;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
@@ -55,9 +55,9 @@
   private final boolean stdDevWeighted;
   private final boolean compactAverages;
   private final long maxEntries;
-  private final FastMap<Comparable<?>, FastMap<Comparable<?>, RunningAverage>> averageDiffs;
-  private final Map<Comparable<?>, RunningAverage> averageItemPref;
-  private final FastSet<Comparable<?>> allRecommendableItemIDs;
+  private final FastByIDMap<FastByIDMap<RunningAverage>> averageDiffs;
+  private final FastByIDMap<RunningAverage> averageItemPref;
+  private final FastIDSet allRecommendableItemIDs;
   private final ReadWriteLock buildAverageDiffsLock;
   private final RefreshHelper refreshHelper;
 
@@ -100,10 +100,10 @@
     this.stdDevWeighted = stdDevWeighted == Weighting.WEIGHTED;
     this.compactAverages = compactAverages;
     this.maxEntries = maxEntries;
-    this.averageDiffs = new FastMap<Comparable<?>, FastMap<Comparable<?>, RunningAverage>>();
-    this.averageItemPref = new FastMap<Comparable<?>, RunningAverage>();
+    this.averageDiffs = new FastByIDMap<FastByIDMap<RunningAverage>>();
+    this.averageItemPref = new FastByIDMap<RunningAverage>();
     this.buildAverageDiffsLock = new ReentrantReadWriteLock();
-    this.allRecommendableItemIDs = new FastSet<Comparable<?>>(dataModel.getNumItems());
+    this.allRecommendableItemIDs = new FastIDSet(dataModel.getNumItems());
     this.refreshHelper = new RefreshHelper(new Callable<Object>() {
       @Override
       public Object call() throws TasteException {
@@ -116,8 +116,8 @@
   }
 
   @Override
-  public RunningAverage getDiff(Comparable<?> itemID1, Comparable<?> itemID2) {
-    Map<Comparable<?>, RunningAverage> level2Map = averageDiffs.get(itemID1);
+  public RunningAverage getDiff(long itemID1, long itemID2) {
+    FastByIDMap<RunningAverage> level2Map = averageDiffs.get(itemID1);
     RunningAverage average = null;
     if (level2Map != null) {
       average = level2Map.get(itemID2);
@@ -143,7 +143,7 @@
   }
 
   @Override
-  public RunningAverage[] getDiffs(Comparable<?> userID, Comparable<?> itemID, PreferenceArray prefs)
+  public RunningAverage[] getDiffs(long userID, long itemID, PreferenceArray prefs)
           throws TasteException {
     try {
       buildAverageDiffsLock.readLock().lock();
@@ -159,20 +159,20 @@
   }
 
   @Override
-  public RunningAverage getAverageItemPref(Comparable<?> itemID) {
+  public RunningAverage getAverageItemPref(long itemID) {
     return averageItemPref.get(itemID);
   }
 
   @Override
-  public void updateItemPref(Comparable<?> itemID, float prefDelta, boolean remove) {
+  public void updateItemPref(long itemID, float prefDelta, boolean remove) {
     if (!remove && stdDevWeighted) {
       throw new UnsupportedOperationException("Can't update only when stdDevWeighted is set");
     }
     try {
       buildAverageDiffsLock.readLock().lock();
-      for (Map.Entry<Comparable<?>, FastMap<Comparable<?>, RunningAverage>> entry : averageDiffs.entrySet()) {
-        boolean matchesItemID1 = itemID.equals(entry.getKey());
-        for (Map.Entry<Comparable<?>, RunningAverage> entry2 : entry.getValue().entrySet()) {
+      for (Map.Entry<Long, FastByIDMap<RunningAverage>> entry : averageDiffs.entrySet()) {
+        boolean matchesItemID1 = itemID == entry.getKey();
+        for (Map.Entry<Long, RunningAverage> entry2 : entry.getValue().entrySet()) {
           RunningAverage average = entry2.getValue();
           if (matchesItemID1) {
             if (remove) {
@@ -180,7 +180,7 @@
             } else {
               average.changeDatum(-prefDelta);
             }
-          } else if (itemID.equals(entry2.getKey())) {
+          } else if (itemID == entry2.getKey()) {
             if (remove) {
               average.removeDatum(-prefDelta);
             } else {
@@ -199,9 +199,9 @@
   }
 
   @Override
-  public Set<Comparable<?>> getRecommendableItemIDs(Comparable<?> userID) throws TasteException {
-    Set<Comparable<?>> result = allRecommendableItemIDs.clone();
-    Iterator<Comparable<?>> it = result.iterator();
+  public FastIDSet getRecommendableItemIDs(long userID) throws TasteException {
+    FastIDSet result = allRecommendableItemIDs.clone();
+    Iterator<Long> it = result.iterator();
     while (it.hasNext()) {
       if (dataModel.getPreferenceValue(userID, it.next()) != null) {
         it.remove();
@@ -216,8 +216,9 @@
       buildAverageDiffsLock.writeLock().lock();
       averageDiffs.clear();
       long averageCount = 0L;
-      for (Comparable<?> userID : dataModel.getUserIDs()) {
-        averageCount = processOneUser(averageCount, userID);
+      LongPrimitiveIterator it = dataModel.getUserIDs();
+      while (it.hasNext()) {
+        averageCount = processOneUser(averageCount, it.nextLong());
       }
 
       pruneInconsequentialDiffs();
@@ -231,12 +232,12 @@
   private void pruneInconsequentialDiffs() {
     // Go back and prune inconsequential diffs. "Inconsequential" means, here, only represented by one
     // data point, so possibly unreliable
-    Iterator<FastMap<Comparable<?>, RunningAverage>> it1 = averageDiffs.values().iterator();
+    Iterator<Map.Entry<Long, FastByIDMap<RunningAverage>>> it1 = averageDiffs.entrySet().iterator();
     while (it1.hasNext()) {
-      FastMap<Comparable<?>, RunningAverage> map = it1.next();
-      Iterator<RunningAverage> it2 = map.values().iterator();
+      FastByIDMap<RunningAverage> map = it1.next().getValue();
+      Iterator<Map.Entry<Long, RunningAverage>> it2 = map.entrySet().iterator();
       while (it2.hasNext()) {
-        RunningAverage average = it2.next();
+        RunningAverage average = it2.next().getValue();
         if (average.getCount() <= 1) {
           it2.remove();
         }
@@ -251,32 +252,35 @@
   }
 
   private void updateAllRecommendableItems() throws TasteException {
-    FastSet<Comparable<?>> ids = new FastSet<Comparable<?>>(dataModel.getNumItems());
-    for (Map.Entry<Comparable<?>, FastMap<Comparable<?>, RunningAverage>> entry : averageDiffs.entrySet()) {
+    FastIDSet ids = new FastIDSet(dataModel.getNumItems());
+    for (Map.Entry<Long, FastByIDMap<RunningAverage>> entry : averageDiffs.entrySet()) {
       ids.add(entry.getKey());
-      ids.addAll(entry.getValue().keySet());
+      LongPrimitiveIterator it = entry.getValue().keySetIterator();
+      while (it.hasNext()) {
+        ids.add(it.next());
+      }
     }
     allRecommendableItemIDs.clear();
     allRecommendableItemIDs.addAll(ids);
     allRecommendableItemIDs.rehash();
   }
 
-  private long processOneUser(long averageCount, Comparable<?> userID) throws TasteException {
+  private long processOneUser(long averageCount, long userID) throws TasteException {
     log.debug("Processing prefs for user {}", userID);
     // Save off prefs for the life of this loop iteration
     PreferenceArray userPreferences = dataModel.getPreferencesFromUser(userID);
     int length = userPreferences.length();
     for (int i = 0; i < length; i++) {
       double prefAValue = userPreferences.getValue(i);
-      Comparable<?> itemIDA = userPreferences.getItemID(i);
-      FastMap<Comparable<?>, RunningAverage> aMap = averageDiffs.get(itemIDA);
+      long itemIDA = userPreferences.getItemID(i);
+      FastByIDMap<RunningAverage> aMap = averageDiffs.get(itemIDA);
       if (aMap == null) {
-        aMap = new FastMap<Comparable<?>, RunningAverage>();
+        aMap = new FastByIDMap<RunningAverage>();
         averageDiffs.put(itemIDA, aMap);
       }
       for (int j = i + 1; j < length; j++) {
         // This is a performance-critical block
-        Comparable<?> itemIDB = userPreferences.getItemID(j);
+        long itemIDB = userPreferences.getItemID(j);
         RunningAverage average = aMap.get(itemIDB);
         if (average == null && averageCount < maxEntries) {
           average = buildRunningAverage();

Modified: lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/slopeone/SlopeOneRecommender.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/slopeone/SlopeOneRecommender.java?rev=803081&r1=803080&r2=803081&view=diff
==============================================================================
--- lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/slopeone/SlopeOneRecommender.java (original)
+++ lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/slopeone/SlopeOneRecommender.java Tue Aug 11 12:04:35 2009
@@ -21,6 +21,7 @@
 import org.apache.mahout.cf.taste.common.Refreshable;
 import org.apache.mahout.cf.taste.common.TasteException;
 import org.apache.mahout.cf.taste.common.Weighting;
+import org.apache.mahout.cf.taste.impl.common.FastIDSet;
 import org.apache.mahout.cf.taste.impl.common.RefreshHelper;
 import org.apache.mahout.cf.taste.impl.common.RunningAverage;
 import org.apache.mahout.cf.taste.impl.common.RunningAverageAndStdDev;
@@ -36,7 +37,6 @@
 
 import java.util.Collection;
 import java.util.List;
-import java.util.Set;
 
 /**
  * <p>A basic "slope one" recommender. (See an <a href="http://www.daniel-lemire.com/fr/abstracts/SDM2005.html">
@@ -95,29 +95,26 @@
   }
 
   @Override
-  public List<RecommendedItem> recommend(Comparable<?> userID, int howMany, Rescorer<Comparable<?>> rescorer)
+  public List<RecommendedItem> recommend(long userID, int howMany, Rescorer<Long> 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);
 
-    Set<Comparable<?>> allItemIDs = diffStorage.getRecommendableItemIDs(userID);
+    FastIDSet allItemIDs = diffStorage.getRecommendableItemIDs(userID);
 
-    TopItems.Estimator<Comparable<?>> estimator = new Estimator(userID);
+    TopItems.Estimator<Long> estimator = new Estimator(userID);
 
-    List<RecommendedItem> topItems = TopItems.getTopItems(howMany, allItemIDs, rescorer, estimator);
+    List<RecommendedItem> topItems = TopItems.getTopItems(howMany, allItemIDs.iterator(), rescorer, estimator);
 
     log.debug("Recommendations are: {}", topItems);
     return topItems;
   }
 
   @Override
-  public float estimatePreference(Comparable<?> userID, Comparable<?> itemID) throws TasteException {
+  public float estimatePreference(long userID, long itemID) throws TasteException {
     DataModel model = getDataModel();
     Float actualPref = model.getPreferenceValue(userID, itemID);
     if (actualPref != null) {
@@ -126,7 +123,7 @@
     return doEstimatePreference(userID, itemID);
   }
 
-  private float doEstimatePreference(Comparable<?> userID, Comparable<?> itemID) throws TasteException {
+  private float doEstimatePreference(long userID, long itemID) throws TasteException {
     double count = 0.0;
     double totalPreference = 0.0;
     PreferenceArray prefs = getDataModel().getPreferencesFromUser(userID);
@@ -166,7 +163,7 @@
   }
 
   @Override
-  public void setPreference(Comparable<?> userID, Comparable<?> itemID, float value) throws TasteException {
+  public void setPreference(long userID, long itemID, float value) throws TasteException {
     DataModel dataModel = getDataModel();
     float prefDelta;
     try {
@@ -180,7 +177,7 @@
   }
 
   @Override
-  public void removePreference(Comparable<?> userID, Comparable<?> itemID) throws TasteException {
+  public void removePreference(long userID, long itemID) throws TasteException {
     DataModel dataModel = getDataModel();
     Float oldPref = dataModel.getPreferenceValue(userID, itemID);
     super.removePreference(userID, itemID);
@@ -201,16 +198,16 @@
         ", diffStorage:" + diffStorage + ']';
   }
 
-  private final class Estimator implements TopItems.Estimator<Comparable<?>> {
+  private final class Estimator implements TopItems.Estimator<Long> {
 
-    private final Comparable<?> userID;
+    private final long userID;
 
-    private Estimator(Comparable<?> userID) {
+    private Estimator(long userID) {
       this.userID = userID;
     }
 
     @Override
-    public double estimate(Comparable<?> itemID) throws TasteException {
+    public double estimate(Long itemID) throws TasteException {
       return doEstimatePreference(userID, itemID);
     }
   }

Modified: lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/slopeone/jdbc/AbstractJDBCDiffStorage.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/slopeone/jdbc/AbstractJDBCDiffStorage.java?rev=803081&r1=803080&r2=803081&view=diff
==============================================================================
--- lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/slopeone/jdbc/AbstractJDBCDiffStorage.java (original)
+++ lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/slopeone/jdbc/AbstractJDBCDiffStorage.java Tue Aug 11 12:04:35 2009
@@ -19,7 +19,7 @@
 
 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.FastIDSet;
 import org.apache.mahout.cf.taste.impl.common.IOUtils;
 import org.apache.mahout.cf.taste.impl.common.RefreshHelper;
 import org.apache.mahout.cf.taste.impl.common.RunningAverage;
@@ -37,7 +37,6 @@
 import java.sql.SQLException;
 import java.sql.Statement;
 import java.util.Collection;
-import java.util.Set;
 import java.util.concurrent.Callable;
 
 /**
@@ -123,7 +122,7 @@
   }
 
   @Override
-  public RunningAverage getDiff(Comparable<?> itemID1, Comparable<?> itemID2) throws TasteException {
+  public RunningAverage getDiff(long itemID1, long itemID2) throws TasteException {
     Connection conn = null;
     PreparedStatement stmt = null;
     ResultSet rs = null;
@@ -132,10 +131,10 @@
       stmt = conn.prepareStatement(getDiffSQL, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
       stmt.setFetchDirection(ResultSet.FETCH_FORWARD);
       stmt.setFetchSize(getFetchSize());
-      stmt.setObject(1, itemID1);
-      stmt.setObject(2, itemID2);
-      stmt.setObject(3, itemID2);
-      stmt.setObject(4, itemID1);
+      stmt.setLong(1, itemID1);
+      stmt.setLong(2, itemID2);
+      stmt.setLong(3, itemID2);
+      stmt.setLong(4, itemID1);
       log.debug("Executing SQL query: {}", getDiffSQL);
       rs = stmt.executeQuery();
       return rs.next() ? new FixedRunningAverage(rs.getInt(1), rs.getDouble(2)) : null;
@@ -148,7 +147,7 @@
   }
 
   @Override
-  public RunningAverage[] getDiffs(Comparable<?> userID, Comparable<?> itemID, PreferenceArray prefs)
+  public RunningAverage[] getDiffs(long userID, long itemID, PreferenceArray prefs)
       throws TasteException {
     int size = prefs.length();
     RunningAverage[] result = new RunningAverage[size];
@@ -160,8 +159,8 @@
       stmt = conn.prepareStatement(getDiffsSQL, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
       stmt.setFetchDirection(ResultSet.FETCH_FORWARD);
       stmt.setFetchSize(getFetchSize());
-      stmt.setObject(1, itemID);
-      stmt.setObject(2, userID);
+      stmt.setLong(1, itemID);
+      stmt.setLong(2, userID);
       log.debug("Executing SQL query: {}", getDiffsSQL);
       rs = stmt.executeQuery();
       // We should have up to one result for each Preference in prefs
@@ -169,8 +168,8 @@
       // with nulls for Preferences that have no corresponding result row
       int i = 0;
       while (rs.next()) {
-        Comparable<?> nextResultItemID = (Comparable<?>) rs.getObject(3);
-        while (!prefs.getItemID(i).equals(nextResultItemID)) {
+        long nextResultItemID = rs.getLong(3);
+        while (prefs.getItemID(i) != nextResultItemID) {
           i++;
           // result[i] is null for these values of i
         }
@@ -187,7 +186,7 @@
   }
 
   @Override
-  public RunningAverage getAverageItemPref(Comparable<?> itemID) throws TasteException {
+  public RunningAverage getAverageItemPref(long itemID) throws TasteException {
     Connection conn = null;
     PreparedStatement stmt = null;
     ResultSet rs = null;
@@ -196,7 +195,7 @@
       stmt = conn.prepareStatement(getAverageItemPrefSQL, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
       stmt.setFetchDirection(ResultSet.FETCH_FORWARD);
       stmt.setFetchSize(getFetchSize());
-      stmt.setObject(1, itemID);
+      stmt.setLong(1, itemID);
       log.debug("Executing SQL query: {}", getAverageItemPrefSQL);
       rs = stmt.executeQuery();
       if (rs.next()) {
@@ -215,7 +214,7 @@
   }
 
   @Override
-  public void updateItemPref(Comparable<?> itemID, float prefDelta, boolean remove)
+  public void updateItemPref(long itemID, float prefDelta, boolean remove)
       throws TasteException {
     Connection conn = null;
     try {
@@ -235,12 +234,12 @@
     }
   }
 
-  private static void doPartialUpdate(String sql, Comparable<?> itemID, double prefDelta, Connection conn)
+  private static void doPartialUpdate(String sql, long itemID, double prefDelta, Connection conn)
       throws SQLException {
     PreparedStatement stmt = conn.prepareStatement(sql);
     try {
       stmt.setDouble(1, prefDelta);
-      stmt.setObject(2, itemID);
+      stmt.setLong(2, itemID);
       log.debug("Executing SQL update: {}", sql);
       stmt.executeUpdate();
     } finally {
@@ -249,7 +248,7 @@
   }
 
   @Override
-  public Set<Comparable<?>> getRecommendableItemIDs(Comparable<?> userID) throws TasteException {
+  public FastIDSet getRecommendableItemIDs(long userID) throws TasteException {
     Connection conn = null;
     PreparedStatement stmt = null;
     ResultSet rs = null;
@@ -258,14 +257,14 @@
       stmt = conn.prepareStatement(getRecommendableItemsSQL, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
       stmt.setFetchDirection(ResultSet.FETCH_FORWARD);
       stmt.setFetchSize(getFetchSize());
-      stmt.setObject(1, userID);
-      stmt.setObject(2, userID);
-      stmt.setObject(3, userID);
+      stmt.setLong(1, userID);
+      stmt.setLong(2, userID);
+      stmt.setLong(3, userID);
       log.debug("Executing SQL query: {}", getRecommendableItemsSQL);
       rs = stmt.executeQuery();
-      Set<Comparable<?>> itemIDs = new FastSet<Comparable<?>>();
+      FastIDSet itemIDs = new FastIDSet();
       while (rs.next()) {
-        itemIDs.add((Comparable<?>) rs.getObject(1));
+        itemIDs.add(rs.getLong(1));
       }
       return itemIDs;
     } catch (SQLException sqle) {

Modified: lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/slopeone/jdbc/MySQLJDBCDiffStorage.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/slopeone/jdbc/MySQLJDBCDiffStorage.java?rev=803081&r1=803080&r2=803081&view=diff
==============================================================================
--- lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/slopeone/jdbc/MySQLJDBCDiffStorage.java (original)
+++ lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/slopeone/jdbc/MySQLJDBCDiffStorage.java Tue Aug 11 12:04:35 2009
@@ -30,16 +30,16 @@
  * <tr><td>123</td><td>234</td><td>0.5</td><td>5</td></tr> <tr><td>123</td><td>789</td><td>-1.33</td><td>3</td></tr>
  * <tr><td>234</td><td>789</td><td>2.1</td><td>1</td></tr> </table>
  *
- * <p><code>item_id_a</code> and <code>item_id_b</code> may have types compatible with Java String, or integer
- * primitive types. <code>average_diff</code> must be compatible with <code>float</code> and
+ * <p><code>item_id_a</code> and <code>item_id_b</code> should have types compatible with the long
+ * primitive type. <code>average_diff</code> must be compatible with <code>float</code> and
  * <code>count</code> must be compatible with <code>int</code>.</p>
  *
  * <p>The following command sets up a suitable table in MySQL:</p>
  *
  * <pre>
  * CREATE TABLE taste_slopeone_diffs (
- *   item_id_a INT NOT NULL,
- *   item_id_b INT NOT NULL,
+ *   item_id_a BIGINT NOT NULL,
+ *   item_id_b BIGINT NOT NULL,
  *   average_diff FLOAT NOT NULL,
  *   count INT NOT NULL,
  *   PRIMARY KEY (item_id_a, item_id_b),

Modified: lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/svd/SVDRecommender.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/svd/SVDRecommender.java?rev=803081&r1=803080&r2=803081&view=diff
==============================================================================
--- lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/svd/SVDRecommender.java (original)
+++ lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/svd/SVDRecommender.java Tue Aug 11 12:04:35 2009
@@ -21,8 +21,10 @@
 import org.apache.mahout.cf.taste.common.NoSuchUserException;
 import org.apache.mahout.cf.taste.common.Refreshable;
 import org.apache.mahout.cf.taste.common.TasteException;
-import org.apache.mahout.cf.taste.impl.common.FastMap;
+import org.apache.mahout.cf.taste.impl.common.FastByIDMap;
+import org.apache.mahout.cf.taste.impl.common.FastIDSet;
 import org.apache.mahout.cf.taste.impl.common.FullRunningAverage;
+import org.apache.mahout.cf.taste.impl.common.LongPrimitiveIterator;
 import org.apache.mahout.cf.taste.impl.common.RandomUtils;
 import org.apache.mahout.cf.taste.impl.common.RefreshHelper;
 import org.apache.mahout.cf.taste.impl.common.RunningAverage;
@@ -40,9 +42,7 @@
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
-import java.util.Map;
 import java.util.Random;
-import java.util.Set;
 import java.util.concurrent.Callable;
 
 /**
@@ -59,8 +59,8 @@
   /** Number of features */
   private final int numFeatures;
 
-  private final Map<Comparable<?>, Integer> userMap;
-  private Map<Comparable<?>, Integer> itemMap;
+  private final FastByIDMap<Integer> userMap;
+  private FastByIDMap<Integer> itemMap;
   private ExpectationMaximizationSVD emSvd;
   private final List<Preference> cachedPreferences;
 
@@ -80,19 +80,21 @@
     this.numFeatures = numFeatures;
 
     int numUsers = dataModel.getNumUsers();
-    userMap = new FastMap<Comparable<?>, Integer>(numUsers);
+    userMap = new FastByIDMap<Integer>(numUsers);
 
     int idx = 0;
-    for (Comparable<?> userID : dataModel.getUserIDs()) {
-      userMap.put(userID, idx++);
+    LongPrimitiveIterator userIterator = dataModel.getUserIDs();
+    while (userIterator.hasNext()) {
+      userMap.put(userIterator.nextLong(), idx++);
     }
 
     int numItems = dataModel.getNumItems();
-    itemMap = new FastMap<Comparable<?>, Integer>(numItems);
+    itemMap = new FastByIDMap<Integer>(numItems);
 
     idx = 0;
-    for (Comparable<?> itemID : dataModel.getItemIDs()) {
-      itemMap.put(itemID, idx++);
+    LongPrimitiveIterator itemIterator = dataModel.getItemIDs();
+    while (itemIterator.hasNext()) {
+      itemMap.put(itemIterator.nextLong(), idx++);
     }
 
     double average = getAveragePreference();
@@ -117,8 +119,9 @@
   private void recachePreferences() throws TasteException {
     cachedPreferences.clear();
     DataModel dataModel = getDataModel();
-    for (Comparable<?> userID : dataModel.getUserIDs()) {
-      for  (Preference pref : dataModel.getPreferencesFromUser(userID)) {
+    LongPrimitiveIterator it = dataModel.getUserIDs();
+    while (it.hasNext()) {
+      for  (Preference pref : dataModel.getPreferencesFromUser(it.nextLong())) {
         cachedPreferences.add(pref);
       }
     }
@@ -127,8 +130,9 @@
   private double getAveragePreference() throws TasteException {
     RunningAverage average = new FullRunningAverage();
     DataModel dataModel = getDataModel();
-    for (Comparable<?> userID : dataModel.getUserIDs()) {
-      for (Preference pref : dataModel.getPreferencesFromUser(userID)) {
+    LongPrimitiveIterator it = dataModel.getUserIDs();
+    while (it.hasNext()) {
+      for (Preference pref : dataModel.getPreferencesFromUser(it.nextLong())) {
         average.addDatum(pref.getValue());
       }
     }
@@ -158,7 +162,7 @@
 
 
   @Override
-  public float estimatePreference(Comparable<?> userID, Comparable<?> itemID) throws TasteException {
+  public float estimatePreference(long userID, long itemID) throws TasteException {
     Integer useridx = userMap.get(userID);
     if (useridx == null) {
       throw new NoSuchUserException();
@@ -171,23 +175,20 @@
   }
 
   @Override
-  public List<RecommendedItem> recommend(Comparable<?> userID, 
+  public List<RecommendedItem> recommend(long userID,
                                          int howMany,
-                                         Rescorer<Comparable<?>> rescorer) throws TasteException {
-    if (userID == null) {
-      throw new IllegalArgumentException("userID is null");
-    }
+                                         Rescorer<Long> rescorer) throws TasteException {
     if (howMany < 1) {
       throw new IllegalArgumentException("howMany must be at least 1");
     }
 
     log.debug("Recommending items for user ID '{}'", userID);
 
-    Set<Comparable<?>> allItemIDs = getAllOtherItems(userID);
+    FastIDSet allItemIDs = getAllOtherItems(userID);
 
-    TopItems.Estimator<Comparable<?>> estimator = new Estimator(userID);
+    TopItems.Estimator<Long> estimator = new Estimator(userID);
 
-    List<RecommendedItem> topItems = TopItems.getTopItems(howMany, allItemIDs, rescorer, estimator);
+    List<RecommendedItem> topItems = TopItems.getTopItems(howMany, allItemIDs.iterator(), rescorer, estimator);
 
     log.debug("Recommendations are: {}", topItems);
     return topItems;
@@ -203,16 +204,16 @@
     return "SVDRecommender[numFeatures:" + numFeatures + ']';
   }
 
-  private final class Estimator implements TopItems.Estimator<Comparable<?>> {
+  private final class Estimator implements TopItems.Estimator<Long> {
 
-    private final Comparable<?> theUserID;
+    private final long theUserID;
 
-    private Estimator(Comparable<?> theUserID) {
+    private Estimator(long theUserID) {
       this.theUserID = theUserID;
     }
 
     @Override
-    public double estimate(Comparable<?> itemID) throws TasteException {
+    public double estimate(Long itemID) throws TasteException {
       return estimatePreference(theUserID, itemID);
     }
   }

Modified: lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/similarity/AbstractSimilarity.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/similarity/AbstractSimilarity.java?rev=803081&r1=803080&r2=803081&view=diff
==============================================================================
--- lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/similarity/AbstractSimilarity.java (original)
+++ lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/similarity/AbstractSimilarity.java Tue Aug 11 12:04:35 2009
@@ -39,7 +39,7 @@
   private final DataModel dataModel;
   private PreferenceInferrer inferrer;
   private PreferenceTransform prefTransform;
-  private SimilarityTransform<Comparable<?>> similarityTransform;
+  private SimilarityTransform similarityTransform;
   private boolean weighted;
   private int cachedNumItems;
   private int cachedNumUsers;
@@ -98,11 +98,11 @@
     this.prefTransform = prefTransform;
   }
 
-  public final SimilarityTransform<Comparable<?>> getSimilarityTransform() {
+  public final SimilarityTransform getSimilarityTransform() {
     return similarityTransform;
   }
 
-  public final void setSimilarityTransform(SimilarityTransform<Comparable<?>> similarityTransform) {
+  public final void setSimilarityTransform(SimilarityTransform similarityTransform) {
     refreshHelper.addDependency(similarityTransform);
     refreshHelper.removeDependency(this.similarityTransform);
     this.similarityTransform = similarityTransform;
@@ -132,12 +132,7 @@
   abstract double computeResult(int n, double sumXY, double sumX2, double sumY2, double sumXYdiff2);
 
   @Override
-  public double userSimilarity(Comparable<?> userID1, Comparable<?> userID2) throws TasteException {
-
-    if (userID1 == null || userID2 == null) {
-      throw new IllegalArgumentException("userID1 or userID2 is null");
-    }
-
+  public double userSimilarity(long userID1, long userID2) throws TasteException {
     PreferenceArray xPrefs = dataModel.getPreferencesFromUser(userID1);
     PreferenceArray yPrefs = dataModel.getPreferencesFromUser(userID2);
     int xLength = xPrefs.length();
@@ -149,8 +144,8 @@
 
     Preference xPref = xPrefs.get(0);
     Preference yPref = yPrefs.get(0);
-    Comparable<?> xIndex = xPref.getItemID();
-    Comparable<?> yIndex = yPref.getItemID();
+    long xIndex = xPref.getItemID();
+    long yIndex = yPref.getItemID();
     int xPrefIndex = 0;
     int yPrefIndex = 0;
 
@@ -166,11 +161,11 @@
     boolean hasPrefTransform = prefTransform != null;
 
     while (true) {
-      int compare = ((Comparable<Object>) xIndex).compareTo(yIndex);
+      int compare = xIndex < yIndex ? -1 : xIndex > yIndex ? 1 : 0;
       if (hasInferrer || compare == 0) {
         double x;
         double y;
-        if (compare == 0) {
+        if (xIndex == yIndex) {
           // Both users expressed a preference for the item
           if (hasPrefTransform) {
             x = prefTransform.getTransformedValue(xPref);
@@ -242,12 +237,7 @@
   }
 
   @Override
-  public final double itemSimilarity(Comparable<?> itemID1, Comparable<?> itemID2) throws TasteException {
-
-    if (itemID1 == null || itemID2 == null) {
-      throw new IllegalArgumentException("item1 or item2 is null");
-    }
-
+  public final double itemSimilarity(long itemID1, long itemID2) throws TasteException {
     PreferenceArray xPrefs = dataModel.getPreferencesForItem(itemID1);
     PreferenceArray yPrefs = dataModel.getPreferencesForItem(itemID2);
     int xLength = xPrefs.length();
@@ -259,8 +249,8 @@
 
     Preference xPref = xPrefs.get(0);
     Preference yPref = yPrefs.get(0);
-    Comparable<?> xIndex = xPref.getUserID();
-    Comparable<?> yIndex = yPref.getUserID();
+    long xIndex = xPref.getUserID();
+    long yIndex = yPref.getUserID();
     int xPrefIndex = 1;
     int yPrefIndex = 1;
 
@@ -275,7 +265,7 @@
     // No, pref inferrers and transforms don't appy here. I think.
 
     while (true) {
-      int compare = ((Comparable<Object>) xIndex).compareTo(yIndex);
+      int compare = xIndex < yIndex ? -1 : xIndex > yIndex ? 1 : 0;
       if (compare == 0) {
         // Both users expressed a preference for the item
         double x = xPref.getValue();

Modified: lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/similarity/AveragingPreferenceInferrer.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/similarity/AveragingPreferenceInferrer.java?rev=803081&r1=803080&r2=803081&view=diff
==============================================================================
--- lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/similarity/AveragingPreferenceInferrer.java (original)
+++ lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/similarity/AveragingPreferenceInferrer.java Tue Aug 11 12:04:35 2009
@@ -39,20 +39,17 @@
   private static final Float ZERO = 0.0f;
 
   private final DataModel dataModel;
-  private final Cache<Comparable<?>, Float> averagePreferenceValue;
+  private final Cache<Long, Float> averagePreferenceValue;
 
   public AveragingPreferenceInferrer(DataModel dataModel) throws TasteException {
     this.dataModel = dataModel;
-    Retriever<Comparable<?>, Float> retriever = new PrefRetriever();
-    averagePreferenceValue = new Cache<Comparable<?>, Float>(retriever, dataModel.getNumUsers());
+    Retriever<Long, Float> retriever = new PrefRetriever();
+    averagePreferenceValue = new Cache<Long, Float>(retriever, dataModel.getNumUsers());
     refresh(null);
   }
 
   @Override
-  public float inferPreference(Comparable<?> userID, Comparable<?> itemID) throws TasteException {
-    if (userID == null || itemID == null) {
-      throw new IllegalArgumentException("userID or item is null");
-    }
+  public float inferPreference(long userID, long itemID) throws TasteException {
     return averagePreferenceValue.get(userID);
   }
 
@@ -61,10 +58,10 @@
     averagePreferenceValue.clear();
   }
 
-  private final class PrefRetriever implements Retriever<Comparable<?>, Float> {
+  private final class PrefRetriever implements Retriever<Long, Float> {
 
     @Override
-    public Float get(Comparable<?> key) throws TasteException {
+    public Float get(Long key) throws TasteException {
       RunningAverage average = new FullRunningAverage();
       PreferenceArray prefs = dataModel.getPreferencesFromUser(key);
       int size = prefs.length();

Modified: lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/similarity/CachingItemSimilarity.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/similarity/CachingItemSimilarity.java?rev=803081&r1=803080&r2=803081&view=diff
==============================================================================
--- lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/similarity/CachingItemSimilarity.java (original)
+++ lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/similarity/CachingItemSimilarity.java Tue Aug 11 12:04:35 2009
@@ -20,7 +20,7 @@
 import org.apache.mahout.cf.taste.common.Refreshable;
 import org.apache.mahout.cf.taste.common.TasteException;
 import org.apache.mahout.cf.taste.impl.common.Cache;
-import org.apache.mahout.cf.taste.impl.common.Pair;
+import org.apache.mahout.cf.taste.impl.common.LongPair;
 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;
@@ -32,7 +32,7 @@
 public final class CachingItemSimilarity implements ItemSimilarity {
 
   private final ItemSimilarity similarity;
-  private final Cache<Pair<Comparable<?>, Comparable<?>>, Double> similarityCache;
+  private final Cache<LongPair, Double> similarityCache;
 
   public CachingItemSimilarity(ItemSimilarity similarity, DataModel dataModel) throws TasteException {
     if (similarity == null) {
@@ -40,15 +40,12 @@
     }
     this.similarity = similarity;
     int maxCacheSize = dataModel.getNumItems(); // just a dumb heuristic for sizing
-    this.similarityCache =
-            new Cache<Pair<Comparable<?>, Comparable<?>>, Double>(new SimilarityRetriever(similarity), maxCacheSize);
+    this.similarityCache = new Cache<LongPair, Double>(new SimilarityRetriever(similarity), maxCacheSize);
   }
 
   @Override
-  public double itemSimilarity(Comparable<?> itemID1, Comparable<?> itemID2) throws TasteException {
-    Pair<Comparable<?>, Comparable<?>> key = ((Comparable<Object>) itemID1).compareTo(itemID2) < 0 ?
-        new Pair<Comparable<?>, Comparable<?>>(itemID1, itemID2) :
-        new Pair<Comparable<?>, Comparable<?>>(itemID2, itemID1);
+  public double itemSimilarity(long itemID1, long itemID2) throws TasteException {
+    LongPair key = itemID1 < itemID2 ? new LongPair(itemID1, itemID2) : new LongPair(itemID2, itemID1);
     return similarityCache.get(key);
   }
 
@@ -59,7 +56,7 @@
     RefreshHelper.maybeRefresh(alreadyRefreshed, similarity);
   }
 
-  private static final class SimilarityRetriever implements Retriever<Pair<Comparable<?>, Comparable<?>>, Double> {
+  private static final class SimilarityRetriever implements Retriever<LongPair, Double> {
     private final ItemSimilarity similarity;
 
     private SimilarityRetriever(ItemSimilarity similarity) {
@@ -67,7 +64,7 @@
     }
 
     @Override
-    public Double get(Pair<Comparable<?>, Comparable<?>> key) throws TasteException {
+    public Double get(LongPair key) throws TasteException {
       return similarity.itemSimilarity(key.getFirst(), key.getSecond());
     }
   }

Modified: lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/similarity/CachingUserSimilarity.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/similarity/CachingUserSimilarity.java?rev=803081&r1=803080&r2=803081&view=diff
==============================================================================
--- lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/similarity/CachingUserSimilarity.java (original)
+++ lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/similarity/CachingUserSimilarity.java Tue Aug 11 12:04:35 2009
@@ -20,7 +20,7 @@
 import org.apache.mahout.cf.taste.common.Refreshable;
 import org.apache.mahout.cf.taste.common.TasteException;
 import org.apache.mahout.cf.taste.impl.common.Cache;
-import org.apache.mahout.cf.taste.impl.common.Pair;
+import org.apache.mahout.cf.taste.impl.common.LongPair;
 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;
@@ -33,7 +33,7 @@
 public final class CachingUserSimilarity implements UserSimilarity {
 
   private final UserSimilarity similarity;
-  private final Cache<Pair<Comparable<?>, Comparable<?>>, Double> similarityCache;
+  private final Cache<LongPair, Double> similarityCache;
 
   public CachingUserSimilarity(UserSimilarity similarity, DataModel dataModel) throws TasteException {
     if (similarity == null) {
@@ -41,14 +41,12 @@
     }
     this.similarity = similarity;
     int maxCacheSize = dataModel.getNumUsers(); // just a dumb heuristic for sizing    
-    this.similarityCache = new Cache<Pair<Comparable<?>, Comparable<?>>, Double>(new SimilarityRetriever(similarity), maxCacheSize);
+    this.similarityCache = new Cache<LongPair, Double>(new SimilarityRetriever(similarity), maxCacheSize);
   }
 
   @Override
-  public double userSimilarity(Comparable<?> userID1, Comparable<?> userID2) throws TasteException {
-    Pair<Comparable<?>, Comparable<?>> key = ((Comparable<Object>) userID1).compareTo(userID2) < 0 ?
-        new Pair<Comparable<?>, Comparable<?>>(userID1, userID2) :
-        new Pair<Comparable<?>, Comparable<?>>(userID2, userID1);
+  public double userSimilarity(long userID1, long userID2) throws TasteException {
+    LongPair key = userID1 < userID2 ? new LongPair(userID1, userID2) : new LongPair(userID2, userID1);
     return similarityCache.get(key);
   }
 
@@ -65,7 +63,7 @@
     RefreshHelper.maybeRefresh(alreadyRefreshed, similarity);
   }
 
-  private static final class SimilarityRetriever implements Retriever<Pair<Comparable<?>, Comparable<?>>, Double> {
+  private static final class SimilarityRetriever implements Retriever<LongPair, Double> {
     private final UserSimilarity similarity;
 
     private SimilarityRetriever(UserSimilarity similarity) {
@@ -73,7 +71,7 @@
     }
 
     @Override
-    public Double get(Pair<Comparable<?>, Comparable<?>> key) throws TasteException {
+    public Double get(LongPair key) throws TasteException {
       return similarity.userSimilarity(key.getFirst(), key.getSecond());
     }
   }

Modified: lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/similarity/GenericItemSimilarity.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/similarity/GenericItemSimilarity.java?rev=803081&r1=803080&r2=803081&view=diff
==============================================================================
--- lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/similarity/GenericItemSimilarity.java (original)
+++ lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/similarity/GenericItemSimilarity.java Tue Aug 11 12:04:35 2009
@@ -19,7 +19,7 @@
 
 import org.apache.mahout.cf.taste.common.Refreshable;
 import org.apache.mahout.cf.taste.common.TasteException;
-import org.apache.mahout.cf.taste.impl.common.FastMap;
+import org.apache.mahout.cf.taste.impl.common.FastByIDMap;
 import org.apache.mahout.cf.taste.impl.common.IteratorIterable;
 import org.apache.mahout.cf.taste.impl.common.IteratorUtils;
 import org.apache.mahout.cf.taste.impl.common.RandomUtils;
@@ -30,7 +30,6 @@
 import java.util.Collection;
 import java.util.Iterator;
 import java.util.List;
-import java.util.Map;
 import java.util.NoSuchElementException;
 
 /**
@@ -45,8 +44,7 @@
  */
 public final class GenericItemSimilarity implements ItemSimilarity {
 
-  private final Map<Comparable<?>, Map<Comparable<?>, Double>> similarityMaps =
-          new FastMap<Comparable<?>, Map<Comparable<?>, Double>>();
+  private final FastByIDMap<FastByIDMap<Double>> similarityMaps = new FastByIDMap<FastByIDMap<Double>>();
 
   /**
    * <p>Creates a {@link GenericItemSimilarity} from a precomputed list of {@link ItemItemSimilarity}s. Each represents
@@ -91,7 +89,7 @@
    * @throws TasteException if an error occurs while accessing the {@link DataModel} items
    */
   public GenericItemSimilarity(ItemSimilarity otherSimilarity, DataModel dataModel) throws TasteException {
-    List<Comparable<?>> itemIDs = IteratorUtils.iterableToList(dataModel.getItemIDs());
+    long[] itemIDs = IteratorUtils.longIteratorToList(dataModel.getItemIDs());
     Iterator<ItemItemSimilarity> it = new DataModelSimilaritiesIterator(otherSimilarity, itemIDs);
     initSimilarityMaps(new IteratorIterable<ItemItemSimilarity>(it));
   }
@@ -110,7 +108,7 @@
    */
   public GenericItemSimilarity(ItemSimilarity otherSimilarity, DataModel dataModel, int maxToKeep)
       throws TasteException {
-    List<Comparable<?>> itemIDs = IteratorUtils.iterableToList(dataModel.getItemIDs());
+    long[] itemIDs = IteratorUtils.longIteratorToList(dataModel.getItemIDs());
     Iterator<ItemItemSimilarity> it = new DataModelSimilaritiesIterator(otherSimilarity, itemIDs);
     Iterable<ItemItemSimilarity> keptSimilarities =
         TopItems.getTopItemItemSimilarities(maxToKeep, new IteratorIterable<ItemItemSimilarity>(it));
@@ -119,23 +117,22 @@
 
   private void initSimilarityMaps(Iterable<ItemItemSimilarity> similarities) {
     for (ItemItemSimilarity iic : similarities) {
-      Comparable<?> similarityItemID1 = iic.getItemID1();
-      Comparable<?> similarityItemID2 = iic.getItemID2();
-      int compare = ((Comparable<Object>) similarityItemID1).compareTo(similarityItemID2);
-      if (compare != 0) {
+      long similarityItemID1 = iic.getItemID1();
+      long similarityItemID2 = iic.getItemID2();
+      if (similarityItemID1 != similarityItemID2) {
         // Order them -- first key should be the "smaller" one
-        Comparable<?> itemID1;
-        Comparable<?> itemID2;
-        if (compare < 0) {
+        long itemID1;
+        long itemID2;
+        if (similarityItemID1 < similarityItemID2) {
           itemID1 = similarityItemID1;
           itemID2 = similarityItemID2;
         } else {
           itemID1 = similarityItemID2;
           itemID2 = similarityItemID1;
         }
-        Map<Comparable<?>, Double> map = similarityMaps.get(itemID1);
+        FastByIDMap<Double> map = similarityMaps.get(itemID1);
         if (map == null) {
-          map = new FastMap<Comparable<?>, Double>();
+          map = new FastByIDMap<Double>();
           similarityMaps.put(itemID1, map);
         }
         map.put(itemID2, iic.getValue());
@@ -154,21 +151,20 @@
    * @return similarity between the two
    */
   @Override
-  public double itemSimilarity(Comparable<?> itemID1, Comparable<?> itemID2) {
-    int compare = ((Comparable<Object>) itemID1).compareTo(itemID2);
-    if (compare == 0) {
+  public double itemSimilarity(long itemID1, long itemID2) {
+    if (itemID1 == itemID2) {
       return 1.0;
     }
-    Comparable<?> firstID;
-    Comparable<?> secondID;
-    if (compare < 0) {
+    long firstID;
+    long secondID;
+    if (itemID1 < itemID2) {
       firstID = itemID1;
       secondID = itemID2;
     } else {
       firstID = itemID2;
       secondID = itemID1;
     }
-    Map<Comparable<?>, Double> nextMap = similarityMaps.get(firstID);
+    FastByIDMap<Double> nextMap = similarityMaps.get(firstID);
     if (nextMap == null) {
       return Double.NaN;
     }
@@ -184,8 +180,8 @@
   /** Encapsulates a similarity between two items. Similarity must be in the range [-1.0,1.0]. */
   public static final class ItemItemSimilarity implements Comparable<ItemItemSimilarity> {
 
-    private final Comparable<?> itemID1;
-    private final Comparable<?> itemID2;
+    private final long itemID1;
+    private final long itemID2;
     private final double value;
 
     /**
@@ -194,10 +190,7 @@
      * @param value similarity between the two
      * @throws IllegalArgumentException if value is NaN, less than -1.0 or greater than 1.0
      */
-    public ItemItemSimilarity(Comparable<?> itemID1, Comparable<?> itemID2, double value) {
-      if (itemID1 == null || itemID2 == null) {
-        throw new IllegalArgumentException("An item is null");
-      }
+    public ItemItemSimilarity(long itemID1, long itemID2, double value) {
       if (Double.isNaN(value) || value < -1.0 || value > 1.0) {
         throw new IllegalArgumentException("Illegal value: " + value);
       }
@@ -206,11 +199,11 @@
       this.value = value;
     }
 
-    public Comparable<?> getItemID1() {
+    public long getItemID1() {
       return itemID1;
     }
 
-    public Comparable<?> getItemID2() {
+    public long getItemID2() {
       return itemID2;
     }
 
@@ -236,12 +229,14 @@
         return false;
       }
       ItemItemSimilarity otherSimilarity = (ItemItemSimilarity) other;
-      return otherSimilarity.itemID1.equals(itemID1) && otherSimilarity.itemID2.equals(itemID2) && otherSimilarity.value == value;
+      return otherSimilarity.itemID1 == itemID1 &&
+             otherSimilarity.itemID2 == itemID2 &&
+             otherSimilarity.value == value;
     }
 
     @Override
     public int hashCode() {
-      return itemID1.hashCode() ^ itemID2.hashCode() ^ RandomUtils.hashDouble(value);
+      return (int) itemID1 ^ (int) itemID2 ^ RandomUtils.hashDouble(value);
     }
 
   }
@@ -249,18 +244,18 @@
   private static final class DataModelSimilaritiesIterator implements Iterator<ItemItemSimilarity> {
 
     private final ItemSimilarity otherSimilarity;
-    private final List<Comparable<?>> itemIDs;
+    private final long[] itemIDs;
     private final int size;
     private int i;
-    private Comparable<?> itemID1;
+    private long itemID1;
     private int j;
 
-    private DataModelSimilaritiesIterator(ItemSimilarity otherSimilarity, List<Comparable<?>> itemIDs) {
+    private DataModelSimilaritiesIterator(ItemSimilarity otherSimilarity, long[] itemIDs) {
       this.otherSimilarity = otherSimilarity;
       this.itemIDs = itemIDs;
-      this.size = itemIDs.size();
+      this.size = itemIDs.length;
       i = 0;
-      itemID1 = itemIDs.get(0);
+      itemID1 = itemIDs[0];
       j = 1;
     }
 
@@ -274,7 +269,7 @@
       if (!hasNext()) {
         throw new NoSuchElementException();
       }
-      Comparable<?> itemID2 = itemIDs.get(j);
+      long itemID2 = itemIDs[j];
       double similarity;
       try {
         similarity = otherSimilarity.itemSimilarity(itemID1, itemID2);
@@ -286,7 +281,7 @@
       j++;
       if (j == size) {
         i++;
-        itemID1 = itemIDs.get(i);
+        itemID1 = itemIDs[i];
         j = i + 1;
       }
       return result;