Author: srowen
Date: Tue Apr 21 10:44:32 2009
New Revision: 767110
URL: http://svn.apache.org/viewvc?rev=767110&view=rev
Log:
User's preferences are now mutable in the User implementation and contains new
mutator methods. FileDataModel / GenericDataModel likewise are mutable. These
methods should be considered expensive.
Modified:
lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/model/BooleanPrefUser.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/GenericUser.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/similarity/SpearmanCorrelationSimilarity.java
lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/model/User.java
lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/model/file/FileDataModelTest.java
Modified:
lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/model/BooleanPrefUser.java
URL:
http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/model/BooleanPrefUser.java?rev=767110&r1=767109&r2=767110&view=diff
==============================================================================
---
lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/model/BooleanPrefUser.java
(original)
+++
lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/model/BooleanPrefUser.java
Tue Apr 21 10:44:32 2009
@@ -19,6 +19,7 @@
import org.apache.mahout.cf.taste.model.Preference;
import org.apache.mahout.cf.taste.model.User;
+import org.apache.mahout.cf.taste.model.Item;
import org.apache.mahout.cf.taste.impl.common.FastSet;
import org.apache.mahout.cf.taste.impl.common.ArrayIterator;
@@ -52,6 +53,19 @@
return itemIDs.contains(itemID) ? buildPreference(itemID) : null;
}
+ /**
+ * Note that the value parameter is ignored; it is as if it were always 1.0.
+ */
+ @Override
+ public void setPreference(Item item, double value) {
+ itemIDs.add(item.getID());
+ }
+
+ @Override
+ public void removePreference(Object itemID) {
+ itemIDs.remove(itemID);
+ }
+
@Override
public Iterable<Preference> getPreferences() {
return new ArrayIterator<Preference>(getPreferencesAsArray());
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=767110&r1=767109&r2=767110&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
Tue Apr 21 10:44:32 2009
@@ -205,20 +205,15 @@
}
}
- /**
- * @throws UnsupportedOperationException
- */
@Override
- public void setPreference(Object userID, Object itemID, double value) {
- throw new UnsupportedOperationException();
+ public void setPreference(Object userID, Object itemID, double value)
+ throws NoSuchUserException, NoSuchItemException {
+ getUser(userID).setPreference(getItem(itemID), value);
}
- /**
- * @throws UnsupportedOperationException
- */
@Override
- public void removePreference(Object userID, Object itemID) {
- throw new UnsupportedOperationException();
+ public void removePreference(Object userID, Object itemID) throws
NoSuchUserException {
+ getUser(userID).removePreference(itemID);
}
@Override
Modified:
lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/model/GenericUser.java
URL:
http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/model/GenericUser.java?rev=767110&r1=767109&r2=767110&view=diff
==============================================================================
---
lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/model/GenericUser.java
(original)
+++
lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/model/GenericUser.java
Tue Apr 21 10:44:32 2009
@@ -21,6 +21,7 @@
import org.apache.mahout.cf.taste.impl.common.FastMap;
import org.apache.mahout.cf.taste.model.Preference;
import org.apache.mahout.cf.taste.model.User;
+import org.apache.mahout.cf.taste.model.Item;
import java.io.Serializable;
import java.util.Arrays;
@@ -40,7 +41,7 @@
private final K id;
private final Map<Object, Preference> data;
// Use an array for maximum performance
- private final Preference[] values;
+ private Preference[] values;
public GenericUser(K id, List<Preference> preferences) {
if (id == null) {
@@ -78,6 +79,45 @@
}
@Override
+ public void setPreference(Item item, double value) {
+ Object itemID = item.getID();
+ Preference oldPref = data.get(itemID);
+ int numValues = values.length;
+ if (oldPref == null) {
+ // No previous pref existed; make room for another
+ // TODO I am concerned we don't have a good theory about where the
factory method
+ // belongs for Preference objects in the scheme of things. Should
probably live in DataModel.
+ // For now we are hard-coding GenericPreference which is usually fine
but not really right.
+ Preference preference = new GenericPreference(this, item, value);
+ Preference[] newValues = new Preference[numValues + 1];
+ System.arraycopy(values, 0, newValues, 1, numValues);
+ newValues[0] = preference;
+ Arrays.sort(newValues, ByItemPreferenceComparator.getInstance());
+ values = newValues;
+ data.put(itemID, preference);
+ } else {
+ oldPref.setValue(value);
+ // We assume the same Preference object is in the array -- this updated
'both'
+ }
+ }
+
+ @Override
+ public void removePreference(Object itemID) {
+ int numValues = values.length;
+ Preference[] newValues = new Preference[numValues - 1];
+ for (int i = 0, j = 0; i < numValues; i++, j++) {
+ Preference value = values[i];
+ if (value.getItem().getID().equals(itemID)) {
+ i++; // skip
+ } else {
+ newValues[j] = value;
+ }
+ }
+ values = newValues;
+ data.remove(itemID);
+ }
+
+ @Override
public Iterable<Preference> getPreferences() {
return new ArrayIterator<Preference>(values);
}
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=767110&r1=767109&r2=767110&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
Tue Apr 21 10:44:32 2009
@@ -166,8 +166,9 @@
AtomicInteger count = new AtomicInteger();
for (String line : new FileLineIterable(dataOrUpdateFile, false)) {
if (line.length() > 0) {
- if (log.isDebugEnabled())
+ if (log.isDebugEnabled()) {
log.debug("Read line: {}", line);
+ }
if (delimiter == UNKNOWN_DELIMITER) {
delimiter = determineDelimiter(line);
}
@@ -248,8 +249,9 @@
item = buildItem(itemID);
itemCache.put(itemID, item);
}
- if (log.isDebugEnabled())
+ if (log.isDebugEnabled()) {
log.debug("Read item '{}' for user ID '{}'", item, userID);
+ }
if (preferenceValueString == null) {
prefs.add(new BooleanPreference(null, item));
} else {
@@ -320,19 +322,24 @@
}
/**
- * @throws UnsupportedOperationException
+ * Note that this method only updates the in-memory preference data that
this {...@link FileDataModel}
+ * maintains; it does not modify any data on disk. Therefore any updates
from this method are only
+ * temporary, and lost when data is reloaded from a file. This method should
also be considered
+ * relatively slow.
*/
@Override
- public void setPreference(Object userID, Object itemID, double value) {
- throw new UnsupportedOperationException();
+ public void setPreference(Object userID, Object itemID, double value) throws
TasteException {
+ checkLoaded();
+ delegate.setPreference(userID, itemID, value);
}
/**
- * @throws UnsupportedOperationException
+ * See the warning at {...@link #setPreference(Object, Object, double)}.
*/
@Override
- public void removePreference(Object userID, Object itemID) {
- throw new UnsupportedOperationException();
+ public void removePreference(Object userID, Object itemID) throws
TasteException {
+ checkLoaded();
+ delegate.removePreference(userID, itemID);
}
@Override
Modified:
lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/similarity/SpearmanCorrelationSimilarity.java
URL:
http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/similarity/SpearmanCorrelationSimilarity.java?rev=767110&r1=767109&r2=767110&view=diff
==============================================================================
---
lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/similarity/SpearmanCorrelationSimilarity.java
(original)
+++
lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/similarity/SpearmanCorrelationSimilarity.java
Tue Apr 21 10:44:32 2009
@@ -28,6 +28,7 @@
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 org.apache.mahout.cf.taste.model.Item;
import java.util.Arrays;
import java.util.Collection;
@@ -94,11 +95,30 @@
return delegate.getID();
}
+ /**
+ * @throws UnsupportedOperationException
+ */
@Override
public Preference getPreferenceFor(Object itemID) {
throw new UnsupportedOperationException();
}
+ /**
+ * @throws UnsupportedOperationException
+ */
+ @Override
+ public void setPreference(Item item, double value) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * @throws UnsupportedOperationException
+ */
+ @Override
+ public void removePreference(Object itemID) {
+ throw new UnsupportedOperationException();
+ }
+
@Override
public Iterable<Preference> getPreferences() {
return Arrays.asList(getPreferencesAsArray());
Modified:
lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/model/User.java
URL:
http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/model/User.java?rev=767110&r1=767109&r2=767110&view=diff
==============================================================================
---
lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/model/User.java
(original)
+++
lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/model/User.java
Tue Apr 21 10:44:32 2009
@@ -35,6 +35,17 @@
Preference getPreferenceFor(Object itemID);
/**
+ * Sets a preference that this {...@link User} has. Note that in general
callers should expect this to
+ * be a slow operation, compared to {...@link #getPreferenceFor(Object)}.
+ */
+ void setPreference(Item item, double value);
+
+ /**
+ * Removes a preference. This method should also be considered potentially
slow.
+ */
+ void removePreference(Object itemID);
+
+ /**
* <p>Returns a sequence of {...@link Preference}s for this {...@link User}
which can be iterated over.
* Note that the sequence <em>must</em> be "in order": ordered by {...@link
Item}.</p>
*
Modified:
lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/model/file/FileDataModelTest.java
URL:
http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/model/file/FileDataModelTest.java?rev=767110&r1=767109&r2=767110&view=diff
==============================================================================
---
lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/model/file/FileDataModelTest.java
(original)
+++
lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/model/file/FileDataModelTest.java
Tue Apr 21 10:44:32 2009
@@ -33,6 +33,7 @@
import java.io.PrintWriter;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
+import java.io.IOException;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -62,7 +63,9 @@
super.setUp();
File tmpDir = new File(System.getProperty("java.io.tmpdir"));
File tmpLoc = new File(tmpDir, "fileDataModel");
- tmpLoc.mkdirs();
+ if (!tmpLoc.mkdirs()) {
+ throw new IOException();
+ }
File testFile = File.createTempFile("test", ".txt", tmpLoc);
testFile.deleteOnExit();
PrintWriter writer =
@@ -151,12 +154,13 @@
}
public void testSetPreference() throws Exception {
- try {
- model.setPreference(null, null, 0.0);
- fail("Should have thrown UnsupportedOperationException");
- } catch (UnsupportedOperationException uoe) {
- // good
- }
+ model.setPreference("A123", "456", 0.2);
+ assertEquals(0.2,
model.getUser("A123").getPreferenceFor("456").getValue());
+ }
+
+ public void testRemovePreference() throws Exception {
+ model.removePreference("A123", "456");
+ assertNull(model.getUser("A123").getPreferenceFor("456"));
}
public void testRefresh() throws Exception {