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;