You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mahout.apache.org by ss...@apache.org on 2013/03/07 11:10:00 UTC

svn commit: r1453756 - in /mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste: hadoop/als/ impl/recommender/ recommender/

Author: ssc
Date: Thu Mar  7 10:10:00 2013
New Revision: 1453756

URL: http://svn.apache.org/r1453756
Log:
MAHOUT-1151, a few more fixes

Added:
    mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/hadoop/als/CappableRecommendedItem.java
Modified:
    mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/hadoop/als/ParallelALSFactorizationJob.java
    mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/hadoop/als/RecommenderJob.java
    mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/GenericRecommendedItem.java
    mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/recommender/RecommendedItem.java

Added: mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/hadoop/als/CappableRecommendedItem.java
URL: http://svn.apache.org/viewvc/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/hadoop/als/CappableRecommendedItem.java?rev=1453756&view=auto
==============================================================================
--- mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/hadoop/als/CappableRecommendedItem.java (added)
+++ mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/hadoop/als/CappableRecommendedItem.java Thu Mar  7 10:10:00 2013
@@ -0,0 +1,76 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.mahout.cf.taste.hadoop.als;
+
+import com.google.common.base.Preconditions;
+import org.apache.mahout.cf.taste.recommender.RecommendedItem;
+import org.apache.mahout.common.RandomUtils;
+
+/**
+ * Mutable variant of {@link RecommendedItem} that allows to cap the preference to a max value
+ */
+class CappableRecommendedItem implements RecommendedItem {
+
+  private final long itemID;
+  private float value;
+
+  /**
+   * @throws IllegalArgumentException
+   *           if item is null or value is NaN
+   */
+  public CappableRecommendedItem(long itemID, float value) {
+    Preconditions.checkArgument(!Float.isNaN(value), "value is NaN");
+    this.itemID = itemID;
+    this.value = value;
+  }
+
+  @Override
+  public long getItemID() {
+    return itemID;
+  }
+
+  @Override
+  public float getValue() {
+    return value;
+  }
+
+  public void capToMaxValue(float maxValue) {
+    if (value > maxValue) {
+      value = maxValue;
+    }
+  }
+
+  @Override
+  public String toString() {
+    return "CappableRecommendedItem[item:" + itemID + ", value:" + value + ']';
+  }
+
+  @Override
+  public int hashCode() {
+    return (int) itemID ^ RandomUtils.hashFloat(value);
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof CappableRecommendedItem)) {
+      return false;
+    }
+    RecommendedItem other = (RecommendedItem) o;
+    return itemID == other.getItemID() && value == other.getValue();
+  }
+}

Modified: mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/hadoop/als/ParallelALSFactorizationJob.java
URL: http://svn.apache.org/viewvc/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/hadoop/als/ParallelALSFactorizationJob.java?rev=1453756&r1=1453755&r2=1453756&view=diff
==============================================================================
--- mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/hadoop/als/ParallelALSFactorizationJob.java (original)
+++ mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/hadoop/als/ParallelALSFactorizationJob.java Thu Mar  7 10:10:00 2013
@@ -269,7 +269,7 @@ public class ParallelALSFactorizationJob
         throws IOException, InterruptedException {
       Vector ratings = ratingsWritable.get();
 
-      List<Vector> featureVectors = Lists.newArrayList();
+      List<Vector> featureVectors = Lists.newArrayListWithCapacity(ratings.getNumNondefaultElements());
       Iterator<Vector.Element> interactions = ratings.iterateNonZero();
       while (interactions.hasNext()) {
         int index = interactions.next().index();

Modified: mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/hadoop/als/RecommenderJob.java
URL: http://svn.apache.org/viewvc/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/hadoop/als/RecommenderJob.java?rev=1453756&r1=1453755&r2=1453756&view=diff
==============================================================================
--- mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/hadoop/als/RecommenderJob.java (original)
+++ mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/hadoop/als/RecommenderJob.java Thu Mar  7 10:10:00 2013
@@ -38,10 +38,12 @@ import org.apache.mahout.math.map.OpenIn
 import org.apache.mahout.math.set.OpenIntHashSet;
 
 import java.io.IOException;
+import java.util.Collections;
 import java.util.Comparator;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.PriorityQueue;
 
 /**
  * <p>Computes the top-N recommendations per user from a decomposition of the rating matrix</p>
@@ -97,7 +99,6 @@ public class RecommenderJob extends Abst
       return -1;
     }
 
-
     return 0;
   }
 
@@ -109,6 +110,9 @@ public class RecommenderJob extends Abst
         }
       };
 
+  private static final Comparator<RecommendedItem> DESCENDING_BY_PREFERENCE_VALUE =
+      Collections.reverseOrder(BY_PREFERENCE_VALUE);
+
   static class PredictionMapper
       extends Mapper<IntWritable,VectorWritable,IntWritable,RecommendedItemsWritable> {
 
@@ -118,7 +122,9 @@ public class RecommenderJob extends Abst
     private int recommendationsPerUser;
     private float maxRating;
 
-    private RecommendedItemsWritable result = new RecommendedItemsWritable();
+    private PriorityQueue<RecommendedItem> topKItems;
+
+    private RecommendedItemsWritable recommendations = new RecommendedItemsWritable();
 
     @Override
     protected void setup(Context ctx) throws IOException, InterruptedException {
@@ -132,6 +138,8 @@ public class RecommenderJob extends Abst
       M = ALSUtils.readMatrixByRows(pathToM, ctx.getConfiguration());
 
       maxRating = Float.parseFloat(ctx.getConfiguration().get(MAX_RATING));
+
+      topKItems = new PriorityQueue<RecommendedItem>(recommendationsPerUser + 1, BY_PREFERENCE_VALUE);
     }
 
     @Override
@@ -141,23 +149,27 @@ public class RecommenderJob extends Abst
       Vector ratings = ratingsWritable.get();
       final int userID = userIDWritable.get();
       final OpenIntHashSet alreadyRatedItems = new OpenIntHashSet(ratings.getNumNondefaultElements());
-      final TopK<RecommendedItem> topKItems = new TopK<RecommendedItem>(recommendationsPerUser, BY_PREFERENCE_VALUE);
 
       Iterator<Vector.Element> ratingsIterator = ratings.iterateNonZero();
       while (ratingsIterator.hasNext()) {
         alreadyRatedItems.add(ratingsIterator.next().index());
       }
 
+      topKItems.clear();
+
       M.forEachPair(new IntObjectProcedure<Vector>() {
         @Override
         public boolean apply(int itemID, Vector itemFeatures) {
           if (!alreadyRatedItems.contains(itemID)) {
             double predictedRating = U.get(userID).dot(itemFeatures);
 
-            // manual check to avoid an object instantiation per unknown item
-            if (topKItems.size() < recommendationsPerUser || (float) predictedRating > topKItems.peek().getValue()) {
-              topKItems.offer(new GenericRecommendedItem(itemID, (float) predictedRating));
+            if (topKItems.size() < recommendationsPerUser) {
+              topKItems.add(new CappableRecommendedItem(itemID, (float) predictedRating));
+            } else if (predictedRating > topKItems.peek().getValue()) {
+              topKItems.add(new CappableRecommendedItem(itemID, (float) predictedRating));
+              topKItems.poll();
             }
+
           }
           return true;
         }
@@ -165,13 +177,14 @@ public class RecommenderJob extends Abst
 
       if (!topKItems.isEmpty()) {
 
-        List<RecommendedItem> recommendedItems = topKItems.retrieve();
+        List<RecommendedItem> recommendedItems = Lists.newArrayList(topKItems);
+        Collections.sort(recommendedItems, DESCENDING_BY_PREFERENCE_VALUE);
         for (RecommendedItem topItem : recommendedItems) {
-          topItem.capToMaxValue(maxRating);
+          ((CappableRecommendedItem) topItem).capToMaxValue(maxRating);
         }
 
-        result.set(recommendedItems);
-        ctx.write(userIDWritable, result);
+        recommendations.set(recommendedItems);
+        ctx.write(userIDWritable, recommendations);
       }
     }
   }

Modified: mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/GenericRecommendedItem.java
URL: http://svn.apache.org/viewvc/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/GenericRecommendedItem.java?rev=1453756&r1=1453755&r2=1453756&view=diff
==============================================================================
--- mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/GenericRecommendedItem.java (original)
+++ mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/GenericRecommendedItem.java Thu Mar  7 10:10:00 2013
@@ -32,7 +32,7 @@ import com.google.common.base.Preconditi
 public final class GenericRecommendedItem implements RecommendedItem, Serializable {
   
   private final long itemID;
-  private float value;
+  private final float value;
   
   /**
    * @throws IllegalArgumentException
@@ -55,13 +55,6 @@ public final class GenericRecommendedIte
   }
 
   @Override
-  public void capToMaxValue(float maxValue) {
-    if (value > maxValue) {
-      value = maxValue;
-    }
-  }
-
-  @Override
   public String toString() {
     return "RecommendedItem[item:" + itemID + ", value:" + value + ']';
   }

Modified: mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/recommender/RecommendedItem.java
URL: http://svn.apache.org/viewvc/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/recommender/RecommendedItem.java?rev=1453756&r1=1453755&r2=1453756&view=diff
==============================================================================
--- mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/recommender/RecommendedItem.java (original)
+++ mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/recommender/RecommendedItem.java Thu Mar  7 10:10:00 2013
@@ -38,10 +38,4 @@ public interface RecommendedItem {
    */
   float getValue();
 
-  /**
-   * set a maximum preference value
-   *
-   * @param maxValue
-   */
-  void capToMaxValue(float maxValue);
 }