Author: srowen
Date: Tue Nov 22 06:48:38 2011
New Revision: 1204829

URL: http://svn.apache.org/viewvc?rev=1204829&view=rev
Log:
MAHOUT-891 add load statistics like average iteration time

Added:
    
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/eval/LoadCallable.java
    
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/eval/LoadStatistics.java
    
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/eval/StatsCallable.java
Modified:
    
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/eval/AbstractDifferenceRecommenderEvaluator.java
    
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/eval/LoadEvaluator.java
    
mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/eval/LoadEvaluationRunner.java
    
mahout/trunk/examples/src/main/java/org/apache/mahout/cf/taste/example/kddcup/track1/Track1RecommenderEvaluator.java

Modified: 
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/eval/AbstractDifferenceRecommenderEvaluator.java
URL: 
http://svn.apache.org/viewvc/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/eval/AbstractDifferenceRecommenderEvaluator.java?rev=1204829&r1=1204828&r2=1204829&view=diff
==============================================================================
--- 
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/eval/AbstractDifferenceRecommenderEvaluator.java
 (original)
+++ 
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/eval/AbstractDifferenceRecommenderEvaluator.java
 Tue Nov 22 06:48:38 2011
@@ -158,7 +158,7 @@ public abstract class AbstractDifference
       }
     }
   }
-  
+
   private float capEstimatedPreference(float estimate) {
     if (estimate > maxPreference) {
       return maxPreference;
@@ -168,7 +168,7 @@ public abstract class AbstractDifference
     }
     return estimate;
   }
-  
+
   private double getEvaluation(FastByIDMap<PreferenceArray> testUserPrefs, 
Recommender recommender)
     throws TasteException {
     reset();
@@ -179,14 +179,16 @@ public abstract class AbstractDifference
           new PreferenceEstimateCallable(recommender, entry.getKey(), 
entry.getValue(), noEstimateCounter));
     }
     log.info("Beginning evaluation of {} users", estimateCallables.size());
-    execute(estimateCallables, noEstimateCounter);
+    RunningAverageAndStdDev timing = new FullRunningAverageAndStdDev();
+    execute(estimateCallables, noEstimateCounter, timing);
     return computeFinalEvaluation();
   }
   
-  protected static void execute(Collection<Callable<Void>> callables, 
AtomicInteger noEstimateCounter)
-    throws TasteException {
+  protected static void execute(Collection<Callable<Void>> callables,
+                                AtomicInteger noEstimateCounter,
+                                RunningAverageAndStdDev timing) throws 
TasteException {
 
-    callables = wrapWithStatsCallables(callables, noEstimateCounter);
+    callables = wrapWithStatsCallables(callables, noEstimateCounter, timing);
     int numProcessors = Runtime.getRuntime().availableProcessors();
     ExecutorService executor = Executors.newFixedThreadPool(numProcessors);
     log.info("Starting timing of {} tasks in {} threads", callables.size(), 
numProcessors);
@@ -204,13 +206,13 @@ public abstract class AbstractDifference
     executor.shutdown();
   }
   
-  private static Collection<Callable<Void>> 
wrapWithStatsCallables(Collection<Callable<Void>> callables,
-                                                                   
AtomicInteger noEstimateCounter) {
+  private static Collection<Callable<Void>> 
wrapWithStatsCallables(Iterable<Callable<Void>> callables,
+                                                                   
AtomicInteger noEstimateCounter,
+                                                                   
RunningAverageAndStdDev timing) {
     Collection<Callable<Void>> wrapped = Lists.newArrayList();
     int count = 0;
-    RunningAverageAndStdDev timing = new FullRunningAverageAndStdDev();
     for (Callable<Void> callable : callables) {
-      boolean logStats = count++ % 1000 == 0; // log every 100 or so iterations
+      boolean logStats = count++ % 1000 == 0; // log every 1000 or so 
iterations
       wrapped.add(new StatsCallable(callable, logStats, timing, 
noEstimateCounter));
     }
     return wrapped;
@@ -221,14 +223,14 @@ public abstract class AbstractDifference
   protected abstract void processOneEstimate(float estimatedPreference, 
Preference realPref);
   
   protected abstract double computeFinalEvaluation();
-  
+
   public final class PreferenceEstimateCallable implements Callable<Void> {
-    
+
     private final Recommender recommender;
     private final long testUserID;
     private final PreferenceArray prefs;
     private final AtomicInteger noEstimateCounter;
-    
+
     public PreferenceEstimateCallable(Recommender recommender,
                                       long testUserID,
                                       PreferenceArray prefs,
@@ -238,7 +240,7 @@ public abstract class AbstractDifference
       this.prefs = prefs;
       this.noEstimateCounter = noEstimateCounter;
     }
-    
+
     @Override
     public Void call() throws TasteException {
       for (Preference realPref : prefs) {
@@ -261,43 +263,7 @@ public abstract class AbstractDifference
       }
       return null;
     }
-    
-  }
-  
-  private static final class StatsCallable implements Callable<Void> {
-    
-    private final Callable<Void> delegate;
-    private final boolean logStats;
-    private final RunningAverageAndStdDev timing;
-    private final AtomicInteger noEstimateCounter;
-    
-    private StatsCallable(Callable<Void> delegate,
-                          boolean logStats,
-                          RunningAverageAndStdDev timing,
-                          AtomicInteger noEstimateCounter) {
-      this.delegate = delegate;
-      this.logStats = logStats;
-      this.timing = timing;
-      this.noEstimateCounter = noEstimateCounter;
-    }
-    
-    @Override
-    public Void call() throws Exception {
-      long start = System.currentTimeMillis();
-      delegate.call();
-      long end = System.currentTimeMillis();
-      timing.addDatum(end - start);
-      if (logStats) {
-        Runtime runtime = Runtime.getRuntime();
-        int average = (int) timing.getAverage();
-        log.info("Average time per recommendation: {}ms", average);
-        long totalMemory = runtime.totalMemory();
-        long memory = totalMemory - runtime.freeMemory();
-        log.info("Approximate memory used: {}MB / {}MB", memory / 1000000L, 
totalMemory / 1000000L);
-        log.info("Unable to recommend in {} cases", noEstimateCounter.get());
-      }
-      return null;
-    }
+
   }
-  
+
 }

Added: 
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/eval/LoadCallable.java
URL: 
http://svn.apache.org/viewvc/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/eval/LoadCallable.java?rev=1204829&view=auto
==============================================================================
--- 
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/eval/LoadCallable.java
 (added)
+++ 
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/eval/LoadCallable.java
 Tue Nov 22 06:48:38 2011
@@ -0,0 +1,40 @@
+/*
+ * 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.impl.eval;
+
+import org.apache.mahout.cf.taste.recommender.Recommender;
+
+import java.util.concurrent.Callable;
+
+final class LoadCallable implements Callable<Void> {
+
+  private final Recommender recommender;
+  private final long userID;
+
+  LoadCallable(Recommender recommender, long userID) {
+    this.recommender = recommender;
+    this.userID = userID;
+  }
+
+  @Override
+  public Void call() throws Exception {
+    recommender.recommend(userID, 10);
+    return null;
+  }
+
+}

Modified: 
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/eval/LoadEvaluator.java
URL: 
http://svn.apache.org/viewvc/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/eval/LoadEvaluator.java?rev=1204829&r1=1204828&r2=1204829&view=diff
==============================================================================
--- 
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/eval/LoadEvaluator.java
 (original)
+++ 
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/eval/LoadEvaluator.java
 Tue Nov 22 06:48:38 2011
@@ -23,7 +23,9 @@ import java.util.concurrent.atomic.Atomi
 
 import com.google.common.collect.Lists;
 import org.apache.mahout.cf.taste.common.TasteException;
+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.RunningAverageAndStdDev;
 import org.apache.mahout.cf.taste.impl.common.SamplingLongPrimitiveIterator;
 import org.apache.mahout.cf.taste.model.DataModel;
 import org.apache.mahout.cf.taste.recommender.Recommender;
@@ -34,36 +36,26 @@ import org.apache.mahout.cf.taste.recomm
 public final class LoadEvaluator {
   
   private LoadEvaluator() { }
+
+  public static LoadStatistics runLoad(Recommender recommender) throws 
TasteException {
+    return runLoad(recommender, 10);
+  }
   
-  public static void runLoad(Recommender recommender) throws TasteException {
+  public static LoadStatistics runLoad(Recommender recommender, int howMany) 
throws TasteException {
     DataModel dataModel = recommender.getDataModel();
     int numUsers = dataModel.getNumUsers();
     double sampleRate = 1000.0 / numUsers;
-    LongPrimitiveIterator userSampler = 
SamplingLongPrimitiveIterator.maybeWrapIterator(dataModel
-        .getUserIDs(), sampleRate);
-    recommender.recommend(userSampler.next(), 10); // Warm up
+    LongPrimitiveIterator userSampler =
+        
SamplingLongPrimitiveIterator.maybeWrapIterator(dataModel.getUserIDs(), 
sampleRate);
+    recommender.recommend(userSampler.next(), howMany); // Warm up
     Collection<Callable<Void>> callables = Lists.newArrayList();
     while (userSampler.hasNext()) {
       callables.add(new LoadCallable(recommender, userSampler.next()));
     }
-    AbstractDifferenceRecommenderEvaluator.execute(callables, new 
AtomicInteger());
-  }
-  
-  private static final class LoadCallable implements Callable<Void> {
-    
-    private final Recommender recommender;
-    private final long userID;
-    
-    private LoadCallable(Recommender recommender, long userID) {
-      this.recommender = recommender;
-      this.userID = userID;
-    }
-    
-    @Override
-    public Void call() throws Exception {
-      recommender.recommend(userID, 10);
-      return null;
-    }
+    AtomicInteger noEstimateCounter = new AtomicInteger();
+    RunningAverageAndStdDev timing = new FullRunningAverageAndStdDev();
+    AbstractDifferenceRecommenderEvaluator.execute(callables, 
noEstimateCounter, timing);
+    return new LoadStatistics(timing);
   }
-  
+
 }
\ No newline at end of file

Added: 
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/eval/LoadStatistics.java
URL: 
http://svn.apache.org/viewvc/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/eval/LoadStatistics.java?rev=1204829&view=auto
==============================================================================
--- 
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/eval/LoadStatistics.java
 (added)
+++ 
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/eval/LoadStatistics.java
 Tue Nov 22 06:48:38 2011
@@ -0,0 +1,34 @@
+/*
+ * 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.impl.eval;
+
+import org.apache.mahout.cf.taste.impl.common.RunningAverage;
+
+public final class LoadStatistics {
+  
+  private final RunningAverage timing;
+
+  LoadStatistics(RunningAverage timing) {
+    this.timing = timing;
+  }
+
+  public RunningAverage getTiming() {
+    return timing;
+  }
+  
+}

Added: 
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/eval/StatsCallable.java
URL: 
http://svn.apache.org/viewvc/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/eval/StatsCallable.java?rev=1204829&view=auto
==============================================================================
--- 
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/eval/StatsCallable.java
 (added)
+++ 
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/eval/StatsCallable.java
 Tue Nov 22 06:48:38 2011
@@ -0,0 +1,64 @@
+/*
+ * 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.impl.eval;
+
+import org.apache.mahout.cf.taste.impl.common.RunningAverageAndStdDev;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.atomic.AtomicInteger;
+
+final class StatsCallable implements Callable<Void> {
+  
+  private static final Logger log = 
LoggerFactory.getLogger(StatsCallable.class);
+  
+  private final Callable<Void> delegate;
+  private final boolean logStats;
+  private final RunningAverageAndStdDev timing;
+  private final AtomicInteger noEstimateCounter;
+  
+  StatsCallable(Callable<Void> delegate,
+                boolean logStats,
+                RunningAverageAndStdDev timing,
+                AtomicInteger noEstimateCounter) {
+    this.delegate = delegate;
+    this.logStats = logStats;
+    this.timing = timing;
+    this.noEstimateCounter = noEstimateCounter;
+  }
+  
+  @Override
+  public Void call() throws Exception {
+    long start = System.currentTimeMillis();
+    delegate.call();
+    long end = System.currentTimeMillis();
+    timing.addDatum(end - start);
+    if (logStats) {
+      Runtime runtime = Runtime.getRuntime();
+      int average = (int) timing.getAverage();
+      log.info("Average time per recommendation: {}ms", average);
+      long totalMemory = runtime.totalMemory();
+      long memory = totalMemory - runtime.freeMemory();
+      log.info("Approximate memory used: {}MB / {}MB", memory / 1000000L, 
totalMemory / 1000000L);
+      log.info("Unable to recommend in {} cases", noEstimateCounter.get());
+    }
+    return null;
+  }
+
+}

Modified: 
mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/eval/LoadEvaluationRunner.java
URL: 
http://svn.apache.org/viewvc/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/eval/LoadEvaluationRunner.java?rev=1204829&r1=1204828&r2=1204829&view=diff
==============================================================================
--- 
mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/eval/LoadEvaluationRunner.java
 (original)
+++ 
mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/eval/LoadEvaluationRunner.java
 Tue Nov 22 06:48:38 2011
@@ -1,5 +1,21 @@
-package org.apache.mahout.cf.taste.impl.eval;
+/*
+ * 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.impl.eval;
 
 import org.apache.mahout.cf.taste.impl.model.file.FileDataModel;
 import org.apache.mahout.cf.taste.impl.neighborhood.NearestNUserNeighborhood;
@@ -14,26 +30,37 @@ import org.apache.mahout.cf.taste.simila
 
 import java.io.File;
 
-/**
- *
- *
- **/
-public class LoadEvaluationRunner {
+public final class LoadEvaluationRunner {
+
+  private static final int LOOPS = 10;
+
+  private LoadEvaluationRunner() {
+  }
 
   public static void main(String[] args) throws Exception {
+
     DataModel model = new FileDataModel(new File(args[0]));
-    ItemSimilarity similarity = new EuclideanDistanceSimilarity(model);
-    Recommender recommender = new GenericItemBasedRecommender(model, 
similarity);//Use an item-item recommender
+
+    int howMany = 10;
+    if (args.length > 1) {
+      howMany = Integer.parseInt(args[1]);
+    }
+
     System.out.println("Run Items");
-    for (int i = 0; i < 10; i++){
-      LoadEvaluator.runLoad(recommender);
+    ItemSimilarity similarity = new EuclideanDistanceSimilarity(model);
+    Recommender recommender = new GenericItemBasedRecommender(model, 
similarity); // Use an item-item recommender
+    for (int i = 0; i < LOOPS; i++){
+      LoadStatistics loadStats = LoadEvaluator.runLoad(recommender, howMany);
+      System.out.println(loadStats);
     }
+
     System.out.println("Run Users");
     UserSimilarity userSim = new EuclideanDistanceSimilarity(model);
     UserNeighborhood neighborhood = new NearestNUserNeighborhood(10, userSim, 
model);
     recommender = new GenericUserBasedRecommender(model, neighborhood, 
userSim);
-    for (int i = 0; i < 10; i++){
-      LoadEvaluator.runLoad(recommender);
+    for (int i = 0; i < LOOPS; i++){
+      LoadStatistics loadStats = LoadEvaluator.runLoad(recommender, howMany);
+      System.out.println(loadStats);
     }
 
   }

Modified: 
mahout/trunk/examples/src/main/java/org/apache/mahout/cf/taste/example/kddcup/track1/Track1RecommenderEvaluator.java
URL: 
http://svn.apache.org/viewvc/mahout/trunk/examples/src/main/java/org/apache/mahout/cf/taste/example/kddcup/track1/Track1RecommenderEvaluator.java?rev=1204829&r1=1204828&r2=1204829&view=diff
==============================================================================
--- 
mahout/trunk/examples/src/main/java/org/apache/mahout/cf/taste/example/kddcup/track1/Track1RecommenderEvaluator.java
 (original)
+++ 
mahout/trunk/examples/src/main/java/org/apache/mahout/cf/taste/example/kddcup/track1/Track1RecommenderEvaluator.java
 Tue Nov 22 06:48:38 2011
@@ -29,7 +29,9 @@ import org.apache.mahout.cf.taste.eval.R
 import org.apache.mahout.cf.taste.example.kddcup.DataFileIterable;
 import org.apache.mahout.cf.taste.example.kddcup.KDDCupDataModel;
 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.RunningAverage;
+import org.apache.mahout.cf.taste.impl.common.RunningAverageAndStdDev;
 import 
org.apache.mahout.cf.taste.impl.eval.AbstractDifferenceRecommenderEvaluator;
 import org.apache.mahout.cf.taste.model.DataModel;
 import org.apache.mahout.cf.taste.model.Preference;
@@ -77,7 +79,8 @@ public final class Track1RecommenderEval
           new PreferenceEstimateCallable(recommender, userID, validationPrefs, 
noEstimateCounter));
     }
 
-    execute(estimateCallables, noEstimateCounter);
+    RunningAverageAndStdDev timing = new FullRunningAverageAndStdDev();
+    execute(estimateCallables, noEstimateCounter, timing);
 
     double result = computeFinalEvaluation();
     log.info("Evaluation result: {}", result);


Reply via email to