Author: srowen
Date: Sat Sep 25 18:59:51 2010
New Revision: 1001298
URL: http://svn.apache.org/viewvc?rev=1001298&view=rev
Log:
Simplify, standardize and in some cases fix much 'reload' logic, by having
constructors reload upfront
Added:
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/similarity/file/FileItemItemSimilarityIterable.java
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/similarity/file/FileItemItemSimilarityIterator.java
Modified:
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/common/RefreshHelper.java
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/model/file/FileDataModel.java
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/model/file/FileIDMigrator.java
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/ItemAverageRecommender.java
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/ItemUserAverageRecommender.java
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/TreeClusteringRecommender.java
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/TreeClusteringRecommender2.java
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/slopeone/file/FileDiffStorage.java
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/similarity/file/FileItemSimilarity.java
mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/similarity/file/FileItemSimilarityTest.java
Modified:
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/common/RefreshHelper.java
URL:
http://svn.apache.org/viewvc/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/common/RefreshHelper.java?rev=1001298&r1=1001297&r2=1001298&view=diff
==============================================================================
---
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/common/RefreshHelper.java
(original)
+++
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/common/RefreshHelper.java
Sat Sep 25 18:59:51 2010
@@ -71,8 +71,7 @@ public final class RefreshHelper impleme
*/
@Override
public void refresh(Collection<Refreshable> alreadyRefreshed) {
- if (!refreshLock.isLocked()) {
- refreshLock.lock();
+ if (refreshLock.tryLock()) {
try {
alreadyRefreshed = buildRefreshed(alreadyRefreshed);
for (Refreshable dependency : dependencies) {
Modified:
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/model/file/FileDataModel.java
URL:
http://svn.apache.org/viewvc/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/model/file/FileDataModel.java?rev=1001298&r1=1001297&r2=1001298&view=diff
==============================================================================
---
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/model/file/FileDataModel.java
(original)
+++
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/model/file/FileDataModel.java
Sat Sep 25 18:59:51 2010
@@ -125,7 +125,6 @@ public class FileDataModel extends Abstr
private final char delimiter;
private final Pattern delimiterPattern;
private final boolean hasPrefValues;
- private boolean loaded;
private DataModel delegate;
private final ReentrantLock reloadLock;
private final boolean transpose;
@@ -186,6 +185,8 @@ public class FileDataModel extends Abstr
this.reloadLock = new ReentrantLock();
this.transpose = transpose;
this.minReloadIntervalMS = minReloadIntervalMS;
+
+ reload();
}
public File getDataFile() {
@@ -197,11 +198,9 @@ public class FileDataModel extends Abstr
}
protected void reload() {
- if (!reloadLock.isLocked()) {
- reloadLock.lock();
+ if (reloadLock.tryLock()) {
try {
delegate = buildModel();
- loaded = true;
} catch (IOException ioe) {
log.warn("Exception while reloading", ioe);
} finally {
@@ -598,11 +597,6 @@ public class FileDataModel extends Abstr
itemTimestamps.remove(itemID);
}
}
- private void checkLoaded() {
- if (!loaded) {
- reload();
- }
- }
/**
* Subclasses may wish to override this if ID values in the file are not
numeric. This provides a hook by
@@ -632,61 +626,51 @@ public class FileDataModel extends Abstr
@Override
public LongPrimitiveIterator getUserIDs() throws TasteException {
- checkLoaded();
return delegate.getUserIDs();
}
@Override
public PreferenceArray getPreferencesFromUser(long userID) throws
TasteException {
- checkLoaded();
return delegate.getPreferencesFromUser(userID);
}
@Override
public FastIDSet getItemIDsFromUser(long userID) throws TasteException {
- checkLoaded();
return delegate.getItemIDsFromUser(userID);
}
@Override
public LongPrimitiveIterator getItemIDs() throws TasteException {
- checkLoaded();
return delegate.getItemIDs();
}
@Override
public PreferenceArray getPreferencesForItem(long itemID) throws
TasteException {
- checkLoaded();
return delegate.getPreferencesForItem(itemID);
}
@Override
public Float getPreferenceValue(long userID, long itemID) throws
TasteException {
- checkLoaded();
return delegate.getPreferenceValue(userID, itemID);
}
@Override
public Long getPreferenceTime(long userID, long itemID) throws
TasteException {
- checkLoaded();
return delegate.getPreferenceTime(userID, itemID);
}
@Override
public int getNumItems() throws TasteException {
- checkLoaded();
return delegate.getNumItems();
}
@Override
public int getNumUsers() throws TasteException {
- checkLoaded();
return delegate.getNumUsers();
}
@Override
public int getNumUsersWithPreferenceFor(long... itemIDs) throws
TasteException {
- checkLoaded();
return delegate.getNumUsersWithPreferenceFor(itemIDs);
}
@@ -698,14 +682,12 @@ public class FileDataModel extends Abstr
*/
@Override
public void setPreference(long userID, long itemID, float value) throws
TasteException {
- checkLoaded();
delegate.setPreference(userID, itemID, value);
}
/** See the warning at {...@link #setPreference(long, long, float)}. */
@Override
public void removePreference(long userID, long itemID) throws TasteException
{
- checkLoaded();
delegate.removePreference(userID, itemID);
}
@@ -720,19 +702,16 @@ public class FileDataModel extends Abstr
@Override
public boolean hasPreferenceValues() {
- checkLoaded();
return delegate.hasPreferenceValues();
}
@Override
public float getMaxPreference() {
- checkLoaded();
return delegate.getMaxPreference();
}
@Override
public float getMinPreference() {
- checkLoaded();
return delegate.getMinPreference();
}
Modified:
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/model/file/FileIDMigrator.java
URL:
http://svn.apache.org/viewvc/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/model/file/FileIDMigrator.java?rev=1001298&r1=1001297&r2=1001298&view=diff
==============================================================================
---
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/model/file/FileIDMigrator.java
(original)
+++
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/model/file/FileIDMigrator.java
Sat Sep 25 18:59:51 2010
@@ -46,11 +46,10 @@ public class FileIDMigrator extends Abst
public static final long DEFAULT_MIN_RELOAD_INTERVAL_MS = 60 * 1000L; // 1
minute?
private final File dataFile;
- private final FastByIDMap<String> longToString;
+ private FastByIDMap<String> longToString;
private final ReentrantLock reloadLock;
private long lastModified;
- private boolean loaded;
private long minReloadIntervalMS;
private static final Logger log =
LoggerFactory.getLogger(FileIDMigrator.class);
@@ -60,7 +59,6 @@ public class FileIDMigrator extends Abst
}
public FileIDMigrator(File dataFile, long minReloadIntervalMS) throws
FileNotFoundException {
- super();
longToString = new FastByIDMap<String>(100);
if (dataFile == null) {
throw new IllegalArgumentException("dataFile is null");
@@ -74,30 +72,20 @@ public class FileIDMigrator extends Abst
this.dataFile = dataFile;
this.reloadLock = new ReentrantLock();
this.lastModified = dataFile.lastModified();
- this.loaded = false;
this.minReloadIntervalMS = minReloadIntervalMS;
+
+ reload();
}
@Override
public String toStringID(long longID) {
- if (!loaded) {
- reload();
- }
- synchronized (longToString) {
- return longToString.get(longID);
- }
+ return longToString.get(longID);
}
private void reload() {
- if (!reloadLock.isLocked()) {
- reloadLock.lock();
+ if (reloadLock.tryLock()) {
try {
- longToString.clear();
- for (String line : new FileLineIterable(dataFile)) {
- longToString.put(toLongID(line), line);
- }
- lastModified = dataFile.lastModified();
- loaded = true;
+ longToString = buildMapping();
} catch (IOException ioe) {
throw new IllegalStateException(ioe);
} finally {
@@ -106,9 +94,18 @@ public class FileIDMigrator extends Abst
}
}
+ private FastByIDMap<String> buildMapping() throws IOException {
+ FastByIDMap<String> mapping = new FastByIDMap<String>();
+ for (String line : new FileLineIterable(dataFile)) {
+ mapping.put(toLongID(line), line);
+ }
+ lastModified = dataFile.lastModified();
+ return mapping;
+ }
+
@Override
public void refresh(Collection<Refreshable> alreadyRefreshed) {
- if (!loaded || dataFile.lastModified() > lastModified +
minReloadIntervalMS) {
+ if (dataFile.lastModified() > lastModified + minReloadIntervalMS) {
log.debug("File has changed; reloading...");
reload();
}
Modified:
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/ItemAverageRecommender.java
URL:
http://svn.apache.org/viewvc/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/ItemAverageRecommender.java?rev=1001298&r1=1001297&r2=1001298&view=diff
==============================================================================
---
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/ItemAverageRecommender.java
(original)
+++
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/ItemAverageRecommender.java
Sat Sep 25 18:59:51 2010
@@ -51,11 +51,10 @@ public final class ItemAverageRecommende
private static final Logger log =
LoggerFactory.getLogger(ItemAverageRecommender.class);
private final FastByIDMap<RunningAverage> itemAverages;
- private boolean averagesBuilt;
private final ReadWriteLock buildAveragesLock;
private final RefreshHelper refreshHelper;
- public ItemAverageRecommender(DataModel dataModel) {
+ public ItemAverageRecommender(DataModel dataModel) throws TasteException {
super(dataModel);
this.itemAverages = new FastByIDMap<RunningAverage>();
this.buildAveragesLock = new ReentrantReadWriteLock();
@@ -67,6 +66,7 @@ public final class ItemAverageRecommende
}
});
refreshHelper.addDependency(dataModel);
+ buildAverageDiffs();
}
@Override
@@ -75,8 +75,7 @@ public final class ItemAverageRecommende
throw new IllegalArgumentException("howMany must be at least 1");
}
log.debug("Recommending items for user ID '{}'", userID);
- checkAverageDiffsBuilt();
-
+
FastIDSet possibleItemIDs = getAllOtherItems(userID);
TopItems.Estimator<Long> estimator = new Estimator();
@@ -95,7 +94,6 @@ public final class ItemAverageRecommende
if (actualPref != null) {
return actualPref;
}
- checkAverageDiffsBuilt();
return doEstimatePreference(itemID);
}
@@ -109,12 +107,6 @@ public final class ItemAverageRecommende
}
}
- private void checkAverageDiffsBuilt() throws TasteException {
- if (!averagesBuilt) {
- buildAverageDiffs();
- }
- }
-
private void buildAverageDiffs() throws TasteException {
try {
buildAveragesLock.writeLock().lock();
@@ -133,7 +125,6 @@ public final class ItemAverageRecommende
average.addDatum(prefs.getValue(i));
}
}
- averagesBuilt = true;
} finally {
buildAveragesLock.writeLock().unlock();
}
Modified:
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/ItemUserAverageRecommender.java
URL:
http://svn.apache.org/viewvc/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/ItemUserAverageRecommender.java?rev=1001298&r1=1001297&r2=1001298&view=diff
==============================================================================
---
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/ItemUserAverageRecommender.java
(original)
+++
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/ItemUserAverageRecommender.java
Sat Sep 25 18:59:51 2010
@@ -54,11 +54,10 @@ public final class ItemUserAverageRecomm
private final FastByIDMap<RunningAverage> itemAverages;
private final FastByIDMap<RunningAverage> userAverages;
private final RunningAverage overallAveragePrefValue;
- private boolean averagesBuilt;
private final ReadWriteLock buildAveragesLock;
private final RefreshHelper refreshHelper;
- public ItemUserAverageRecommender(DataModel dataModel) {
+ public ItemUserAverageRecommender(DataModel dataModel) throws TasteException
{
super(dataModel);
this.itemAverages = new FastByIDMap<RunningAverage>();
this.userAverages = new FastByIDMap<RunningAverage>();
@@ -72,6 +71,7 @@ public final class ItemUserAverageRecomm
}
});
refreshHelper.addDependency(dataModel);
+ buildAverageDiffs();
}
@Override
@@ -80,8 +80,7 @@ public final class ItemUserAverageRecomm
throw new IllegalArgumentException("howMany must be at least 1");
}
log.debug("Recommending items for user ID '{}'", userID);
- checkAverageDiffsBuilt();
-
+
FastIDSet possibleItemIDs = getAllOtherItems(userID);
TopItems.Estimator<Long> estimator = new Estimator(userID);
@@ -100,7 +99,6 @@ public final class ItemUserAverageRecomm
if (actualPref != null) {
return actualPref;
}
- checkAverageDiffsBuilt();
return doEstimatePreference(userID, itemID);
}
@@ -121,13 +119,7 @@ public final class ItemUserAverageRecomm
buildAveragesLock.readLock().unlock();
}
}
-
- private void checkAverageDiffsBuilt() throws TasteException {
- if (!averagesBuilt) {
- buildAverageDiffs();
- }
- }
-
+
private void buildAverageDiffs() throws TasteException {
try {
buildAveragesLock.writeLock().lock();
@@ -145,7 +137,6 @@ public final class ItemUserAverageRecomm
overallAveragePrefValue.addDatum(value);
}
}
- averagesBuilt = true;
} finally {
buildAveragesLock.writeLock().unlock();
}
Modified:
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/TreeClusteringRecommender.java
URL:
http://svn.apache.org/viewvc/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/TreeClusteringRecommender.java?rev=1001298&r1=1001297&r2=1001298&view=diff
==============================================================================
---
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/TreeClusteringRecommender.java
(original)
+++
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/TreeClusteringRecommender.java
Sat Sep 25 18:59:51 2010
@@ -23,7 +23,6 @@ import java.util.Collections;
import java.util.List;
import java.util.Random;
import java.util.concurrent.Callable;
-import java.util.concurrent.locks.ReentrantLock;
import org.apache.mahout.cf.taste.common.Refreshable;
import org.apache.mahout.cf.taste.common.TasteException;
@@ -74,8 +73,6 @@ public final class TreeClusteringRecomme
private FastByIDMap<List<RecommendedItem>> topRecsByUserID;
private FastIDSet[] allClusters;
private FastByIDMap<FastIDSet> clustersByUserID;
- private boolean clustersBuilt;
- private final ReentrantLock buildClustersLock;
private final RefreshHelper refreshHelper;
/**
@@ -88,7 +85,8 @@ public final class TreeClusteringRecomme
* @throws IllegalArgumentException
* if arguments are <code>null</code>, or <code>numClusters</code>
is less than 2
*/
- public TreeClusteringRecommender(DataModel dataModel, ClusterSimilarity
clusterSimilarity, int numClusters) {
+ public TreeClusteringRecommender(DataModel dataModel, ClusterSimilarity
clusterSimilarity, int numClusters)
+ throws TasteException {
this(dataModel, clusterSimilarity, numClusters, 1.0);
}
@@ -109,7 +107,7 @@ public final class TreeClusteringRecomme
public TreeClusteringRecommender(DataModel dataModel,
ClusterSimilarity clusterSimilarity,
int numClusters,
- double samplingRate) {
+ double samplingRate) throws TasteException {
super(dataModel);
if (clusterSimilarity == null) {
throw new IllegalArgumentException("clusterSimilarity is null");
@@ -125,7 +123,6 @@ public final class TreeClusteringRecomme
this.clusteringThreshold = Double.NaN;
this.clusteringByThreshold = false;
this.samplingRate = samplingRate;
- this.buildClustersLock = new ReentrantLock();
this.refreshHelper = new RefreshHelper(new Callable<Object>() {
@Override
public Object call() throws TasteException {
@@ -135,6 +132,7 @@ public final class TreeClusteringRecomme
});
refreshHelper.addDependency(dataModel);
refreshHelper.addDependency(clusterSimilarity);
+ buildClusters();
}
/**
@@ -150,7 +148,7 @@ public final class TreeClusteringRecomme
*/
public TreeClusteringRecommender(DataModel dataModel,
ClusterSimilarity clusterSimilarity,
- double clusteringThreshold) {
+ double clusteringThreshold) throws
TasteException {
this(dataModel, clusterSimilarity, clusteringThreshold, 1.0);
}
@@ -172,7 +170,7 @@ public final class TreeClusteringRecomme
public TreeClusteringRecommender(DataModel dataModel,
ClusterSimilarity clusterSimilarity,
double clusteringThreshold,
- double samplingRate) {
+ double samplingRate) throws TasteException {
super(dataModel);
if (clusterSimilarity == null) {
throw new IllegalArgumentException("clusterSimilarity is null");
@@ -188,7 +186,6 @@ public final class TreeClusteringRecomme
this.clusteringThreshold = clusteringThreshold;
this.clusteringByThreshold = true;
this.samplingRate = samplingRate;
- this.buildClustersLock = new ReentrantLock();
this.refreshHelper = new RefreshHelper(new Callable<Object>() {
@Override
public Object call() throws TasteException {
@@ -198,6 +195,7 @@ public final class TreeClusteringRecomme
});
refreshHelper.addDependency(dataModel);
refreshHelper.addDependency(clusterSimilarity);
+ buildClusters();
}
@Override
@@ -267,39 +265,27 @@ public final class TreeClusteringRecomme
}
private void buildClusters() throws TasteException {
- if (clustersBuilt) {
- return;
- }
- buildClustersLock.lock();
- try {
- if (clustersBuilt) {
- return;
- }
- DataModel model = getDataModel();
- int numUsers = model.getNumUsers();
- if (numUsers > 0) {
- List<FastIDSet> newClusters = new ArrayList<FastIDSet>(numUsers);
- // Begin with a cluster for each user:
- LongPrimitiveIterator it = model.getUserIDs();
- while (it.hasNext()) {
- FastIDSet newCluster = new FastIDSet();
- newCluster.add(it.nextLong());
- newClusters.add(newCluster);
- }
- if (numUsers > 1) {
- findClusters(newClusters);
- }
- topRecsByUserID = computeTopRecsPerUserID(newClusters);
- clustersByUserID = computeClustersPerUserID(newClusters);
- allClusters = newClusters.toArray(new FastIDSet[newClusters.size()]);
- } else {
- topRecsByUserID = new FastByIDMap<List<RecommendedItem>>();
- clustersByUserID = new FastByIDMap<FastIDSet>();
- allClusters = NO_CLUSTERS;
- }
- clustersBuilt = true;
- } finally {
- buildClustersLock.unlock();
+ DataModel model = getDataModel();
+ int numUsers = model.getNumUsers();
+ if (numUsers > 0) {
+ List<FastIDSet> newClusters = new ArrayList<FastIDSet>(numUsers);
+ // Begin with a cluster for each user:
+ LongPrimitiveIterator it = model.getUserIDs();
+ while (it.hasNext()) {
+ FastIDSet newCluster = new FastIDSet();
+ newCluster.add(it.nextLong());
+ newClusters.add(newCluster);
+ }
+ if (numUsers > 1) {
+ findClusters(newClusters);
+ }
+ topRecsByUserID = computeTopRecsPerUserID(newClusters);
+ clustersByUserID = computeClustersPerUserID(newClusters);
+ allClusters = newClusters.toArray(new FastIDSet[newClusters.size()]);
+ } else {
+ topRecsByUserID = new FastByIDMap<List<RecommendedItem>>();
+ clustersByUserID = new FastByIDMap<FastIDSet>();
+ allClusters = NO_CLUSTERS;
}
}
Modified:
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/TreeClusteringRecommender2.java
URL:
http://svn.apache.org/viewvc/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/TreeClusteringRecommender2.java?rev=1001298&r1=1001297&r2=1001298&view=diff
==============================================================================
---
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/TreeClusteringRecommender2.java
(original)
+++
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/TreeClusteringRecommender2.java
Sat Sep 25 18:59:51 2010
@@ -26,7 +26,6 @@ import java.util.ListIterator;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.concurrent.Callable;
-import java.util.concurrent.locks.ReentrantLock;
import org.apache.mahout.cf.taste.common.Refreshable;
import org.apache.mahout.cf.taste.common.TasteException;
@@ -80,8 +79,6 @@ public final class TreeClusteringRecomme
private FastByIDMap<List<RecommendedItem>> topRecsByUserID;
private FastIDSet[] allClusters;
private FastByIDMap<FastIDSet> clustersByUserID;
- private boolean clustersBuilt;
- private final ReentrantLock buildClustersLock;
private final RefreshHelper refreshHelper;
/**
@@ -94,7 +91,8 @@ public final class TreeClusteringRecomme
* @throws IllegalArgumentException
* if arguments are <code>null</code>, or <code>numClusters</code>
is less than 2
*/
- public TreeClusteringRecommender2(DataModel dataModel, ClusterSimilarity
clusterSimilarity, int numClusters) {
+ public TreeClusteringRecommender2(DataModel dataModel, ClusterSimilarity
clusterSimilarity, int numClusters)
+ throws TasteException {
super(dataModel);
if (clusterSimilarity == null) {
throw new IllegalArgumentException("clusterSimilarity is null");
@@ -106,7 +104,6 @@ public final class TreeClusteringRecomme
this.numClusters = numClusters;
this.clusteringThreshold = Double.NaN;
this.clusteringByThreshold = false;
- this.buildClustersLock = new ReentrantLock();
this.refreshHelper = new RefreshHelper(new Callable<Object>() {
@Override
public Object call() throws TasteException {
@@ -116,6 +113,7 @@ public final class TreeClusteringRecomme
});
refreshHelper.addDependency(dataModel);
refreshHelper.addDependency(clusterSimilarity);
+ buildClusters();
}
/**
@@ -132,7 +130,7 @@ public final class TreeClusteringRecomme
*/
public TreeClusteringRecommender2(DataModel dataModel,
ClusterSimilarity clusterSimilarity,
- double clusteringThreshold) {
+ double clusteringThreshold) throws
TasteException {
super(dataModel);
if (clusterSimilarity == null) {
throw new IllegalArgumentException("clusterSimilarity is null");
@@ -144,7 +142,6 @@ public final class TreeClusteringRecomme
this.numClusters = Integer.MIN_VALUE;
this.clusteringThreshold = clusteringThreshold;
this.clusteringByThreshold = true;
- this.buildClustersLock = new ReentrantLock();
this.refreshHelper = new RefreshHelper(new Callable<Object>() {
@Override
public Object call() throws TasteException {
@@ -154,6 +151,7 @@ public final class TreeClusteringRecomme
});
refreshHelper.addDependency(dataModel);
refreshHelper.addDependency(clusterSimilarity);
+ buildClusters();
}
@Override
@@ -276,47 +274,34 @@ public final class TreeClusteringRecomme
}
private void buildClusters() throws TasteException {
- if (clustersBuilt) {
- return;
- }
- buildClustersLock.lock();
- try {
- if (clustersBuilt) {
- return;
+ DataModel model = getDataModel();
+ int numUsers = model.getNumUsers();
+
+ if (numUsers == 0) {
+
+ topRecsByUserID = new FastByIDMap<List<RecommendedItem>>();
+ clustersByUserID = new FastByIDMap<FastIDSet>();
+
+ } else {
+
+ List<FastIDSet> clusters = new ArrayList<FastIDSet>();
+ // Begin with a cluster for each user:
+ LongPrimitiveIterator it = model.getUserIDs();
+ while (it.hasNext()) {
+ FastIDSet newCluster = new FastIDSet();
+ newCluster.add(it.nextLong());
+ clusters.add(newCluster);
}
- DataModel model = getDataModel();
- int numUsers = model.getNumUsers();
-
- if (numUsers == 0) {
-
- topRecsByUserID = new FastByIDMap<List<RecommendedItem>>();
- clustersByUserID = new FastByIDMap<FastIDSet>();
-
- } else {
-
- List<FastIDSet> clusters = new ArrayList<FastIDSet>();
- // Begin with a cluster for each user:
- LongPrimitiveIterator it = model.getUserIDs();
- while (it.hasNext()) {
- FastIDSet newCluster = new FastIDSet();
- newCluster.add(it.nextLong());
- clusters.add(newCluster);
- }
-
- boolean done = false;
- while (!done) {
- done = mergeClosestClusters(numUsers, clusters, done);
- }
-
- topRecsByUserID = computeTopRecsPerUserID(clusters);
- clustersByUserID = computeClustersPerUserID(clusters);
- allClusters = clusters.toArray(new FastIDSet[clusters.size()]);
-
+
+ boolean done = false;
+ while (!done) {
+ done = mergeClosestClusters(numUsers, clusters, done);
}
-
- clustersBuilt = true;
- } finally {
- buildClustersLock.unlock();
+
+ topRecsByUserID = computeTopRecsPerUserID(clusters);
+ clustersByUserID = computeClustersPerUserID(clusters);
+ allClusters = clusters.toArray(new FastIDSet[clusters.size()]);
+
}
}
Modified:
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/slopeone/file/FileDiffStorage.java
URL:
http://svn.apache.org/viewvc/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/slopeone/file/FileDiffStorage.java?rev=1001298&r1=1001297&r2=1001298&view=diff
==============================================================================
---
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/slopeone/file/FileDiffStorage.java
(original)
+++
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/slopeone/file/FileDiffStorage.java
Sat Sep 25 18:59:51 2010
@@ -62,7 +62,6 @@ public final class FileDiffStorage imple
private final File dataFile;
private long lastModified;
- private boolean loaded;
private final long maxEntries;
private final FastByIDMap<FastByIDMap<RunningAverage>> averageDiffs;
private final FastIDSet allRecommendableItemIDs;
@@ -95,6 +94,8 @@ public final class FileDiffStorage imple
this.averageDiffs = new FastByIDMap<FastByIDMap<RunningAverage>>();
this.allRecommendableItemIDs = new FastIDSet();
this.buildAverageDiffsLock = new ReentrantReadWriteLock();
+
+ buildDiffs();
}
private void buildDiffs() {
@@ -206,17 +207,9 @@ public final class FileDiffStorage imple
allRecommendableItemIDs.rehash();
}
- private void checkLoaded() {
- if (!loaded) {
- buildDiffs();
- loaded = true;
- }
- }
-
@Override
public RunningAverage getDiff(long itemID1, long itemID2) {
- checkLoaded();
-
+
boolean inverted = false;
if (itemID1 > itemID2) {
inverted = true;
@@ -248,7 +241,6 @@ public final class FileDiffStorage imple
@Override
public RunningAverage[] getDiffs(long userID, long itemID, PreferenceArray
prefs) {
- checkLoaded();
try {
buildAverageDiffsLock.readLock().lock();
int size = prefs.length();
@@ -264,13 +256,11 @@ public final class FileDiffStorage imple
@Override
public RunningAverage getAverageItemPref(long itemID) {
- checkLoaded();
return null; // TODO can't do this without a DataModel
}
@Override
public void updateItemPref(long itemID, float prefDelta, boolean remove) {
- checkLoaded();
try {
buildAverageDiffsLock.readLock().lock();
for (Map.Entry<Long,FastByIDMap<RunningAverage>> entry :
averageDiffs.entrySet()) {
@@ -303,7 +293,6 @@ public final class FileDiffStorage imple
@Override
public FastIDSet getRecommendableItemIDs(long userID) {
- checkLoaded();
try {
buildAverageDiffsLock.readLock().lock();
return allRecommendableItemIDs.clone();
Added:
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/similarity/file/FileItemItemSimilarityIterable.java
URL:
http://svn.apache.org/viewvc/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/similarity/file/FileItemItemSimilarityIterable.java?rev=1001298&view=auto
==============================================================================
---
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/similarity/file/FileItemItemSimilarityIterable.java
(added)
+++
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/similarity/file/FileItemItemSimilarityIterable.java
Sat Sep 25 18:59:51 2010
@@ -0,0 +1,46 @@
+/*
+ * 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.similarity.file;
+
+import org.apache.mahout.cf.taste.impl.similarity.GenericItemSimilarity;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Iterator;
+
+/**
+ * {...@link Iterable} to be able to read a file linewise into a {...@link
GenericItemSimilarity}
+ */
+final class FileItemItemSimilarityIterable implements
Iterable<GenericItemSimilarity.ItemItemSimilarity> {
+
+ private final File similaritiesFile;
+
+ FileItemItemSimilarityIterable(File similaritiesFile) {
+ this.similaritiesFile = similaritiesFile;
+ }
+
+ @Override
+ public Iterator<GenericItemSimilarity.ItemItemSimilarity> iterator() {
+ try {
+ return new FileItemItemSimilarityIterator(similaritiesFile);
+ } catch (IOException ioe) {
+ throw new IllegalStateException("Can't read " + similaritiesFile);
+ }
+ }
+
+}
Added:
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/similarity/file/FileItemItemSimilarityIterator.java
URL:
http://svn.apache.org/viewvc/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/similarity/file/FileItemItemSimilarityIterator.java?rev=1001298&view=auto
==============================================================================
---
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/similarity/file/FileItemItemSimilarityIterator.java
(added)
+++
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/similarity/file/FileItemItemSimilarityIterator.java
Sat Sep 25 18:59:51 2010
@@ -0,0 +1,60 @@
+/*
+ * 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.similarity.file;
+
+import org.apache.mahout.cf.taste.impl.similarity.GenericItemSimilarity;
+import org.apache.mahout.common.FileLineIterator;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.regex.Pattern;
+
+/**
+ * a simple iterator using a {...@link
org.apache.mahout.common.FileLineIterator} internally, parsing each
+ * line into an {...@link
org.apache.mahout.cf.taste.impl.similarity.GenericItemSimilarity.ItemItemSimilarity}
+ */
+final class FileItemItemSimilarityIterator implements
Iterator<GenericItemSimilarity.ItemItemSimilarity> {
+
+ private static final Pattern SEPARATOR = Pattern.compile("[,\t]");
+
+ private final FileLineIterator lineIterator;
+
+ FileItemItemSimilarityIterator(File similaritiesFile) throws IOException {
+ lineIterator = new FileLineIterator(similaritiesFile);
+ }
+
+ @Override
+ public boolean hasNext() {
+ return lineIterator.hasNext();
+ }
+
+ @Override
+ public GenericItemSimilarity.ItemItemSimilarity next() {
+ String line = lineIterator.next();
+ String[] tokens = SEPARATOR.split(line);
+ return new
GenericItemSimilarity.ItemItemSimilarity(Long.parseLong(tokens[0]),
+
Long.parseLong(tokens[1]),
+
Double.parseDouble(tokens[2]));
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+}
Modified:
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/similarity/file/FileItemSimilarity.java
URL:
http://svn.apache.org/viewvc/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/similarity/file/FileItemSimilarity.java?rev=1001298&r1=1001297&r2=1001298&view=diff
==============================================================================
---
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/similarity/file/FileItemSimilarity.java
(original)
+++
mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/similarity/file/FileItemSimilarity.java
Sat Sep 25 18:59:51 2010
@@ -18,19 +18,13 @@
package org.apache.mahout.cf.taste.impl.similarity.file;
import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
import java.util.Collection;
-import java.util.Iterator;
import java.util.concurrent.locks.ReentrantLock;
-import java.util.regex.Pattern;
import org.apache.mahout.cf.taste.common.Refreshable;
import org.apache.mahout.cf.taste.common.TasteException;
import org.apache.mahout.cf.taste.impl.similarity.GenericItemSimilarity;
-import
org.apache.mahout.cf.taste.impl.similarity.GenericItemSimilarity.ItemItemSimilarity;
import org.apache.mahout.cf.taste.similarity.ItemSimilarity;
-import org.apache.mahout.common.FileLineIterator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -65,7 +59,6 @@ public class FileItemSimilarity implemen
private final ReentrantLock reloadLock;
private final File dataFile;
private long lastModified;
- private boolean loaded;
private final long minReloadIntervalMS;
private static final Logger log =
LoggerFactory.getLogger(FileItemSimilarity.class);
@@ -73,9 +66,8 @@ public class FileItemSimilarity implemen
/**
* @param dataFile
* file containing the similarity data
- * @throws IOException
*/
- public FileItemSimilarity(File dataFile) throws IOException {
+ public FileItemSimilarity(File dataFile) {
this(dataFile, DEFAULT_MIN_RELOAD_INTERVAL_MS);
}
@@ -85,57 +77,48 @@ public class FileItemSimilarity implemen
* when refresh() is called
* @see #FileItemSimilarity(File)
*/
- public FileItemSimilarity(File dataFile, long minReloadIntervalMS) throws
IOException {
+ public FileItemSimilarity(File dataFile, long minReloadIntervalMS) {
if (dataFile == null) {
throw new IllegalArgumentException("dataFile is null");
}
if (!dataFile.exists() || dataFile.isDirectory()) {
- throw new FileNotFoundException(dataFile.toString());
+ throw new IllegalArgumentException("dataFile is missing or a directory:
" + dataFile);
}
log.info("Creating FileItemSimilarity for file {}", dataFile);
this.dataFile = dataFile.getAbsoluteFile();
this.lastModified = dataFile.lastModified();
- this.loaded = false;
this.minReloadIntervalMS = minReloadIntervalMS;
this.reloadLock = new ReentrantLock();
+
+ reload();
}
@Override
public double[] itemSimilarities(long itemID1, long[] itemID2s) throws
TasteException {
- checkLoaded();
return delegate.itemSimilarities(itemID1, itemID2s);
}
@Override
public double itemSimilarity(long itemID1, long itemID2) throws
TasteException {
- checkLoaded();
return delegate.itemSimilarity(itemID1, itemID2);
}
@Override
public void refresh(Collection<Refreshable> alreadyRefreshed) {
- if (delegate == null || dataFile.lastModified() > lastModified +
minReloadIntervalMS) {
+ if (dataFile.lastModified() > lastModified + minReloadIntervalMS) {
log.debug("File has changed; reloading...");
reload();
}
}
- private void checkLoaded() {
- if (!loaded) {
- reload();
- }
- }
-
protected void reload() {
- if (!reloadLock.isLocked()) {
- reloadLock.lock();
+ if (reloadLock.tryLock()) {
try {
long newLastModified = dataFile.lastModified();
delegate = new GenericItemSimilarity(new
FileItemItemSimilarityIterable(dataFile));
lastModified = newLastModified;
- loaded = true;
} finally {
reloadLock.unlock();
}
@@ -147,58 +130,4 @@ public class FileItemSimilarity implemen
return "FileItemSimilarity[dataFile:" + dataFile + ']';
}
- /**
- * {...@link Iterable} to be able to read a file linewise into a {...@link
GenericItemSimilarity}
- */
- static class FileItemItemSimilarityIterable implements
Iterable<ItemItemSimilarity> {
-
- private final File similaritiesFile;
-
- FileItemItemSimilarityIterable(File similaritiesFile) {
- this.similaritiesFile = similaritiesFile;
- }
-
- @Override
- public Iterator<ItemItemSimilarity> iterator() {
- return new FileItemItemSimilarityIterator(similaritiesFile);
- }
-
- /**
- * a simple iterator using a {...@link FileLineIterator} internally,
parsing each
- * line into an {...@link ItemItemSimilarity}
- */
- static class FileItemItemSimilarityIterator implements
Iterator<ItemItemSimilarity> {
-
- private static final Pattern SEPARATOR = Pattern.compile("[,\t]");
-
- private final FileLineIterator lineIterator;
-
- FileItemItemSimilarityIterator(File similaritiesFile) {
- try {
- lineIterator = new FileLineIterator(similaritiesFile);
- } catch (IOException e) {
- throw new IllegalArgumentException("Cannot read similarities file",
e);
- }
- }
-
- @Override
- public boolean hasNext() {
- return lineIterator.hasNext();
- }
-
- @Override
- public ItemItemSimilarity next() {
- String line = lineIterator.next();
- String[] tokens = SEPARATOR.split(line);
- return new ItemItemSimilarity(Long.parseLong(tokens[0]),
Long.parseLong(tokens[1]),
- Double.parseDouble(tokens[2]));
- }
-
- @Override
- public void remove() {
- throw new UnsupportedOperationException();
- }
- }
-
- }
}
Modified:
mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/similarity/file/FileItemSimilarityTest.java
URL:
http://svn.apache.org/viewvc/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/similarity/file/FileItemSimilarityTest.java?rev=1001298&r1=1001297&r2=1001298&view=diff
==============================================================================
---
mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/similarity/file/FileItemSimilarityTest.java
(original)
+++
mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/similarity/file/FileItemSimilarityTest.java
Sat Sep 25 18:59:51 2010
@@ -18,7 +18,6 @@
package org.apache.mahout.cf.taste.impl.similarity.file;
import java.io.File;
-import java.io.FileNotFoundException;
import org.apache.mahout.cf.taste.impl.TasteTestCase;
import org.apache.mahout.cf.taste.impl.similarity.GenericItemSimilarity;
@@ -110,16 +109,14 @@ public final class FileItemSimilarityTes
assertEquals(0.112, similarity.itemSimilarity(8L, 7L), EPSILON);
}
- @Test
+ @Test(expected = IllegalArgumentException.class)
public void testFileNotFoundExceptionForNonExistingFile() throws Exception {
- try {
- new FileItemSimilarity(new File("xKsdfksdfsdf"));
- fail();
- } catch (FileNotFoundException e) {}
+ new FileItemSimilarity(new File("xKsdfksdfsdf"));
}
+ @Test
public void testFileItemItemSimilarityIterable() throws Exception {
- Iterable<ItemItemSimilarity> similarityIterable = new
FileItemSimilarity.FileItemItemSimilarityIterable(testFile);
+ Iterable<ItemItemSimilarity> similarityIterable = new
FileItemItemSimilarityIterable(testFile);
GenericItemSimilarity similarity = new
GenericItemSimilarity(similarityIterable);
assertEquals(0.125, similarity.itemSimilarity(1L, 5L), EPSILON);