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 <= 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