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 {


Reply via email to