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 2008/08/09 23:55:05 UTC

svn commit: r684358 [1/2] - in /lucene/mahout/trunk/core/src: main/examples/org/apache/mahout/cf/taste/example/grouplens/ main/java/org/apache/mahout/cf/taste/common/ main/java/org/apache/mahout/cf/taste/impl/common/ main/java/org/apache/mahout/cf/tast...

Author: srowen
Date: Sat Aug  9 14:55:03 2008
New Revision: 684358

URL: http://svn.apache.org/viewvc?rev=684358&view=rev
Log:
Complete reinvention of refresh() mechanism, with cleaner, intelligent dependency management.

Added:
    lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/common/RefreshHelper.java
    lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/common/MockRefreshable.java
    lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/common/RefreshHelperTest.java
Modified:
    lucene/mahout/trunk/core/src/main/examples/org/apache/mahout/cf/taste/example/grouplens/GroupLensRecommender.java
    lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/common/Refreshable.java
    lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/correlation/AbstractCorrelation.java
    lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/correlation/AveragingPreferenceInferrer.java
    lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/correlation/CachingItemCorrelation.java
    lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/correlation/CachingUserCorrelation.java
    lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/correlation/GenericItemCorrelation.java
    lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/correlation/LogLikelihoodCorrelation.java
    lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/correlation/SpearmanCorrelation.java
    lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/correlation/TanimotoCoefficientCorrelation.java
    lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/model/GenericDataModel.java
    lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/model/file/FileDataModel.java
    lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/model/jdbc/AbstractJDBCDataModel.java
    lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/neighborhood/AbstractUserNeighborhood.java
    lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/neighborhood/CachingUserNeighborhood.java
    lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/AbstractRecommender.java
    lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/CachingRecommender.java
    lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/FarthestNeighborClusterSimilarity.java
    lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/GenericItemBasedRecommender.java
    lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/GenericUserBasedRecommender.java
    lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/ItemAverageRecommender.java
    lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/ItemUserAverageRecommender.java
    lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/NearestNeighborClusterSimilarity.java
    lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/TreeClusteringRecommender.java
    lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/TreeClusteringRecommender2.java
    lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/slopeone/MemoryDiffStorage.java
    lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/slopeone/SlopeOneRecommender.java
    lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/slopeone/jdbc/AbstractJDBCDiffStorage.java
    lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/transforms/CaseAmplification.java
    lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/transforms/InverseUserFrequency.java
    lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/transforms/ZScore.java
    lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/LoadTest.java
    lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/correlation/EuclideanDistanceCorrelationTest.java
    lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/correlation/LogLikelihoodCorrelationTest.java
    lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/correlation/PearsonCorrelationTest.java
    lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/correlation/SpearmanCorrelationTest.java
    lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/correlation/TanimotoCoefficientCorrelationTest.java
    lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/model/file/FileDataModelTest.java
    lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/neighborhood/DummyCorrelation.java
    lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/neighborhood/NearestNNeighborhoodTest.java
    lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/neighborhood/ThresholdNeighborhoodTest.java
    lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/recommender/CachingRecommenderTest.java
    lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/recommender/GenericItemBasedRecommenderTest.java
    lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/recommender/GenericUserBasedRecommenderTest.java
    lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/recommender/MockRecommender.java
    lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/recommender/TreeClusteringRecommenderTest.java
    lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/recommender/slopeone/SlopeOneRecommenderTest.java
    lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/transforms/CaseAmplificationTest.java
    lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/transforms/InverseUserFrequencyTest.java
    lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/transforms/ZScoreTest.java

Modified: lucene/mahout/trunk/core/src/main/examples/org/apache/mahout/cf/taste/example/grouplens/GroupLensRecommender.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/examples/org/apache/mahout/cf/taste/example/grouplens/GroupLensRecommender.java?rev=684358&r1=684357&r2=684358&view=diff
==============================================================================
--- lucene/mahout/trunk/core/src/main/examples/org/apache/mahout/cf/taste/example/grouplens/GroupLensRecommender.java (original)
+++ lucene/mahout/trunk/core/src/main/examples/org/apache/mahout/cf/taste/example/grouplens/GroupLensRecommender.java Sat Aug  9 14:55:03 2008
@@ -18,6 +18,7 @@
 package org.apache.mahout.cf.taste.example.grouplens;
 
 import org.apache.mahout.cf.taste.common.TasteException;
+import org.apache.mahout.cf.taste.common.Refreshable;
 import org.apache.mahout.cf.taste.impl.recommender.CachingRecommender;
 import org.apache.mahout.cf.taste.impl.recommender.slopeone.SlopeOneRecommender;
 import org.apache.mahout.cf.taste.model.DataModel;
@@ -28,6 +29,7 @@
 
 import java.io.IOException;
 import java.util.List;
+import java.util.Collection;
 
 /**
  * A simple {@link Recommender} implemented for the GroupLens demo.
@@ -80,8 +82,8 @@
     return recommender.getDataModel();
   }
 
-  public void refresh() {
-    recommender.refresh();
+  public void refresh(Collection<Refreshable> alreadyRefreshed) {
+    recommender.refresh(alreadyRefreshed);
   }
 
   @Override

Modified: lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/common/Refreshable.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/common/Refreshable.java?rev=684358&r1=684357&r2=684358&view=diff
==============================================================================
--- lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/common/Refreshable.java (original)
+++ lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/common/Refreshable.java Sat Aug  9 14:55:03 2008
@@ -17,13 +17,15 @@
 
 package org.apache.mahout.cf.taste.common;
 
+import java.util.Collection;
+
 /**
  * <p>Implementations of this interface have state that can be periodically refreshed. For example, an
  * implementation instance might contain some pre-computed information that should be periodically
- * refreshed. The {@link #refresh()} method triggers such a refresh.</p>
+ * refreshed. The {@link #refresh(Collection)} method triggers such a refresh.</p>
  *
  * <p>All Taste components implement this. In particular, {@link org.apache.mahout.cf.taste.recommender.Recommender}s do.
- * Callers may want to call {@link #refresh()} periodically to re-compute information throughout the system
+ * Callers may want to call {@link #refresh(Collection)} periodically to re-compute information throughout the system
  * and bring it up to date, though this operation may be expensive.</p>
  */
 public interface Refreshable {
@@ -32,7 +34,11 @@
    * <p>Triggers "refresh" -- whatever that means -- of the implementation. The general contract is that
    * any {@link Refreshable} should always leave itself in a consistent, operational state, and that
    * the refresh atomically updates internal state from old to new.</p>
+   *
+   * @param alreadyRefreshed {@link org.apache.mahout.cf.taste.common.Refreshable}s that are known to have already
+   *  been refreshed as a result of an initial call to a {@link #refresh(Collection)} method on some
+   *  object. This ensure that objects in a refresh dependency graph aren't refreshed twice needlessly.
    */
-  void refresh();
+  void refresh(Collection<Refreshable> alreadyRefreshed);
 
 }

Added: lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/common/RefreshHelper.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/common/RefreshHelper.java?rev=684358&view=auto
==============================================================================
--- lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/common/RefreshHelper.java (added)
+++ lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/common/RefreshHelper.java Sat Aug  9 14:55:03 2008
@@ -0,0 +1,86 @@
+/**
+ * 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.common;
+
+import org.apache.mahout.cf.taste.common.Refreshable;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ * A helper class for implementing {@link Refreshable}.
+ */
+public final class RefreshHelper implements Refreshable {
+
+  private static final Logger log = LoggerFactory.getLogger(RefreshHelper.class);
+
+  private final List<Refreshable> dependencies;
+  private final ReentrantLock refreshLock;
+  private final Callable<?> refreshRunnable;
+
+  public RefreshHelper(Callable<?> refreshRunnable) {
+    this.dependencies = new ArrayList<Refreshable>(3);
+    this.refreshLock = new ReentrantLock();
+    this.refreshRunnable = refreshRunnable;
+  }
+
+  public void addDependency(Refreshable refreshable) {
+    if (refreshable != null) {
+      dependencies.add(refreshable);
+    }
+  }
+
+  public void refresh(Collection<Refreshable> alreadyRefreshed) {
+    if (!refreshLock.isLocked()) {
+      refreshLock.lock();
+      try {
+        alreadyRefreshed = buildRefreshed(alreadyRefreshed);
+        for (Refreshable dependency : dependencies) {
+          maybeRefresh(alreadyRefreshed, dependency);
+        }
+        if (refreshRunnable != null) {
+          try {
+            refreshRunnable.call();
+          } catch (Exception e) {
+            log.warn("Unexpected exception while refreshing", e);
+          }
+        }
+      } finally {
+        refreshLock.unlock();
+      }
+    }
+  }
+
+  public static Collection<Refreshable> buildRefreshed(Collection<Refreshable> currentAlreadyRefreshed) {
+    return currentAlreadyRefreshed == null ? new HashSet<Refreshable>(3) : currentAlreadyRefreshed;
+  }
+
+  public static void maybeRefresh(Collection<Refreshable> alreadyRefreshed, Refreshable refreshable) {
+    if (!alreadyRefreshed.contains(refreshable)) {
+      alreadyRefreshed.add(refreshable);
+      refreshable.refresh(alreadyRefreshed);
+    }
+  }
+
+}

Modified: lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/correlation/AbstractCorrelation.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/correlation/AbstractCorrelation.java?rev=684358&r1=684357&r2=684358&view=diff
==============================================================================
--- lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/correlation/AbstractCorrelation.java (original)
+++ lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/correlation/AbstractCorrelation.java Sat Aug  9 14:55:03 2008
@@ -28,9 +28,14 @@
 import org.apache.mahout.cf.taste.transforms.PreferenceTransform;
 import org.apache.mahout.cf.taste.common.TasteException;
 import org.apache.mahout.cf.taste.common.Weighting;
+import org.apache.mahout.cf.taste.common.Refreshable;
+import org.apache.mahout.cf.taste.impl.common.RefreshHelper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.util.Collection;
+import java.util.concurrent.Callable;
+
 /**
  * Abstract superclass encapsulating functionality that is common to most
  * implementations in this package, including the basic correlation algorithm,
@@ -47,6 +52,7 @@
   private boolean weighted;
   private int cachedNumItems;
   private int cachedNumUsers;
+  private final RefreshHelper refreshHelper;
 
   /**
    * <p>Creates a normal (unweighted) {@link AbstractCorrelation}.</p>
@@ -66,6 +72,17 @@
     this.weighted = weighting == Weighting.WEIGHTED;
     this.cachedNumItems = dataModel.getNumItems();
     this.cachedNumUsers = dataModel.getNumUsers();
+    this.refreshHelper = new RefreshHelper(new Callable<Object>() {
+      public Object call() throws Exception {
+        cachedNumItems = AbstractCorrelation.this.dataModel.getNumItems();
+        cachedNumUsers = AbstractCorrelation.this.dataModel.getNumUsers();
+        return null;
+      }
+    });
+    this.refreshHelper.addDependency(this.dataModel);
+    this.refreshHelper.addDependency(this.inferrer);
+    this.refreshHelper.addDependency(this.prefTransform);
+    this.refreshHelper.addDependency(this.correlationTransform);
   }
 
   final DataModel getDataModel() {
@@ -347,24 +364,8 @@
     return result;
   }
 
-  public final void refresh() {
-    dataModel.refresh();
-    try {
-      cachedNumItems = dataModel.getNumItems();
-      cachedNumUsers = dataModel.getNumUsers();
-    } catch (TasteException te) {
-      // hmm, continue?
-      log.warn("Unable to refresh number of users and items", te);
-    }
-    if (inferrer != null) {
-      inferrer.refresh();
-    }
-    if (prefTransform != null) {
-      prefTransform.refresh();
-    }
-    if (correlationTransform != null) {
-      correlationTransform.refresh();
-    }
+  public final void refresh(Collection<Refreshable> alreadyRefreshed) {
+    refreshHelper.refresh(alreadyRefreshed);
   }
 
   @Override

Modified: lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/correlation/AveragingPreferenceInferrer.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/correlation/AveragingPreferenceInferrer.java?rev=684358&r1=684357&r2=684358&view=diff
==============================================================================
--- lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/correlation/AveragingPreferenceInferrer.java (original)
+++ lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/correlation/AveragingPreferenceInferrer.java Sat Aug  9 14:55:03 2008
@@ -18,6 +18,7 @@
 package org.apache.mahout.cf.taste.impl.correlation;
 
 import org.apache.mahout.cf.taste.common.TasteException;
+import org.apache.mahout.cf.taste.common.Refreshable;
 import org.apache.mahout.cf.taste.correlation.PreferenceInferrer;
 import org.apache.mahout.cf.taste.impl.common.FullRunningAverage;
 import org.apache.mahout.cf.taste.impl.common.RunningAverage;
@@ -28,6 +29,8 @@
 import org.apache.mahout.cf.taste.model.Preference;
 import org.apache.mahout.cf.taste.model.User;
 
+import java.util.Collection;
+
 /**
  * <p>Implementations of this interface compute an inferred preference for a {@link User} and an {@link Item}
  * that the user has not expressed any preference for. This might be an average of other preferences scores
@@ -41,7 +44,7 @@
 
   public AveragingPreferenceInferrer(DataModel dataModel) throws TasteException {
     averagePreferenceValue = new Cache<User, Double>(RETRIEVER, dataModel.getNumUsers());
-    refresh();
+    refresh(null);
   }
 
   public double inferPreference(User user, Item item) throws TasteException {
@@ -51,7 +54,7 @@
     return averagePreferenceValue.get(user);
   }
 
-  public void refresh() {
+  public void refresh(Collection<Refreshable> alreadyRefreshed) {
     averagePreferenceValue.clear();
   }
 

Modified: lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/correlation/CachingItemCorrelation.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/correlation/CachingItemCorrelation.java?rev=684358&r1=684357&r2=684358&view=diff
==============================================================================
--- lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/correlation/CachingItemCorrelation.java (original)
+++ lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/correlation/CachingItemCorrelation.java Sat Aug  9 14:55:03 2008
@@ -21,9 +21,13 @@
 import org.apache.mahout.cf.taste.model.Item;
 import org.apache.mahout.cf.taste.model.DataModel;
 import org.apache.mahout.cf.taste.common.TasteException;
+import org.apache.mahout.cf.taste.common.Refreshable;
 import org.apache.mahout.cf.taste.impl.common.Pair;
 import org.apache.mahout.cf.taste.impl.common.Cache;
 import org.apache.mahout.cf.taste.impl.common.Retriever;
+import org.apache.mahout.cf.taste.impl.common.RefreshHelper;
+
+import java.util.Collection;
 
 /**
  * Caches the results from an underlying {@link ItemCorrelation} implementation.
@@ -52,9 +56,10 @@
     return correlationCache.get(key);
   }
 
-  public void refresh() {
+  public void refresh(Collection<Refreshable> alreadyRefreshed) {
     correlationCache.clear();
-    correlation.refresh();
+    alreadyRefreshed = RefreshHelper.buildRefreshed(alreadyRefreshed);
+    RefreshHelper.maybeRefresh(alreadyRefreshed, correlation);
   }
 
   private static final class CorrelationRetriever implements Retriever<Pair<Item, Item>, Double> {

Modified: lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/correlation/CachingUserCorrelation.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/correlation/CachingUserCorrelation.java?rev=684358&r1=684357&r2=684358&view=diff
==============================================================================
--- lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/correlation/CachingUserCorrelation.java (original)
+++ lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/correlation/CachingUserCorrelation.java Sat Aug  9 14:55:03 2008
@@ -22,9 +22,13 @@
 import org.apache.mahout.cf.taste.model.User;
 import org.apache.mahout.cf.taste.model.DataModel;
 import org.apache.mahout.cf.taste.common.TasteException;
+import org.apache.mahout.cf.taste.common.Refreshable;
 import org.apache.mahout.cf.taste.impl.common.Pair;
 import org.apache.mahout.cf.taste.impl.common.Cache;
 import org.apache.mahout.cf.taste.impl.common.Retriever;
+import org.apache.mahout.cf.taste.impl.common.RefreshHelper;
+
+import java.util.Collection;
 
 /**
  * Caches the results from an underlying {@link UserCorrelation} implementation.
@@ -58,9 +62,10 @@
     correlation.setPreferenceInferrer(inferrer);
   }
 
-  public void refresh() {
+  public void refresh(Collection<Refreshable> alreadyRefreshed) {
     correlationCache.clear();
-    correlation.refresh();
+    alreadyRefreshed = RefreshHelper.buildRefreshed(alreadyRefreshed);
+    RefreshHelper.maybeRefresh(alreadyRefreshed, correlation);
   }
 
   private static final class CorrelationRetriever implements Retriever<Pair<User, User>, Double> {

Modified: lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/correlation/GenericItemCorrelation.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/correlation/GenericItemCorrelation.java?rev=684358&r1=684357&r2=684358&view=diff
==============================================================================
--- lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/correlation/GenericItemCorrelation.java (original)
+++ lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/correlation/GenericItemCorrelation.java Sat Aug  9 14:55:03 2008
@@ -18,6 +18,7 @@
 package org.apache.mahout.cf.taste.impl.correlation;
 
 import org.apache.mahout.cf.taste.common.TasteException;
+import org.apache.mahout.cf.taste.common.Refreshable;
 import org.apache.mahout.cf.taste.correlation.ItemCorrelation;
 import org.apache.mahout.cf.taste.impl.common.IteratorIterable;
 import org.apache.mahout.cf.taste.impl.common.IteratorUtils;
@@ -30,6 +31,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.NoSuchElementException;
+import java.util.Collection;
 
 /**
  * <p>A "generic" {@link ItemCorrelation} which takes a static list of precomputed {@link Item}
@@ -173,7 +175,7 @@
     return correlation == null ? Double.NaN : correlation;
   }
 
-  public void refresh() {
+  public void refresh(Collection<Refreshable> alreadyRefreshed) {
     // Do nothing
   }
 

Modified: lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/correlation/LogLikelihoodCorrelation.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/correlation/LogLikelihoodCorrelation.java?rev=684358&r1=684357&r2=684358&view=diff
==============================================================================
--- lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/correlation/LogLikelihoodCorrelation.java (original)
+++ lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/correlation/LogLikelihoodCorrelation.java Sat Aug  9 14:55:03 2008
@@ -20,7 +20,11 @@
 import org.apache.mahout.cf.taste.model.DataModel;
 import org.apache.mahout.cf.taste.model.Item;
 import org.apache.mahout.cf.taste.common.TasteException;
+import org.apache.mahout.cf.taste.common.Refreshable;
 import org.apache.mahout.cf.taste.correlation.ItemCorrelation;
+import org.apache.mahout.cf.taste.impl.common.RefreshHelper;
+
+import java.util.Collection;
 
 /**
  * See <a href="http://citeseer.ist.psu.edu/29096.html">http://citeseer.ist.psu.edu/29096.html</a>.
@@ -59,8 +63,9 @@
     return d <= 0.0 ? 0 : Math.log(d);
   }
 
-  public void refresh() {
-    dataModel.refresh();
+  public void refresh(Collection<Refreshable> alreadyRefreshed) {
+    alreadyRefreshed = RefreshHelper.buildRefreshed(alreadyRefreshed);
+    RefreshHelper.maybeRefresh(alreadyRefreshed, dataModel);
   }
 
   @Override

Modified: lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/correlation/SpearmanCorrelation.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/correlation/SpearmanCorrelation.java?rev=684358&r1=684357&r2=684358&view=diff
==============================================================================
--- lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/correlation/SpearmanCorrelation.java (original)
+++ lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/correlation/SpearmanCorrelation.java Sat Aug  9 14:55:03 2008
@@ -18,16 +18,19 @@
 package org.apache.mahout.cf.taste.impl.correlation;
 
 import org.apache.mahout.cf.taste.common.TasteException;
+import org.apache.mahout.cf.taste.common.Refreshable;
 import org.apache.mahout.cf.taste.correlation.PreferenceInferrer;
 import org.apache.mahout.cf.taste.correlation.UserCorrelation;
 import org.apache.mahout.cf.taste.impl.model.ByItemPreferenceComparator;
 import org.apache.mahout.cf.taste.impl.model.ByValuePreferenceComparator;
 import org.apache.mahout.cf.taste.impl.model.GenericPreference;
+import org.apache.mahout.cf.taste.impl.common.RefreshHelper;
 import org.apache.mahout.cf.taste.model.DataModel;
 import org.apache.mahout.cf.taste.model.Preference;
 import org.apache.mahout.cf.taste.model.User;
 
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.concurrent.locks.ReentrantLock;
 
 /**
@@ -39,14 +42,12 @@
 public final class SpearmanCorrelation implements UserCorrelation {
 
   private final UserCorrelation rankingUserCorrelation;
-  private final ReentrantLock refreshLock;
 
   public SpearmanCorrelation(DataModel dataModel) throws TasteException {
     if (dataModel == null) {
       throw new IllegalArgumentException("dataModel is null");
     }
     this.rankingUserCorrelation = new PearsonCorrelation(dataModel);
-    this.refreshLock = new ReentrantLock();
   }
 
   public SpearmanCorrelation(UserCorrelation rankingUserCorrelation) {
@@ -54,7 +55,6 @@
       throw new IllegalArgumentException("rankingUserCorrelation is null");
     }
     this.rankingUserCorrelation = rankingUserCorrelation;
-    this.refreshLock = new ReentrantLock();
   }
 
   public double userCorrelation(User user1, User user2) throws TasteException {
@@ -69,16 +69,9 @@
     rankingUserCorrelation.setPreferenceInferrer(inferrer);
   }
 
-  public void refresh() {
-    if (refreshLock.isLocked()) {
-      return;
-    }
-    try {
-      refreshLock.lock();
-      rankingUserCorrelation.refresh();
-    } finally {
-      refreshLock.unlock();
-    }
+  public void refresh(Collection<Refreshable> alreadyRefreshed) {
+    alreadyRefreshed = RefreshHelper.buildRefreshed(alreadyRefreshed);
+    RefreshHelper.maybeRefresh(alreadyRefreshed, rankingUserCorrelation);
   }
 
 

Modified: lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/correlation/TanimotoCoefficientCorrelation.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/correlation/TanimotoCoefficientCorrelation.java?rev=684358&r1=684357&r2=684358&view=diff
==============================================================================
--- lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/correlation/TanimotoCoefficientCorrelation.java (original)
+++ lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/correlation/TanimotoCoefficientCorrelation.java Sat Aug  9 14:55:03 2008
@@ -22,12 +22,16 @@
 import org.apache.mahout.cf.taste.model.Preference;
 import org.apache.mahout.cf.taste.model.Item;
 import org.apache.mahout.cf.taste.common.TasteException;
+import org.apache.mahout.cf.taste.common.Refreshable;
 import org.apache.mahout.cf.taste.correlation.UserCorrelation;
 import org.apache.mahout.cf.taste.correlation.ItemCorrelation;
 import org.apache.mahout.cf.taste.correlation.PreferenceInferrer;
+import org.apache.mahout.cf.taste.impl.common.RefreshHelper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.util.Collection;
+
 /**
  * <p>An implementation of a "correlation" based on the
  * <a href="http://en.wikipedia.org/wiki/Jaccard_index">Tanimoto coefficient</a>, or extended
@@ -166,8 +170,9 @@
     return result;
   }
 
-  public void refresh() {
-    dataModel.refresh();
+  public void refresh(Collection<Refreshable> alreadyRefreshed) {
+    alreadyRefreshed = RefreshHelper.buildRefreshed(alreadyRefreshed);
+    RefreshHelper.maybeRefresh(alreadyRefreshed, dataModel);
   }
 
   @Override

Modified: lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/model/GenericDataModel.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/model/GenericDataModel.java?rev=684358&r1=684357&r2=684358&view=diff
==============================================================================
--- lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/model/GenericDataModel.java (original)
+++ lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/model/GenericDataModel.java Sat Aug  9 14:55:03 2008
@@ -18,6 +18,7 @@
 package org.apache.mahout.cf.taste.impl.model;
 
 import org.apache.mahout.cf.taste.common.TasteException;
+import org.apache.mahout.cf.taste.common.Refreshable;
 import org.apache.mahout.cf.taste.impl.common.ArrayIterator;
 import org.apache.mahout.cf.taste.impl.common.EmptyIterable;
 import org.apache.mahout.cf.taste.impl.common.FastMap;
@@ -35,6 +36,7 @@
 import java.util.NoSuchElementException;
 import java.util.Set;
 import java.util.HashSet;
+import java.util.Collection;
 
 /**
  * <p>A simple {@link DataModel} which uses a given {@link List} of {@link User}s as
@@ -207,7 +209,7 @@
     throw new UnsupportedOperationException();
   }
 
-  public void refresh() {
+  public void refresh(Collection<Refreshable> alreadyRefreshed) {
     // Does nothing
   }
 

Modified: lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/model/file/FileDataModel.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/model/file/FileDataModel.java?rev=684358&r1=684357&r2=684358&view=diff
==============================================================================
--- lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/model/file/FileDataModel.java (original)
+++ lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/model/file/FileDataModel.java Sat Aug  9 14:55:03 2008
@@ -17,6 +17,7 @@
 
 package org.apache.mahout.cf.taste.impl.model.file;
 
+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.FileLineIterable;
@@ -34,9 +35,9 @@
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.List;
 import java.util.Map;
-import java.util.NoSuchElementException;
 import java.util.Timer;
 import java.util.TimerTask;
 import java.util.concurrent.locks.ReentrantLock;
@@ -63,7 +64,6 @@
   private long lastModified;
   private boolean loaded;
   private DataModel delegate;
-  private final ReentrantLock refreshLock;
   private final ReentrantLock reloadLock;
 
   /**
@@ -82,7 +82,6 @@
 
     this.dataFile = dataFile;
     this.lastModified = dataFile.lastModified();
-    this.refreshLock = new ReentrantLock();
     this.reloadLock = new ReentrantLock();
 
     // Schedule next refresh
@@ -149,9 +148,6 @@
     return delegate.getUsers();
   }
 
-  /**
-   * @throws NoSuchElementException if there is no such user
-   */
   public User getUser(Object id) throws TasteException {
     checkLoaded();
     return delegate.getUser(id);
@@ -206,17 +202,8 @@
     throw new UnsupportedOperationException();
   }
 
-  public void refresh() {
-    if (refreshLock.isLocked()) {
-      return;
-    }
-    try {
-      refreshLock.lock();
-      reload();
-    } finally {
-      refreshLock.unlock();
-    }
-
+  public void refresh(Collection<Refreshable> alreadyRefreshed) {
+    reload();
   }
 
   /**

Modified: lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/model/jdbc/AbstractJDBCDataModel.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/model/jdbc/AbstractJDBCDataModel.java?rev=684358&r1=684357&r2=684358&view=diff
==============================================================================
--- lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/model/jdbc/AbstractJDBCDataModel.java (original)
+++ lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/model/jdbc/AbstractJDBCDataModel.java Sat Aug  9 14:55:03 2008
@@ -18,6 +18,7 @@
 package org.apache.mahout.cf.taste.impl.model.jdbc;
 
 import org.apache.mahout.cf.taste.common.TasteException;
+import org.apache.mahout.cf.taste.common.Refreshable;
 import org.apache.mahout.cf.taste.impl.common.IOUtils;
 import org.apache.mahout.cf.taste.impl.common.IteratorIterable;
 import org.apache.mahout.cf.taste.impl.model.GenericItem;
@@ -415,7 +416,7 @@
     }
   }
 
-  public final void refresh() {
+  public final void refresh(Collection<Refreshable> alreadyRefreshed) {
     // do nothing
   }
 

Modified: lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/neighborhood/AbstractUserNeighborhood.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/neighborhood/AbstractUserNeighborhood.java?rev=684358&r1=684357&r2=684358&view=diff
==============================================================================
--- lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/neighborhood/AbstractUserNeighborhood.java (original)
+++ lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/neighborhood/AbstractUserNeighborhood.java Sat Aug  9 14:55:03 2008
@@ -20,6 +20,10 @@
 import org.apache.mahout.cf.taste.correlation.UserCorrelation;
 import org.apache.mahout.cf.taste.model.DataModel;
 import org.apache.mahout.cf.taste.neighborhood.UserNeighborhood;
+import org.apache.mahout.cf.taste.impl.common.RefreshHelper;
+import org.apache.mahout.cf.taste.common.Refreshable;
+
+import java.util.Collection;
 
 /**
  * <p>Contains methods and resources useful to all classes in this package.</p>
@@ -29,6 +33,7 @@
   private final UserCorrelation userCorrelation;
   private final DataModel dataModel;
   private final double samplingRate;
+  private final RefreshHelper refreshHelper;
 
   AbstractUserNeighborhood(UserCorrelation userCorrelation,
                            DataModel dataModel,
@@ -42,6 +47,9 @@
     this.userCorrelation = userCorrelation;
     this.dataModel = dataModel;
     this.samplingRate = samplingRate;
+    this.refreshHelper = new RefreshHelper(null);
+    this.refreshHelper.addDependency(this.dataModel);
+    this.refreshHelper.addDependency(this.userCorrelation);
   }
 
   final UserCorrelation getUserCorrelation() {
@@ -56,9 +64,8 @@
     return samplingRate >= 1.0 || Math.random() < samplingRate;
   }
 
-  public final void refresh() {
-    userCorrelation.refresh();
-    dataModel.refresh();
+  public final void refresh(Collection<Refreshable> alreadyRefreshed) {
+    refreshHelper.refresh(alreadyRefreshed);
   }
 
 }

Modified: lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/neighborhood/CachingUserNeighborhood.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/neighborhood/CachingUserNeighborhood.java?rev=684358&r1=684357&r2=684358&view=diff
==============================================================================
--- lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/neighborhood/CachingUserNeighborhood.java (original)
+++ lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/neighborhood/CachingUserNeighborhood.java Sat Aug  9 14:55:03 2008
@@ -21,8 +21,10 @@
 import org.apache.mahout.cf.taste.model.User;
 import org.apache.mahout.cf.taste.model.DataModel;
 import org.apache.mahout.cf.taste.common.TasteException;
+import org.apache.mahout.cf.taste.common.Refreshable;
 import org.apache.mahout.cf.taste.impl.common.Cache;
 import org.apache.mahout.cf.taste.impl.common.Retriever;
+import org.apache.mahout.cf.taste.impl.common.RefreshHelper;
 
 import java.util.Collection;
 
@@ -47,9 +49,10 @@
     return neighborhoodCache.get(userID);
   }
 
-  public void refresh() {
+  public void refresh(Collection<Refreshable> alreadyRefreshed) {
     neighborhoodCache.clear();
-    neighborhood.refresh();
+    alreadyRefreshed = RefreshHelper.buildRefreshed(alreadyRefreshed);
+    RefreshHelper.maybeRefresh(alreadyRefreshed, neighborhood);
   }
 
   private static final class NeighborhoodRetriever implements Retriever<Object, Collection<User>> {

Modified: lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/AbstractRecommender.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/AbstractRecommender.java?rev=684358&r1=684357&r2=684358&view=diff
==============================================================================
--- lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/AbstractRecommender.java (original)
+++ lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/AbstractRecommender.java Sat Aug  9 14:55:03 2008
@@ -29,21 +29,18 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
-import java.util.concurrent.locks.ReentrantLock;
 
 public abstract class AbstractRecommender implements Recommender {
 
   private static final Logger log = LoggerFactory.getLogger(AbstractRecommender.class);
 
   private final DataModel dataModel;
-  private final ReentrantLock refreshLock;
 
   protected AbstractRecommender(DataModel dataModel) {
     if (dataModel == null) {
       throw new IllegalArgumentException("dataModel is null");
     }
     this.dataModel = dataModel;
-    this.refreshLock = new ReentrantLock();
   }
 
   /**
@@ -92,18 +89,6 @@
     return dataModel;
   }
 
-  public void refresh() {
-    if (refreshLock.isLocked()) {
-      return;
-    }
-    try {
-      refreshLock.lock();
-      dataModel.refresh();
-    } finally {
-      refreshLock.unlock();
-    }
-  }
-
   /**
    * @param theUser {@link User} being evaluated
    * @return all {@link Item}s in the {@link DataModel} for which the {@link User} has not expressed a preference

Modified: lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/CachingRecommender.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/CachingRecommender.java?rev=684358&r1=684357&r2=684358&view=diff
==============================================================================
--- lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/CachingRecommender.java (original)
+++ lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/CachingRecommender.java Sat Aug  9 14:55:03 2008
@@ -18,9 +18,11 @@
 package org.apache.mahout.cf.taste.impl.recommender;
 
 import org.apache.mahout.cf.taste.common.TasteException;
+import org.apache.mahout.cf.taste.common.Refreshable;
 import org.apache.mahout.cf.taste.impl.common.Pair;
 import org.apache.mahout.cf.taste.impl.common.Cache;
 import org.apache.mahout.cf.taste.impl.common.Retriever;
+import org.apache.mahout.cf.taste.impl.common.RefreshHelper;
 import org.apache.mahout.cf.taste.model.DataModel;
 import org.apache.mahout.cf.taste.model.Item;
 import org.apache.mahout.cf.taste.recommender.RecommendedItem;
@@ -32,8 +34,10 @@
 import java.lang.ref.SoftReference;
 import java.util.Collections;
 import java.util.List;
+import java.util.Collection;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.locks.ReentrantLock;
+import java.util.concurrent.Callable;
 
 /**
  * <p>A {@link Recommender} which caches the results from another {@link Recommender} in memory.
@@ -48,7 +52,7 @@
   private final AtomicInteger maxHowMany;
   private final Cache<Object, Recommendations> recommendationCache;
   private final Cache<Pair<?, ?>, Double> estimatedPrefCache;
-  private final ReentrantLock refreshLock;
+  private final RefreshHelper refreshHelper;
 
   public CachingRecommender(Recommender recommender) throws TasteException {
     if (recommender == null) {
@@ -64,7 +68,13 @@
                     numUsers);
     this.estimatedPrefCache =
             new Cache<Pair<?, ?>, Double>(new EstimatedPrefRetriever(this.recommender), numUsers);
-    this.refreshLock = new ReentrantLock();
+    this.refreshHelper = new RefreshHelper(new Callable<Object>() {
+      public Object call() {
+        clear();
+        return null;
+      }
+    });
+    this.refreshHelper.addDependency(recommender);
   }
 
   public List<RecommendedItem> recommend(Object userID, int howMany) throws TasteException {
@@ -82,17 +92,17 @@
     }
 
     Recommendations recommendations = recommendationCache.get(userID);
-    if (recommendations.items.size() < howMany && !recommendations.noMoreRecommendableItems) {
+    if (recommendations.getItems().size() < howMany && !recommendations.noMoreRecommendableItems) {
       clear(userID);
       recommendations = recommendationCache.get(userID);
-      if (recommendations.items.size() < howMany) {
+      if (recommendations.getItems().size() < howMany) {
         recommendations.noMoreRecommendableItems = true;
       }
     }
 
-    return recommendations.items.size() > howMany ?
-           recommendations.items.subList(0, howMany) :
-           recommendations.items;
+    return recommendations.getItems().size() > howMany ?
+           recommendations.getItems().subList(0, howMany) :
+           recommendations.getItems();
   }
 
   public List<RecommendedItem> recommend(Object userID, int howMany, Rescorer<Item> rescorer)
@@ -119,17 +129,8 @@
     return recommender.getDataModel();
   }
 
-  public void refresh() {
-    if (refreshLock.isLocked()) {
-      return;
-    }
-    try {
-      refreshLock.lock();
-      recommender.refresh();
-      clear();
-    } finally {
-      refreshLock.unlock();
-    }
+  public void refresh(Collection<Refreshable> alreadyRefreshed) {
+    refreshHelper.refresh(alreadyRefreshed);
   }
 
   /**
@@ -196,6 +197,10 @@
       this.items = items;
       this.noMoreRecommendableItems = false;
     }
+
+    private List<RecommendedItem> getItems() {
+      return items;
+    }
   }
 
 }

Modified: lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/FarthestNeighborClusterSimilarity.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/FarthestNeighborClusterSimilarity.java?rev=684358&r1=684357&r2=684358&view=diff
==============================================================================
--- lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/FarthestNeighborClusterSimilarity.java (original)
+++ lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/FarthestNeighborClusterSimilarity.java Sat Aug  9 14:55:03 2008
@@ -18,8 +18,10 @@
 package org.apache.mahout.cf.taste.impl.recommender;
 
 import org.apache.mahout.cf.taste.common.TasteException;
+import org.apache.mahout.cf.taste.common.Refreshable;
 import org.apache.mahout.cf.taste.correlation.UserCorrelation;
 import org.apache.mahout.cf.taste.model.User;
+import org.apache.mahout.cf.taste.impl.common.RefreshHelper;
 
 import java.util.Collection;
 
@@ -36,8 +38,6 @@
   /**
    * <p>Constructs a {@link FarthestNeighborClusterSimilarity} based on the given {@link UserCorrelation}.
    * All user-user correlations are examined.</p>
-   *
-   * @param correlation
    */
   public FarthestNeighborClusterSimilarity(UserCorrelation correlation) {
     this(correlation, 1.0);
@@ -48,9 +48,6 @@
    * By setting <code>samplingPercentage</code> to a value less than 1.0, this implementation will only examine
    * that fraction of all user-user correlations between two clusters, increasing performance at the expense
    * of accuracy.</p>
-   *
-   * @param correlation
-   * @param samplingPercentage
    */
   public FarthestNeighborClusterSimilarity(UserCorrelation correlation, double samplingPercentage) {
     if (correlation == null) {
@@ -86,8 +83,9 @@
     return leastCorrelation;
   }
 
-  public void refresh() {
-    correlation.refresh();
+  public void refresh(Collection<Refreshable> alreadyRefreshed) {
+    alreadyRefreshed = RefreshHelper.buildRefreshed(alreadyRefreshed);
+    RefreshHelper.maybeRefresh(alreadyRefreshed, correlation);
   }
 
   @Override

Modified: lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/GenericItemBasedRecommender.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/GenericItemBasedRecommender.java?rev=684358&r1=684357&r2=684358&view=diff
==============================================================================
--- lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/GenericItemBasedRecommender.java (original)
+++ lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/GenericItemBasedRecommender.java Sat Aug  9 14:55:03 2008
@@ -18,10 +18,12 @@
 package org.apache.mahout.cf.taste.impl.recommender;
 
 import org.apache.mahout.cf.taste.common.TasteException;
+import org.apache.mahout.cf.taste.common.Refreshable;
 import org.apache.mahout.cf.taste.correlation.ItemCorrelation;
 import org.apache.mahout.cf.taste.impl.common.FullRunningAverage;
 import org.apache.mahout.cf.taste.impl.common.Pair;
 import org.apache.mahout.cf.taste.impl.common.RunningAverage;
+import org.apache.mahout.cf.taste.impl.common.RefreshHelper;
 import org.apache.mahout.cf.taste.model.DataModel;
 import org.apache.mahout.cf.taste.model.Item;
 import org.apache.mahout.cf.taste.model.Preference;
@@ -38,7 +40,6 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
-import java.util.concurrent.locks.ReentrantLock;
 
 /**
  * <p>A simple {@link org.apache.mahout.cf.taste.recommender.Recommender} which uses a given
@@ -60,7 +61,7 @@
   private static final Logger log = LoggerFactory.getLogger(GenericItemBasedRecommender.class);
 
   private final ItemCorrelation correlation;
-  private final ReentrantLock refreshLock;
+  private final RefreshHelper refreshHelper;
 
   public GenericItemBasedRecommender(DataModel dataModel, ItemCorrelation correlation) {
     super(dataModel);
@@ -68,7 +69,9 @@
       throw new IllegalArgumentException("correlation is null");
     }
     this.correlation = correlation;
-    this.refreshLock = new ReentrantLock();
+    this.refreshHelper = new RefreshHelper(null);
+    refreshHelper.addDependency(dataModel);
+    refreshHelper.addDependency(correlation);
   }
 
   public List<RecommendedItem> recommend(Object userID, int howMany, Rescorer<Item> rescorer)
@@ -217,18 +220,8 @@
     return theUser.getPreferencesAsArray().length;
   }
 
-  @Override
-  public void refresh() {
-    if (refreshLock.isLocked()) {
-      return;
-    }
-    try {
-      refreshLock.lock();
-      super.refresh();
-      correlation.refresh();
-    } finally {
-      refreshLock.unlock();
-    }
+  public void refresh(Collection<Refreshable> alreadyRefreshed) {
+    refreshHelper.refresh(alreadyRefreshed);
   }
 
   @Override

Modified: lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/GenericUserBasedRecommender.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/GenericUserBasedRecommender.java?rev=684358&r1=684357&r2=684358&view=diff
==============================================================================
--- lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/GenericUserBasedRecommender.java (original)
+++ lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/GenericUserBasedRecommender.java Sat Aug  9 14:55:03 2008
@@ -18,8 +18,10 @@
 package org.apache.mahout.cf.taste.impl.recommender;
 
 import org.apache.mahout.cf.taste.common.TasteException;
+import org.apache.mahout.cf.taste.common.Refreshable;
 import org.apache.mahout.cf.taste.correlation.UserCorrelation;
 import org.apache.mahout.cf.taste.impl.common.Pair;
+import org.apache.mahout.cf.taste.impl.common.RefreshHelper;
 import org.apache.mahout.cf.taste.model.DataModel;
 import org.apache.mahout.cf.taste.model.Item;
 import org.apache.mahout.cf.taste.model.Preference;
@@ -37,7 +39,6 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
-import java.util.concurrent.locks.ReentrantLock;
 
 /**
  * <p>A simple {@link Recommender} which uses a given {@link DataModel} and {@link UserNeighborhood}
@@ -49,7 +50,7 @@
 
   private final UserNeighborhood neighborhood;
   private final UserCorrelation correlation;
-  private final ReentrantLock refreshLock;
+  private final RefreshHelper refreshHelper;
 
   public GenericUserBasedRecommender(DataModel dataModel,
                                      UserNeighborhood neighborhood,
@@ -60,7 +61,10 @@
     }
     this.neighborhood = neighborhood;
     this.correlation = correlation;
-    this.refreshLock = new ReentrantLock();
+    this.refreshHelper = new RefreshHelper(null);
+    refreshHelper.addDependency(dataModel);
+    refreshHelper.addDependency(correlation);
+    refreshHelper.addDependency(neighborhood);
   }
 
   public List<RecommendedItem> recommend(Object userID, int howMany, Rescorer<Item> rescorer)
@@ -174,18 +178,8 @@
     return allItems;
   }
 
-  @Override
-  public void refresh() {
-    if (refreshLock.isLocked()) {
-      return;
-    }
-    try {
-      refreshLock.lock();
-      super.refresh();
-      neighborhood.refresh();
-    } finally {
-      refreshLock.unlock();
-    }
+  public void refresh(Collection<Refreshable> alreadyRefreshed) {
+    refreshHelper.refresh(alreadyRefreshed);
   }
 
   @Override

Modified: lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/ItemAverageRecommender.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/ItemAverageRecommender.java?rev=684358&r1=684357&r2=684358&view=diff
==============================================================================
--- lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/ItemAverageRecommender.java (original)
+++ lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/ItemAverageRecommender.java Sat Aug  9 14:55:03 2008
@@ -18,9 +18,11 @@
 package org.apache.mahout.cf.taste.impl.recommender;
 
 import org.apache.mahout.cf.taste.common.TasteException;
+import org.apache.mahout.cf.taste.common.Refreshable;
 import org.apache.mahout.cf.taste.impl.common.FullRunningAverage;
 import org.apache.mahout.cf.taste.impl.common.RunningAverage;
 import org.apache.mahout.cf.taste.impl.common.FastMap;
+import org.apache.mahout.cf.taste.impl.common.RefreshHelper;
 import org.apache.mahout.cf.taste.model.DataModel;
 import org.apache.mahout.cf.taste.model.Item;
 import org.apache.mahout.cf.taste.model.Preference;
@@ -34,9 +36,10 @@
 import java.util.Map;
 import java.util.NoSuchElementException;
 import java.util.Set;
+import java.util.Collection;
 import java.util.concurrent.locks.ReadWriteLock;
-import java.util.concurrent.locks.ReentrantLock;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.concurrent.Callable;
 
 /**
  * <p>A simple recommender that always estimates preference for an {@link Item} to be the average of
@@ -50,14 +53,20 @@
 
   private final Map<Object, RunningAverage> itemAverages;
   private boolean averagesBuilt;
-  private final ReentrantLock refreshLock;
   private final ReadWriteLock buildAveragesLock;
+  private final RefreshHelper refreshHelper;
 
   public ItemAverageRecommender(DataModel dataModel) {
     super(dataModel);
     this.itemAverages = new FastMap<Object, RunningAverage>();
-    this.refreshLock = new ReentrantLock();
     this.buildAveragesLock = new ReentrantReadWriteLock();
+    this.refreshHelper = new RefreshHelper(new Callable<Object>() {
+      public Object call() throws TasteException {
+        buildAverageDiffs();
+        return null;
+      }
+    });
+    refreshHelper.addDependency(dataModel);
   }
 
   public List<RecommendedItem> recommend(Object userID, int howMany, Rescorer<Item> rescorer)
@@ -183,22 +192,8 @@
     }
   }
 
-  @Override
-  public void refresh() {
-    if (refreshLock.isLocked()) {
-      return;
-    }
-    try {
-      refreshLock.lock();
-      super.refresh();
-      try {
-        buildAverageDiffs();
-      } catch (TasteException te) {
-        log.warn("Unexpected excpetion while refreshing", te);
-      }
-    } finally {
-      refreshLock.unlock();
-    }
+  public void refresh(Collection<Refreshable> alreadyRefreshed) {
+    refreshHelper.refresh(alreadyRefreshed);
   }
 
   @Override

Modified: lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/ItemUserAverageRecommender.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/ItemUserAverageRecommender.java?rev=684358&r1=684357&r2=684358&view=diff
==============================================================================
--- lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/ItemUserAverageRecommender.java (original)
+++ lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/ItemUserAverageRecommender.java Sat Aug  9 14:55:03 2008
@@ -18,9 +18,11 @@
 package org.apache.mahout.cf.taste.impl.recommender;
 
 import org.apache.mahout.cf.taste.common.TasteException;
+import org.apache.mahout.cf.taste.common.Refreshable;
 import org.apache.mahout.cf.taste.impl.common.FullRunningAverage;
 import org.apache.mahout.cf.taste.impl.common.RunningAverage;
 import org.apache.mahout.cf.taste.impl.common.FastMap;
+import org.apache.mahout.cf.taste.impl.common.RefreshHelper;
 import org.apache.mahout.cf.taste.model.DataModel;
 import org.apache.mahout.cf.taste.model.Item;
 import org.apache.mahout.cf.taste.model.Preference;
@@ -34,9 +36,10 @@
 import java.util.Map;
 import java.util.NoSuchElementException;
 import java.util.Set;
+import java.util.Collection;
 import java.util.concurrent.locks.ReadWriteLock;
-import java.util.concurrent.locks.ReentrantLock;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.concurrent.Callable;
 
 /**
  * <p>Like {@link ItemAverageRecommender}, except that estimated preferences are adjusted for the
@@ -53,16 +56,22 @@
   private final Map<Object, RunningAverage> userAverages;
   private final RunningAverage overallAveragePrefValue;
   private boolean averagesBuilt;
-  private final ReentrantLock refreshLock;
   private final ReadWriteLock buildAveragesLock;
+  private final RefreshHelper refreshHelper;
 
   public ItemUserAverageRecommender(DataModel dataModel) {
     super(dataModel);
     this.itemAverages = new FastMap<Object, RunningAverage>();
     this.userAverages = new FastMap<Object, RunningAverage>();
     this.overallAveragePrefValue = new FullRunningAverage();
-    this.refreshLock = new ReentrantLock();
     this.buildAveragesLock = new ReentrantReadWriteLock();
+    this.refreshHelper = new RefreshHelper(new Callable<Object>() {
+      public Object call() throws TasteException {
+        buildAverageDiffs();
+        return null;
+      }
+    });
+    refreshHelper.addDependency(dataModel);
   }
 
   public List<RecommendedItem> recommend(Object userID, int howMany, Rescorer<Item> rescorer)
@@ -221,22 +230,8 @@
     }
   }
 
-  @Override
-  public void refresh() {
-    if (refreshLock.isLocked()) {
-      return;
-    }
-    try {
-      refreshLock.lock();
-      super.refresh();
-      try {
-        buildAverageDiffs();
-      } catch (TasteException te) {
-        log.warn("Unexpected excpetion while refreshing", te);
-      }
-    } finally {
-      refreshLock.unlock();
-    }
+  public void refresh(Collection<Refreshable> alreadyRefreshed) {
+    refreshHelper.refresh(alreadyRefreshed);
   }
 
   @Override

Modified: lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/NearestNeighborClusterSimilarity.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/NearestNeighborClusterSimilarity.java?rev=684358&r1=684357&r2=684358&view=diff
==============================================================================
--- lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/NearestNeighborClusterSimilarity.java (original)
+++ lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/NearestNeighborClusterSimilarity.java Sat Aug  9 14:55:03 2008
@@ -18,8 +18,10 @@
 package org.apache.mahout.cf.taste.impl.recommender;
 
 import org.apache.mahout.cf.taste.common.TasteException;
+import org.apache.mahout.cf.taste.common.Refreshable;
 import org.apache.mahout.cf.taste.correlation.UserCorrelation;
 import org.apache.mahout.cf.taste.model.User;
+import org.apache.mahout.cf.taste.impl.common.RefreshHelper;
 
 import java.util.Collection;
 
@@ -36,8 +38,6 @@
   /**
    * <p>Constructs a {@link NearestNeighborClusterSimilarity} based on the given {@link UserCorrelation}.
    * All user-user correlations are examined.</p>
-   *
-   * @param correlation
    */
   public NearestNeighborClusterSimilarity(UserCorrelation correlation) {
     this(correlation, 1.0);
@@ -48,9 +48,6 @@
    * By setting <code>samplingPercentage</code> to a value less than 1.0, this implementation will only examine
    * that fraction of all user-user correlations between two clusters, increasing performance at the expense
    * of accuracy.</p>
-   *
-   * @param correlation
-   * @param samplingPercentage
    */
   public NearestNeighborClusterSimilarity(UserCorrelation correlation, double samplingPercentage) {
     if (correlation == null) {
@@ -86,8 +83,9 @@
     return greatestCorrelation;
   }
 
-  public void refresh() {
-    correlation.refresh();
+  public void refresh(Collection<Refreshable> alreadyRefreshed) {
+    alreadyRefreshed = RefreshHelper.buildRefreshed(alreadyRefreshed);
+    RefreshHelper.maybeRefresh(alreadyRefreshed, correlation);
   }
 
   @Override

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=684358&r1=684357&r2=684358&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 Sat Aug  9 14:55:03 2008
@@ -18,11 +18,8 @@
 package org.apache.mahout.cf.taste.impl.recommender;
 
 import org.apache.mahout.cf.taste.common.TasteException;
-import org.apache.mahout.cf.taste.impl.common.FullRunningAverage;
-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.RunningAverage;
-import org.apache.mahout.cf.taste.impl.common.FastMap;
+import org.apache.mahout.cf.taste.common.Refreshable;
+import org.apache.mahout.cf.taste.impl.common.*;
 import org.apache.mahout.cf.taste.model.DataModel;
 import org.apache.mahout.cf.taste.model.Item;
 import org.apache.mahout.cf.taste.model.Preference;
@@ -41,6 +38,7 @@
 import java.util.Map;
 import java.util.Random;
 import java.util.concurrent.locks.ReentrantLock;
+import java.util.concurrent.Callable;
 
 /**
  * <p>A {@link org.apache.mahout.cf.taste.recommender.Recommender} that clusters {@link User}s, then determines
@@ -68,8 +66,8 @@
   private Collection<Collection<User>> allClusters;
   private Map<Object, Collection<User>> clustersByUserID;
   private boolean clustersBuilt;
-  private final ReentrantLock refreshLock;
   private final ReentrantLock buildClustersLock;
+  private final RefreshHelper refreshHelper;
 
   /**
    * @param dataModel {@link DataModel} which provdes {@link User}s
@@ -113,8 +111,15 @@
     this.clusteringThreshold = Double.NaN;
     this.clusteringByThreshold = false;
     this.samplingPercentage = samplingPercentage;
-    this.refreshLock = new ReentrantLock();
     this.buildClustersLock = new ReentrantLock();
+    this.refreshHelper = new RefreshHelper(new Callable<Object>() {
+      public Object call() throws TasteException {
+        buildClusters();
+        return null;
+      }
+    });
+    refreshHelper.addDependency(dataModel);
+    refreshHelper.addDependency(clusterSimilarity);
   }
 
   /**
@@ -161,8 +166,15 @@
     this.clusteringThreshold = clusteringThreshold;
     this.clusteringByThreshold = true;
     this.samplingPercentage = samplingPercentage;
-    this.refreshLock = new ReentrantLock();
     this.buildClustersLock = new ReentrantLock();
+    this.refreshHelper = new RefreshHelper(new Callable<Object>() {
+      public Object call() throws TasteException {
+        buildClusters();
+        return null;
+      }
+    });
+    refreshHelper.addDependency(dataModel);
+    refreshHelper.addDependency(clusterSimilarity);
   }
 
   public List<RecommendedItem> recommend(Object userID, int howMany, Rescorer<Item> rescorer)
@@ -385,23 +397,8 @@
     return clustersPerUser;
   }
 
-  @Override
-  public void refresh() {
-    if (refreshLock.isLocked()) {
-      return;
-    }
-    try {
-      refreshLock.lock();
-      super.refresh();
-      clusterSimilarity.refresh();
-      try {
-        buildClusters();
-      } catch (TasteException te) {
-        log.warn("Unexpected excpetion while refreshing", te);
-      }
-    } finally {
-      refreshLock.unlock();
-    }
+  public void refresh(Collection<Refreshable> alreadyRefreshed) {
+    refreshHelper.refresh(alreadyRefreshed);
   }
 
   @Override

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=684358&r1=684357&r2=684358&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 Sat Aug  9 14:55:03 2008
@@ -18,9 +18,11 @@
 package org.apache.mahout.cf.taste.impl.recommender;
 
 import org.apache.mahout.cf.taste.common.TasteException;
+import org.apache.mahout.cf.taste.common.Refreshable;
 import org.apache.mahout.cf.taste.impl.common.FullRunningAverage;
 import org.apache.mahout.cf.taste.impl.common.RunningAverage;
 import org.apache.mahout.cf.taste.impl.common.FastMap;
+import org.apache.mahout.cf.taste.impl.common.RefreshHelper;
 import org.apache.mahout.cf.taste.model.DataModel;
 import org.apache.mahout.cf.taste.model.Item;
 import org.apache.mahout.cf.taste.model.Preference;
@@ -41,6 +43,7 @@
 import java.util.ListIterator;
 import java.util.Map;
 import java.util.concurrent.locks.ReentrantLock;
+import java.util.concurrent.Callable;
 
 /**
  * <p>A {@link org.apache.mahout.cf.taste.recommender.Recommender} that clusters
@@ -74,8 +77,8 @@
   private Collection<Collection<User>> allClusters;
   private Map<Object, Collection<User>> clustersByUserID;
   private boolean clustersBuilt;
-  private final ReentrantLock refreshLock;
   private final ReentrantLock buildClustersLock;
+  private final RefreshHelper refreshHelper;
 
   /**
    * @param dataModel {@link org.apache.mahout.cf.taste.model.DataModel} which provdes {@link org.apache.mahout.cf.taste.model.User}s
@@ -99,8 +102,15 @@
     this.numClusters = numClusters;
     this.clusteringThreshold = Double.NaN;
     this.clusteringByThreshold = false;
-    this.refreshLock = new ReentrantLock();
     this.buildClustersLock = new ReentrantLock();
+    this.refreshHelper = new RefreshHelper(new Callable<Object>() {
+      public Object call() throws TasteException {
+        buildClusters();
+        return null;
+      }
+    });
+    refreshHelper.addDependency(dataModel);
+    refreshHelper.addDependency(clusterSimilarity);
   }
 
   /**
@@ -126,8 +136,15 @@
     this.numClusters = Integer.MIN_VALUE;
     this.clusteringThreshold = clusteringThreshold;
     this.clusteringByThreshold = true;
-    this.refreshLock = new ReentrantLock();
     this.buildClustersLock = new ReentrantLock();
+    this.refreshHelper = new RefreshHelper(new Callable<Object>() {
+      public Object call() throws TasteException {
+        buildClusters();
+        return null;
+      }
+    });
+    refreshHelper.addDependency(dataModel);
+    refreshHelper.addDependency(clusterSimilarity);
   }
 
   public List<RecommendedItem> recommend(Object userID, int howMany, Rescorer<Item> rescorer)
@@ -457,23 +474,8 @@
     return clustersPerUser;
   }
 
-  @Override
-  public void refresh() {
-    if (refreshLock.isLocked()) {
-      return;
-    }
-    try {
-      refreshLock.lock();
-      super.refresh();
-      clusterSimilarity.refresh();
-      try {
-        buildClusters();
-      } catch (TasteException te) {
-        log.warn("Unexpected excpetion while refreshing", te);
-      }
-    } finally {
-      refreshLock.unlock();
-    }
+  public void refresh(Collection<Refreshable> alreadyRefreshed) {
+    refreshHelper.refresh(alreadyRefreshed);
   }
 
   @Override

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=684358&r1=684357&r2=684358&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 Sat Aug  9 14:55:03 2008
@@ -18,13 +18,8 @@
 package org.apache.mahout.cf.taste.impl.recommender.slopeone;
 
 import org.apache.mahout.cf.taste.common.TasteException;
-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.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.common.Refreshable;
+import org.apache.mahout.cf.taste.impl.common.*;
 import org.apache.mahout.cf.taste.model.DataModel;
 import org.apache.mahout.cf.taste.model.Item;
 import org.apache.mahout.cf.taste.model.Preference;
@@ -37,9 +32,11 @@
 import java.util.Iterator;
 import java.util.Map;
 import java.util.Set;
+import java.util.Collection;
 import java.util.concurrent.locks.ReadWriteLock;
 import java.util.concurrent.locks.ReentrantLock;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.concurrent.Callable;
 
 /**
  * <p>An implementation of {@link DiffStorage} that merely stores item-item diffs in memory.
@@ -56,7 +53,7 @@
   private final Map<Object, Map<Object, RunningAverage>> averageDiffs;
   private final Map<Object, RunningAverage> averageItemPref;
   private final ReadWriteLock buildAverageDiffsLock;
-  private final ReentrantLock refreshLock;
+  private final RefreshHelper refreshHelper;
 
   /**
    * <p>Creates a new {@link MemoryDiffStorage}.</p>
@@ -102,7 +99,13 @@
     this.averageDiffs = new FastMap<Object, Map<Object, RunningAverage>>();
     this.averageItemPref = new FastMap<Object, RunningAverage>();
     this.buildAverageDiffsLock = new ReentrantReadWriteLock();
-    this.refreshLock = new ReentrantLock();
+    this.refreshHelper = new RefreshHelper(new Callable<Object>() {
+      public Object call() throws TasteException {
+        buildAverageDiffs();
+        return null;
+      }
+    });
+    refreshHelper.addDependency(dataModel);
     buildAverageDiffs();
   }
 
@@ -275,21 +278,8 @@
     }
   }
 
-  public void refresh() {
-    if (refreshLock.isLocked()) {
-      return;
-    }
-    try {
-      refreshLock.lock();
-      dataModel.refresh();
-      try {
-        buildAverageDiffs();
-      } catch (TasteException te) {
-        log.warn("Unexpected exception while refreshing", te);
-      }
-    } finally {
-      refreshLock.unlock();
-    }
+  public void refresh(Collection<Refreshable> alreadyRefreshed) {
+    refreshHelper.refresh(alreadyRefreshed);
   }
 
   @Override

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=684358&r1=684357&r2=684358&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 Sat Aug  9 14:55:03 2008
@@ -19,8 +19,10 @@
 
 import org.apache.mahout.cf.taste.common.TasteException;
 import org.apache.mahout.cf.taste.common.Weighting;
+import org.apache.mahout.cf.taste.common.Refreshable;
 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.common.RefreshHelper;
 import org.apache.mahout.cf.taste.impl.recommender.AbstractRecommender;
 import org.apache.mahout.cf.taste.impl.recommender.TopItems;
 import org.apache.mahout.cf.taste.model.DataModel;
@@ -36,6 +38,7 @@
 import java.util.List;
 import java.util.NoSuchElementException;
 import java.util.Set;
+import java.util.Collection;
 
 /**
  * <p>A basic "slope one" recommender. (See an <a href="http://www.daniel-lemire.com/fr/abstracts/SDM2005.html">
@@ -193,9 +196,9 @@
     }
   }
 
-  @Override
-  public void refresh() {
-    diffStorage.refresh();
+  public void refresh(Collection<Refreshable> alreadyRefreshed) {
+    alreadyRefreshed = RefreshHelper.buildRefreshed(alreadyRefreshed);
+    RefreshHelper.maybeRefresh(alreadyRefreshed, diffStorage);
   }
 
   @Override

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=684358&r1=684357&r2=684358&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 Sat Aug  9 14:55:03 2008
@@ -18,8 +18,10 @@
 package org.apache.mahout.cf.taste.impl.recommender.slopeone.jdbc;
 
 import org.apache.mahout.cf.taste.common.TasteException;
+import org.apache.mahout.cf.taste.common.Refreshable;
 import org.apache.mahout.cf.taste.impl.common.IOUtils;
 import org.apache.mahout.cf.taste.impl.common.RunningAverage;
+import org.apache.mahout.cf.taste.impl.common.RefreshHelper;
 import org.apache.mahout.cf.taste.model.Item;
 import org.apache.mahout.cf.taste.model.JDBCDataModel;
 import org.apache.mahout.cf.taste.model.Preference;
@@ -34,7 +36,8 @@
 import java.sql.SQLException;
 import java.util.HashSet;
 import java.util.Set;
-import java.util.concurrent.locks.ReentrantLock;
+import java.util.Collection;
+import java.util.concurrent.Callable;
 
 /**
  * <p>A  {@link DiffStorage} which stores diffs in a database. Database-specific implementations subclass
@@ -64,7 +67,7 @@
   private final String createDiffsSQL;
   private final String diffsExistSQL;
   private final int minDiffCount;
-  private final ReentrantLock refreshLock;
+  private final RefreshHelper refreshHelper;
 
   protected AbstractJDBCDiffStorage(JDBCDataModel dataModel,
                                     String getDiffSQL,
@@ -95,7 +98,13 @@
     this.createDiffsSQL = createDiffsSQL;
     this.diffsExistSQL = diffsExistSQL;
     this.minDiffCount = minDiffCount;
-    this.refreshLock = new ReentrantLock();
+    this.refreshHelper = new RefreshHelper(new Callable<Object>() {
+      public Object call() throws TasteException {
+        buildAverageDiffs();
+        return null;
+      }
+    });
+    refreshHelper.addDependency(dataModel);
     if (isDiffsExist()) {
       log.info("Diffs already exist in database; using them instead of recomputing");
     } else {
@@ -296,21 +305,8 @@
     }
   }
 
-  public void refresh() {
-    if (refreshLock.isLocked()) {
-      return;
-    }
-    try {
-      refreshLock.lock();
-      dataModel.refresh();
-      try {
-        buildAverageDiffs();
-      } catch (TasteException te) {
-        log.warn("Unexpected exception while refreshing", te);
-      }
-    } finally {
-      refreshLock.unlock();
-    }
+  public void refresh(Collection<Refreshable> alreadyRefreshed) {
+    refreshHelper.refresh(alreadyRefreshed);
   }
 
   private static class FixedRunningAverage implements RunningAverage {

Modified: lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/transforms/CaseAmplification.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/transforms/CaseAmplification.java?rev=684358&r1=684357&r2=684358&view=diff
==============================================================================
--- lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/transforms/CaseAmplification.java (original)
+++ lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/transforms/CaseAmplification.java Sat Aug  9 14:55:03 2008
@@ -18,6 +18,9 @@
 package org.apache.mahout.cf.taste.impl.transforms;
 
 import org.apache.mahout.cf.taste.transforms.CorrelationTransform;
+import org.apache.mahout.cf.taste.common.Refreshable;
+
+import java.util.Collection;
 
 /**
  * <p>Applies "case amplification" to correlations. This essentially makes big values bigger
@@ -55,7 +58,7 @@
     return value < 0.0 ? -Math.pow(-value, factor) : Math.pow(value, factor);
   }
 
-  public void refresh() {
+  public void refresh(Collection<Refreshable> alreadyRefreshed) {
     // do nothing
   }
 

Modified: lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/transforms/InverseUserFrequency.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/transforms/InverseUserFrequency.java?rev=684358&r1=684357&r2=684358&view=diff
==============================================================================
--- lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/transforms/InverseUserFrequency.java (original)
+++ lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/transforms/InverseUserFrequency.java Sat Aug  9 14:55:03 2008
@@ -18,6 +18,7 @@
 package org.apache.mahout.cf.taste.impl.transforms;
 
 import org.apache.mahout.cf.taste.common.TasteException;
+import org.apache.mahout.cf.taste.common.Refreshable;
 import org.apache.mahout.cf.taste.model.DataModel;
 import org.apache.mahout.cf.taste.model.Item;
 import org.apache.mahout.cf.taste.model.Preference;
@@ -29,6 +30,7 @@
 
 import java.util.Collections;
 import java.util.Map;
+import java.util.Collection;
 import java.util.concurrent.atomic.AtomicReference;
 
 /**
@@ -60,7 +62,7 @@
    * @param logBase calculation logarithm base
    * @throws IllegalArgumentException if dataModel is <code>null</code> or logBase is {@link Double#NaN} or &lt;= 1.0
    */
-  public InverseUserFrequency(DataModel dataModel, double logBase) {
+  public InverseUserFrequency(DataModel dataModel, double logBase) throws TasteException {
     if (dataModel == null) {
       throw new IllegalArgumentException("dataModel is null");
     }
@@ -70,7 +72,7 @@
     this.dataModel = dataModel;
     this.logBase = logBase;
     this.iufFactors = new AtomicReference<Map<Item, Double>>(new FastMap<Item, Double>());
-    refresh();
+    recompute();
   }
 
   /**
@@ -88,29 +90,31 @@
     return pref.getValue();
   }
 
-  public void refresh() {
+  public void refresh(Collection<Refreshable> alreadyRefreshed) {
     try {
-      Counters<Item> itemPreferenceCounts = new Counters<Item>();
-      synchronized (this) {
-        int numUsers = 0;
-        for (User user : dataModel.getUsers()) {
-          Preference[] prefs = user.getPreferencesAsArray();
-          for (int i = 0; i < prefs.length; i++) {
-            itemPreferenceCounts.increment(prefs[i].getItem());
-          }
-          numUsers++;
-        }
-        Map<Item, Double> newIufFactors = new FastMap<Item, Double>(itemPreferenceCounts.size());
-        double logFactor = Math.log(logBase);
-        for (Map.Entry<Item, Counters.MutableInteger> entry : itemPreferenceCounts.getEntrySet()) {
-          newIufFactors.put(entry.getKey(),
-                            Math.log((double) numUsers / (double) entry.getValue().value) / logFactor);
-        }
-        iufFactors.set(Collections.unmodifiableMap(newIufFactors));
+      recompute();
+    } catch (TasteException te) {
+      log.warn("Unable to refresh", te);
+    }
+  }
+
+  private synchronized void recompute() throws TasteException {
+    Counters<Item> itemPreferenceCounts = new Counters<Item>();
+    int numUsers = 0;
+    for (User user : dataModel.getUsers()) {
+      Preference[] prefs = user.getPreferencesAsArray();
+      for (int i = 0; i < prefs.length; i++) {
+        itemPreferenceCounts.increment(prefs[i].getItem());
       }
-    } catch (TasteException dme) {
-      log.warn("Unable to refresh", dme);
+      numUsers++;
+    }
+    Map<Item, Double> newIufFactors = new FastMap<Item, Double>(itemPreferenceCounts.size());
+    double logFactor = Math.log(logBase);
+    for (Map.Entry<Item, Counters.MutableInteger> entry : itemPreferenceCounts.getEntrySet()) {
+      newIufFactors.put(entry.getKey(),
+                        Math.log((double) numUsers / (double) entry.getValue().value) / logFactor);
     }
+    iufFactors.set(Collections.unmodifiableMap(newIufFactors));
   }
 
   @Override

Modified: lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/transforms/ZScore.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/transforms/ZScore.java?rev=684358&r1=684357&r2=684358&view=diff
==============================================================================
--- lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/transforms/ZScore.java (original)
+++ lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/transforms/ZScore.java Sat Aug  9 14:55:03 2008
@@ -18,6 +18,7 @@
 package org.apache.mahout.cf.taste.impl.transforms;
 
 import org.apache.mahout.cf.taste.common.TasteException;
+import org.apache.mahout.cf.taste.common.Refreshable;
 import org.apache.mahout.cf.taste.impl.common.FullRunningAverageAndStdDev;
 import org.apache.mahout.cf.taste.impl.common.RunningAverageAndStdDev;
 import org.apache.mahout.cf.taste.impl.common.Cache;
@@ -26,6 +27,8 @@
 import org.apache.mahout.cf.taste.model.User;
 import org.apache.mahout.cf.taste.transforms.PreferenceTransform;
 
+import java.util.Collection;
+
 /**
  * <p>Normalizes preference values for a {@link User} by converting them to
  * <a href="http://mathworld.wolfram.com/z-Score.html">"z-scores"</a>. This process
@@ -43,7 +46,7 @@
 
   public ZScore() {
     this.meanAndStdevs = new Cache<User, RunningAverageAndStdDev>(new MeanStdevRetriever());
-    refresh();
+    refresh(null);
   }
 
   public double getTransformedValue(Preference pref) throws TasteException {
@@ -57,7 +60,7 @@
     return 0.0;
   }
 
-  public void refresh() {
+  public void refresh(Collection<Refreshable> alreadyRefreshed) {
     // do nothing
   }
 

Modified: lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/LoadTest.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/LoadTest.java?rev=684358&r1=684357&r2=684358&view=diff
==============================================================================
--- lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/LoadTest.java (original)
+++ lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/LoadTest.java Sat Aug  9 14:55:03 2008
@@ -140,7 +140,7 @@
       for (int i = 0; i < NUM_USERS / 2; i++) {
         recommender.recommend(String.valueOf(random.nextInt(NUM_USERS)), 10);
       }
-      recommender.refresh();
+      recommender.refresh(null);
       for (int i = NUM_USERS / 2; i < NUM_USERS; i++) {
         recommender.recommend(String.valueOf(random.nextInt(NUM_USERS)), 10);
       }

Added: lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/common/MockRefreshable.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/common/MockRefreshable.java?rev=684358&view=auto
==============================================================================
--- lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/common/MockRefreshable.java (added)
+++ lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/common/MockRefreshable.java Sat Aug  9 14:55:03 2008
@@ -0,0 +1,45 @@
+/**
+ * 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.common;
+
+import org.apache.mahout.cf.taste.common.Refreshable;
+
+import java.util.Collection;
+import java.util.concurrent.Callable;
+
+/**
+ * A mock {@link Refreshable} which counts the number of times it has been refreshed, for use in tests.
+ */
+final class MockRefreshable implements Refreshable, Callable<Object> {
+
+  private int callCount;
+
+  public void refresh(Collection<Refreshable> alreadyRefreshed) {
+    call();
+  }
+
+  public Object call() {
+    callCount++;
+    return null;
+  }
+
+  int getCallCount() {
+    return callCount;
+  }
+
+}

Added: lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/common/RefreshHelperTest.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/common/RefreshHelperTest.java?rev=684358&view=auto
==============================================================================
--- lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/common/RefreshHelperTest.java (added)
+++ lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/common/RefreshHelperTest.java Sat Aug  9 14:55:03 2008
@@ -0,0 +1,69 @@
+/**
+ * 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.common;
+
+import org.apache.mahout.cf.taste.impl.common.RefreshHelper;
+import org.apache.mahout.cf.taste.common.Refreshable;
+import junit.framework.TestCase;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Collection;
+
+/**
+ * Tests {@link RefreshHelper}
+ */
+public final class RefreshHelperTest extends TestCase {
+
+  public void testCallable() {
+    MockRefreshable mock = new MockRefreshable();
+    RefreshHelper helper = new RefreshHelper(mock);
+    helper.refresh(null);
+    assertEquals(1, mock.getCallCount());
+  }
+
+  public void testNoCallable() {
+    RefreshHelper helper = new RefreshHelper(null);
+    helper.refresh(null);
+  }
+
+  public void testDependencies() {
+    RefreshHelper helper = new RefreshHelper(null);
+    MockRefreshable mock1 = new MockRefreshable();
+    MockRefreshable mock2 = new MockRefreshable();
+    helper.addDependency(mock1);
+    helper.addDependency(mock2);
+    helper.refresh(null);
+    assertEquals(1, mock1.getCallCount());
+    assertEquals(1, mock2.getCallCount()) ;
+  }
+
+  public void testAlreadyRefreshed() {
+    RefreshHelper helper = new RefreshHelper(null);
+    MockRefreshable mock1 = new MockRefreshable();
+    MockRefreshable mock2 = new MockRefreshable();
+    helper.addDependency(mock1);
+    helper.addDependency(mock2);
+    Collection<Refreshable> alreadyRefreshed = new HashSet<Refreshable>(1);
+    alreadyRefreshed.add(mock1);
+    helper.refresh(alreadyRefreshed);
+    assertEquals(0, mock1.getCallCount());
+    assertEquals(1, mock2.getCallCount()) ;
+  }
+
+}

Modified: lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/correlation/EuclideanDistanceCorrelationTest.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/correlation/EuclideanDistanceCorrelationTest.java?rev=684358&r1=684357&r2=684358&view=diff
==============================================================================
--- lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/correlation/EuclideanDistanceCorrelationTest.java (original)
+++ lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/correlation/EuclideanDistanceCorrelationTest.java Sat Aug  9 14:55:03 2008
@@ -179,7 +179,7 @@
 
   public void testRefresh() throws TasteException {
     // Make sure this doesn't throw an exception
-    new EuclideanDistanceCorrelation(getDataModel()).refresh();
+    new EuclideanDistanceCorrelation(getDataModel()).refresh(null);
   }
 
 }
\ No newline at end of file