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 2010/03/18 13:15:46 UTC
svn commit: r924738 - in /lucene/mahout/trunk:
core/src/main/java/org/apache/mahout/cf/taste/eval/
core/src/main/java/org/apache/mahout/cf/taste/impl/model/
core/src/main/java/org/apache/mahout/cf/taste/impl/model/file/
core/src/main/java/org/apache/ma...
Author: srowen
Date: Thu Mar 18 12:15:45 2010
New Revision: 924738
URL: http://svn.apache.org/viewvc?rev=924738&view=rev
Log:
MAHOUT-321. Don't add 1 to similarity scores as weights. Also reject user-based pref estimates based on one similarity, as item-based does.
Added:
lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/model/AbstractDataModel.java
lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/EstimatedPreferenceCapper.java
Modified:
lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/eval/RecommenderEvaluator.java
lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/model/GenericBooleanPrefDataModel.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/PlusAnonymousUserDataModel.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/AbstractBooleanPrefJDBCDataModel.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/model/jdbc/GenericJDBCDataModel.java
lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/model/jdbc/MySQLJDBCDataModel.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/model/DataModel.java
lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/recommender/Recommender.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/recommender/GenericItemBasedRecommenderTest.java
lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/recommender/GenericUserBasedRecommenderTest.java
lucene/mahout/trunk/examples/src/main/java/org/apache/mahout/cf/taste/example/netflix/NetflixDataModel.java
lucene/mahout/trunk/examples/src/main/java/org/apache/mahout/cf/taste/example/netflix/NetflixFileDataModel.java
Modified: lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/eval/RecommenderEvaluator.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/eval/RecommenderEvaluator.java?rev=924738&r1=924737&r2=924738&view=diff
==============================================================================
--- lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/eval/RecommenderEvaluator.java (original)
+++ lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/eval/RecommenderEvaluator.java Thu Mar 18 12:15:45 2010
@@ -83,28 +83,23 @@ public interface RecommenderEvaluator {
DataModel dataModel,
double trainingPercentage,
double evaluationPercentage) throws TasteException;
-
- float getMaxPreference();
-
+
/**
- * Sets the maximum preference value that is possible in the current problem domain being evaluated. For
- * example, if the domain is movie ratings on a scale of 1 to 5, this should be set to 5. While a
- * {@link org.apache.mahout.cf.taste.recommender.Recommender} may estimate a preference value above 5.0, it
- * isn't "fair" to consider that the system is actually suggesting an impossible rating of, say, 5.4 stars.
- * In practice the application would cap this estimate to 5.0. Since s evaluate
- * the difference between estimated and actual value, this at least prevents this effect from unfairly
- * penalizing a {@link org.apache.mahout.cf.taste.recommender.Recommender}.
- *
- * @see #setMinPreference(float)
+ * @deprecated see {@link DataModel#getMaxPreference()}
*/
+ @Deprecated
+ float getMaxPreference();
+
+ @Deprecated
void setMaxPreference(float maxPreference);
-
- float getMinPreference();
-
+
/**
- * Sets the minimum preference value that is possible in the current problem domain being evaluated.
- *
+ * @deprecated see {@link DataModel#getMinPreference()}
*/
+ @Deprecated
+ float getMinPreference();
+
+ @Deprecated
void setMinPreference(float minPreference);
}
\ No newline at end of file
Added: lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/model/AbstractDataModel.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/model/AbstractDataModel.java?rev=924738&view=auto
==============================================================================
--- lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/model/AbstractDataModel.java (added)
+++ lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/model/AbstractDataModel.java Thu Mar 18 12:15:45 2010
@@ -0,0 +1,53 @@
+/**
+ * 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.model;
+
+import org.apache.mahout.cf.taste.model.DataModel;
+
+/**
+ * Contains some features common to all implementations.
+ */
+public abstract class AbstractDataModel implements DataModel {
+
+ private float maxPreference;
+ private float minPreference;
+
+ protected AbstractDataModel() {
+ maxPreference = Float.NaN;
+ minPreference = Float.NaN;
+ }
+
+ @Override
+ public float getMaxPreference() {
+ return maxPreference;
+ }
+
+ protected void setMaxPreference(float maxPreference) {
+ this.maxPreference = maxPreference;
+ }
+
+ @Override
+ public float getMinPreference() {
+ return minPreference;
+ }
+
+ protected void setMinPreference(float minPreference) {
+ this.minPreference = minPreference;
+ }
+
+}
Modified: lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/model/GenericBooleanPrefDataModel.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/model/GenericBooleanPrefDataModel.java?rev=924738&r1=924737&r2=924738&view=diff
==============================================================================
--- lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/model/GenericBooleanPrefDataModel.java (original)
+++ lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/model/GenericBooleanPrefDataModel.java Thu Mar 18 12:15:45 2010
@@ -40,7 +40,7 @@ import org.apache.mahout.cf.taste.model.
* is mostly useful for small experiments and is not recommended for contexts where performance is important.
* </p>
*/
-public final class GenericBooleanPrefDataModel implements DataModel, Serializable {
+public final class GenericBooleanPrefDataModel extends AbstractDataModel implements Serializable {
private final long[] userIDs;
private final FastByIDMap<FastIDSet> preferenceFromUsers;
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=924738&r1=924737&r2=924738&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 Thu Mar 18 12:15:45 2010
@@ -44,7 +44,7 @@ import org.slf4j.LoggerFactory;
* is mostly useful for small experiments and is not recommended for contexts where performance is important.
* </p>
*/
-public final class GenericDataModel implements DataModel, Serializable {
+public final class GenericDataModel extends AbstractDataModel implements Serializable {
private static final Logger log = LoggerFactory.getLogger(GenericDataModel.class);
@@ -72,6 +72,8 @@ public final class GenericDataModel impl
FastByIDMap<Collection<Preference>> prefsForItems = new FastByIDMap<Collection<Preference>>();
FastIDSet itemIDSet = new FastIDSet();
int currentCount = 0;
+ float maxPrefValue = Float.NEGATIVE_INFINITY;
+ float minPrefValue = Float.POSITIVE_INFINITY;
for (Map.Entry<Long,PreferenceArray> entry : preferenceFromUsers.entrySet()) {
PreferenceArray prefs = entry.getValue();
prefs.sortByItem();
@@ -84,12 +86,22 @@ public final class GenericDataModel impl
prefsForItems.put(itemID, prefsForItem);
}
prefsForItem.add(preference);
+ float value = preference.getValue();
+ if (value > maxPrefValue) {
+ maxPrefValue = value;
+ }
+ if (value < minPrefValue) {
+ minPrefValue = value;
+ }
}
if (++currentCount % 10000 == 0) {
log.info("Processed {} users", currentCount);
}
}
log.info("Processed {} users", currentCount);
+
+ setMinPreference(minPrefValue);
+ setMaxPreference(maxPrefValue);
this.itemIDs = itemIDSet.toArray();
itemIDSet = null; // Might help GC -- this is big
Modified: lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/model/PlusAnonymousUserDataModel.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/model/PlusAnonymousUserDataModel.java?rev=924738&r1=924737&r2=924738&view=diff
==============================================================================
--- lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/model/PlusAnonymousUserDataModel.java (original)
+++ lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/model/PlusAnonymousUserDataModel.java Thu Mar 18 12:15:45 2010
@@ -208,5 +208,15 @@ public final class PlusAnonymousUserData
public boolean hasPreferenceValues() {
return delegate.hasPreferenceValues();
}
-
+
+ @Override
+ public float getMaxPreference() {
+ return delegate.getMaxPreference();
+ }
+
+ @Override
+ public float getMinPreference() {
+ return delegate.getMinPreference();
+ }
+
}
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=924738&r1=924737&r2=924738&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 Thu Mar 18 12:15:45 2010
@@ -34,6 +34,7 @@ import org.apache.mahout.cf.taste.common
import org.apache.mahout.cf.taste.impl.common.FastByIDMap;
import org.apache.mahout.cf.taste.impl.common.FastIDSet;
import org.apache.mahout.cf.taste.impl.common.LongPrimitiveIterator;
+import org.apache.mahout.cf.taste.impl.model.AbstractDataModel;
import org.apache.mahout.cf.taste.impl.model.GenericBooleanPrefDataModel;
import org.apache.mahout.cf.taste.impl.model.GenericDataModel;
import org.apache.mahout.cf.taste.impl.model.GenericPreference;
@@ -101,7 +102,7 @@ import org.slf4j.LoggerFactory;
* application-specific needs and input formats. See {@link #processLine(String, FastByIDMap, boolean)} and
* {@link #processLineWithoutID(String, FastByIDMap)}
*/
-public class FileDataModel implements DataModel {
+public class FileDataModel extends AbstractDataModel {
private static final Logger log = LoggerFactory.getLogger(FileDataModel.class);
Modified: lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/model/jdbc/AbstractBooleanPrefJDBCDataModel.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/model/jdbc/AbstractBooleanPrefJDBCDataModel.java?rev=924738&r1=924737&r2=924738&view=diff
==============================================================================
--- lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/model/jdbc/AbstractBooleanPrefJDBCDataModel.java (original)
+++ lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/model/jdbc/AbstractBooleanPrefJDBCDataModel.java Thu Mar 18 12:15:45 2010
@@ -56,7 +56,8 @@ public abstract class AbstractBooleanPre
String getNumPreferenceForItemsSQL) {
super(dataSource, preferenceTable, userIDColumn, itemIDColumn, preferenceColumn, getPreferenceSQL,
getUserSQL, getAllUsersSQL, getNumItemsSQL, getNumUsersSQL, setPreferenceSQL, removePreferenceSQL,
- getUsersSQL, getItemsSQL, getPrefsForItemSQL, getNumPreferenceForItemSQL, getNumPreferenceForItemsSQL);
+ getUsersSQL, getItemsSQL, getPrefsForItemSQL, getNumPreferenceForItemSQL, getNumPreferenceForItemsSQL,
+ null, null);
this.setPreferenceSQL = setPreferenceSQL;
}
@@ -97,5 +98,15 @@ public abstract class AbstractBooleanPre
public boolean hasPreferenceValues() {
return false;
}
+
+ @Override
+ public float getMaxPreference() {
+ return 1.0f;
+ }
+
+ @Override
+ public float getMinPreference() {
+ return 1.0f;
+ }
}
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=924738&r1=924737&r2=924738&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 Thu Mar 18 12:15:45 2010
@@ -94,9 +94,13 @@ public abstract class AbstractJDBCDataMo
private final String getPrefsForItemSQL;
private final String getNumPreferenceForItemSQL;
private final String getNumPreferenceForItemsSQL;
+ private final String getMaxPreferenceSQL;
+ private final String getMinPreferenceSQL;
private int cachedNumUsers;
private int cachedNumItems;
private final Cache<Long,Integer> itemPrefCounts;
+ private float maxPreference;
+ private float minPreference;
protected AbstractJDBCDataModel(DataSource dataSource,
String getPreferenceSQL,
@@ -110,12 +114,15 @@ public abstract class AbstractJDBCDataMo
String getItemsSQL,
String getPrefsForItemSQL,
String getNumPreferenceForItemSQL,
- String getNumPreferenceForItemsSQL) {
+ String getNumPreferenceForItemsSQL,
+ String getMaxPreferenceSQL,
+ String getMinPreferenceSQL) {
this(dataSource, DEFAULT_PREFERENCE_TABLE,
DEFAULT_USER_ID_COLUMN, DEFAULT_ITEM_ID_COLUMN,
DEFAULT_PREFERENCE_COLUMN, getPreferenceSQL, getUserSQL, getAllUsersSQL,
getNumItemsSQL, getNumUsersSQL, setPreferenceSQL, removePreferenceSQL, getUsersSQL, getItemsSQL,
- getPrefsForItemSQL, getNumPreferenceForItemSQL, getNumPreferenceForItemsSQL);
+ getPrefsForItemSQL, getNumPreferenceForItemSQL, getNumPreferenceForItemsSQL,
+ getMaxPreferenceSQL, getMinPreferenceSQL);
}
protected AbstractJDBCDataModel(DataSource dataSource,
@@ -134,7 +141,9 @@ public abstract class AbstractJDBCDataMo
String getItemsSQL,
String getPrefsForItemSQL,
String getNumPreferenceForItemSQL,
- String getNumPreferenceForItemsSQL) {
+ String getNumPreferenceForItemsSQL,
+ String getMaxPreferenceSQL,
+ String getMinPreferenceSQL) {
log.debug("Creating AbstractJDBCModel...");
@@ -156,7 +165,9 @@ public abstract class AbstractJDBCDataMo
AbstractJDBCComponent.checkNotNullAndLog("getPrefsForItemSQL", getPrefsForItemSQL);
AbstractJDBCComponent.checkNotNullAndLog("getNumPreferenceForItemSQL", getNumPreferenceForItemSQL);
AbstractJDBCComponent.checkNotNullAndLog("getNumPreferenceForItemsSQL", getNumPreferenceForItemsSQL);
-
+ AbstractJDBCComponent.checkNotNullAndLog("getMaxPreferenceSQL", getMaxPreferenceSQL);
+ AbstractJDBCComponent.checkNotNullAndLog("getMinPreferenceSQL", getMinPreferenceSQL);
+
if (!(dataSource instanceof ConnectionPoolDataSource)) {
AbstractJDBCDataModel.log
.warn("You are not using ConnectionPoolDataSource. Make sure your DataSource pools connections "
@@ -181,11 +192,15 @@ public abstract class AbstractJDBCDataMo
this.getPrefsForItemSQL = getPrefsForItemSQL;
this.getNumPreferenceForItemSQL = getNumPreferenceForItemSQL;
this.getNumPreferenceForItemsSQL = getNumPreferenceForItemsSQL;
+ this.getMaxPreferenceSQL = getMaxPreferenceSQL;
+ this.getMinPreferenceSQL = getMinPreferenceSQL;
this.cachedNumUsers = -1;
this.cachedNumItems = -1;
this.itemPrefCounts = new Cache<Long,Integer>(new ItemPrefCountRetriever(getNumPreferenceForItemSQL));
-
+
+ this.maxPreference = Float.NaN;
+ this.minPreference = Float.NaN;
}
/** @return the {@link DataSource} that this instance is using */
@@ -584,6 +599,8 @@ public abstract class AbstractJDBCDataMo
public void refresh(Collection<Refreshable> alreadyRefreshed) {
cachedNumUsers = -1;
cachedNumItems = -1;
+ minPreference = Float.NaN;
+ maxPreference = Float.NaN;
itemPrefCounts.clear();
}
@@ -591,6 +608,56 @@ public abstract class AbstractJDBCDataMo
public boolean hasPreferenceValues() {
return true;
}
+
+ @Override
+ public float getMaxPreference() {
+ if (Float.isNaN(maxPreference)) {
+ Connection conn = null;
+ PreparedStatement stmt = null;
+ ResultSet rs = null;
+ try {
+ conn = dataSource.getConnection();
+ stmt = conn.prepareStatement(getMaxPreferenceSQL);
+
+ log.debug("Executing SQL query: {}", getMaxPreferenceSQL);
+ rs = stmt.executeQuery();
+ rs.next();
+ maxPreference = rs.getFloat(1);
+
+ } catch (SQLException sqle) {
+ log.warn("Exception while removing preference", sqle);
+ // do nothing
+ } finally {
+ IOUtils.quietClose(rs, stmt, conn);
+ }
+ }
+ return maxPreference;
+ }
+
+ @Override
+ public float getMinPreference() {
+ if (Float.isNaN(minPreference)) {
+ Connection conn = null;
+ PreparedStatement stmt = null;
+ ResultSet rs = null;
+ try {
+ conn = dataSource.getConnection();
+ stmt = conn.prepareStatement(getMinPreferenceSQL);
+
+ log.debug("Executing SQL query: {}", getMinPreferenceSQL);
+ rs = stmt.executeQuery();
+ rs.next();
+ minPreference = rs.getFloat(1);
+
+ } catch (SQLException sqle) {
+ log.warn("Exception while removing preference", sqle);
+ // do nothing
+ } finally {
+ IOUtils.quietClose(rs, stmt, conn);
+ }
+ }
+ return minPreference;
+ }
// Some overrideable methods to customize the class behavior:
Modified: lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/model/jdbc/GenericJDBCDataModel.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/model/jdbc/GenericJDBCDataModel.java?rev=924738&r1=924737&r2=924738&view=diff
==============================================================================
--- lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/model/jdbc/GenericJDBCDataModel.java (original)
+++ lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/model/jdbc/GenericJDBCDataModel.java Thu Mar 18 12:15:45 2010
@@ -53,7 +53,9 @@ public final class GenericJDBCDataModel
public static final String GET_PREFS_FOR_ITEM_SQL_KEY = "getPrefsForItemSQL";
public static final String GET_NUM_PREFERENCE_FOR_ITEM_KEY = "getNumPreferenceForItemSQL";
public static final String GET_NUM_PREFERENCE_FOR_ITEMS_KEY = "getNumPreferenceForItemsSQL";
-
+ public static final String GET_MAX_PREFERENCE_KEY = "getMaxPreferenceSQL";
+ public static final String GET_MIN_PREFERENCE_KEY = "getMinPreferenceSQL";
+
/**
* <p>
* Specifies all SQL queries in a {@link Properties} object. See the <code>*_KEY</code> constants in this
@@ -79,7 +81,9 @@ public final class GenericJDBCDataModel
props.getProperty(GET_ITEMS_SQL_KEY),
props.getProperty(GET_PREFS_FOR_ITEM_SQL_KEY),
props.getProperty(GET_NUM_PREFERENCE_FOR_ITEM_KEY),
- props.getProperty(GET_NUM_PREFERENCE_FOR_ITEMS_KEY));
+ props.getProperty(GET_NUM_PREFERENCE_FOR_ITEMS_KEY),
+ props.getProperty(GET_MAX_PREFERENCE_KEY),
+ props.getProperty(GET_MIN_PREFERENCE_KEY));
}
/**
Modified: lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/model/jdbc/MySQLJDBCDataModel.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/model/jdbc/MySQLJDBCDataModel.java?rev=924738&r1=924737&r2=924738&view=diff
==============================================================================
--- lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/model/jdbc/MySQLJDBCDataModel.java (original)
+++ lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/model/jdbc/MySQLJDBCDataModel.java Thu Mar 18 12:15:45 2010
@@ -197,7 +197,7 @@ public class MySQLJDBCDataModel extends
String itemIDColumn,
String preferenceColumn) {
super(dataSource, preferenceTable, userIDColumn, itemIDColumn, preferenceColumn,
- // getPreferenceSQL
+ // getPreferenceSQL
"SELECT " + preferenceColumn + " FROM " + preferenceTable + " WHERE " + userIDColumn + "=? AND "
+ itemIDColumn + "=?",
// getUserSQL
@@ -226,7 +226,9 @@ public class MySQLJDBCDataModel extends
"SELECT COUNT(1) FROM " + preferenceTable + " WHERE " + itemIDColumn + "=?",
// getNumPreferenceForItemsSQL
"SELECT COUNT(1) FROM " + preferenceTable + " tp1 JOIN " + preferenceTable + " tp2 " + "USING ("
- + userIDColumn + ") WHERE tp1." + itemIDColumn + "=? and tp2." + itemIDColumn + "=?");
+ + userIDColumn + ") WHERE tp1." + itemIDColumn + "=? and tp2." + itemIDColumn + "=?",
+ "SELECT MAX(" + preferenceColumn + ") FROM " + preferenceTable,
+ "SELECT MIN(" + preferenceColumn + ") FROM " + preferenceTable);
}
@Override
Added: lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/EstimatedPreferenceCapper.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/EstimatedPreferenceCapper.java?rev=924738&view=auto
==============================================================================
--- lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/EstimatedPreferenceCapper.java (added)
+++ lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/impl/recommender/EstimatedPreferenceCapper.java Thu Mar 18 12:15:45 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.recommender;
+
+import org.apache.mahout.cf.taste.model.DataModel;
+
+/**
+ * Simple class which encapsulates restricting a preference value
+ * to a predefined range. The simple logic is wrapped up here for
+ * performance reasons.
+ */
+public final class EstimatedPreferenceCapper {
+
+ private final float min;
+ private final float max;
+
+ public EstimatedPreferenceCapper(DataModel model) {
+ min = model.getMinPreference();
+ max = model.getMaxPreference();
+ }
+
+ public float capEstimate(float estimate) {
+ if (estimate > max) {
+ estimate = max;
+ } else if (estimate < min) {
+ estimate = min;
+ }
+ return estimate;
+ }
+
+}
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=924738&r1=924737&r2=924738&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 Thu Mar 18 12:15:45 2010
@@ -67,7 +67,8 @@ public class GenericItemBasedRecommender
private final ItemSimilarity similarity;
private final RefreshHelper refreshHelper;
-
+ private EstimatedPreferenceCapper capper;
+
public GenericItemBasedRecommender(DataModel dataModel, ItemSimilarity similarity) {
super(dataModel);
if (similarity == null) {
@@ -77,6 +78,7 @@ public class GenericItemBasedRecommender
this.refreshHelper = new RefreshHelper(null);
refreshHelper.addDependency(dataModel);
refreshHelper.addDependency(similarity);
+ capper = buildCapper();
}
public ItemSimilarity getSimilarity() {
@@ -186,10 +188,7 @@ public class GenericItemBasedRecommender
for (int i = 0; i < size; i++) {
double theSimilarity = similarity.itemSimilarity(itemID, prefs.getItemID(i));
if (!Double.isNaN(theSimilarity)) {
- // Why + 1.0? similarity ranges from -1.0 to 1.0, and we want to use it as a simple
- // weight. To avoid negative values, we add 1.0 to put it in
- // the [0.0,2.0] range which is reasonable for weights
- theSimilarity += 1.0;
+ // Weights can be negative!
preference += theSimilarity * prefs.getValue(i);
totalSimilarity += theSimilarity;
count++;
@@ -200,7 +199,14 @@ public class GenericItemBasedRecommender
// The reason is that in this case the estimate is, simply, the user's rating for one item
// that happened to have a defined similarity. The similarity score doesn't matter, and that
// seems like a bad situation.
- return count <= 1 ? Float.NaN : (float) (preference / totalSimilarity);
+ if (count <= 1) {
+ return Float.NaN;
+ }
+ float estimate = (float) (preference / totalSimilarity);
+ if (capper != null) {
+ estimate = capper.capEstimate(estimate);
+ }
+ return estimate;
}
private int getNumPreferences(long userID) throws TasteException {
@@ -210,12 +216,22 @@ public class GenericItemBasedRecommender
@Override
public void refresh(Collection<Refreshable> alreadyRefreshed) {
refreshHelper.refresh(alreadyRefreshed);
+ capper = buildCapper();
}
@Override
public String toString() {
return "GenericItemBasedRecommender[similarity:" + similarity + ']';
}
+
+ private EstimatedPreferenceCapper buildCapper() {
+ DataModel dataModel = getDataModel();
+ if (Float.isNaN(dataModel.getMinPreference()) && Float.isNaN(dataModel.getMaxPreference())) {
+ return null;
+ } else {
+ return new EstimatedPreferenceCapper(dataModel);
+ }
+ }
public static class MostSimilarEstimator implements TopItems.Estimator<Long> {
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=924738&r1=924737&r2=924738&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 Thu Mar 18 12:15:45 2010
@@ -50,6 +50,7 @@ public class GenericUserBasedRecommender
private final UserNeighborhood neighborhood;
private final UserSimilarity similarity;
private final RefreshHelper refreshHelper;
+ private EstimatedPreferenceCapper capper;
public GenericUserBasedRecommender(DataModel dataModel,
UserNeighborhood neighborhood,
@@ -64,6 +65,7 @@ public class GenericUserBasedRecommender
refreshHelper.addDependency(dataModel);
refreshHelper.addDependency(similarity);
refreshHelper.addDependency(neighborhood);
+ capper = buildCapper();
}
public UserSimilarity getSimilarity() {
@@ -129,21 +131,34 @@ public class GenericUserBasedRecommender
DataModel dataModel = getDataModel();
double preference = 0.0;
double totalSimilarity = 0.0;
+ int count = 0;
for (long userID : theNeighborhood) {
if (userID != theUserID) {
// See GenericItemBasedRecommender.doEstimatePreference() too
Float pref = dataModel.getPreferenceValue(userID, itemID);
if (pref != null) {
- double theSimilarity = similarity.userSimilarity(theUserID, userID) + 1.0;
- // Similarity should not be NaN or else the user should never have showed up
- // in the neighborhood. Adding 1.0 puts this in the range [0,2] which is
- // more appropriate for weights
- preference += theSimilarity * pref;
- totalSimilarity += theSimilarity;
+ double theSimilarity = similarity.userSimilarity(theUserID, userID);
+ if (!Double.isNaN(theSimilarity)) {
+ preference += theSimilarity * pref;
+ totalSimilarity += theSimilarity;
+ count++;
+ }
}
}
}
- return totalSimilarity == 0.0 ? Float.NaN : (float) (preference / totalSimilarity);
+ // Throw out the estimate if it was based on no data points, of course, but also if based on
+ // just one. This is a bit of a band-aid on the 'stock' item-based algorithm for the moment.
+ // The reason is that in this case the estimate is, simply, the user's rating for one item
+ // that happened to have a defined similarity. The similarity score doesn't matter, and that
+ // seems like a bad situation.
+ if (count <= 1) {
+ return Float.NaN;
+ }
+ float estimate = (float) (preference / totalSimilarity);
+ if (capper != null) {
+ estimate = capper.capEstimate(estimate);
+ }
+ return estimate;
}
protected FastIDSet getAllOtherItems(long[] theNeighborhood, long theUserID) throws TasteException {
@@ -159,12 +174,22 @@ public class GenericUserBasedRecommender
@Override
public void refresh(Collection<Refreshable> alreadyRefreshed) {
refreshHelper.refresh(alreadyRefreshed);
+ capper = buildCapper();
}
@Override
public String toString() {
return "GenericUserBasedRecommender[neighborhood:" + neighborhood + ']';
}
+
+ private EstimatedPreferenceCapper buildCapper() {
+ DataModel dataModel = getDataModel();
+ if (Float.isNaN(dataModel.getMinPreference()) && Float.isNaN(dataModel.getMaxPreference())) {
+ return null;
+ } else {
+ return new EstimatedPreferenceCapper(dataModel);
+ }
+ }
private static class MostSimilarEstimator implements TopItems.Estimator<Long> {
Modified: lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/model/DataModel.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/model/DataModel.java?rev=924738&r1=924737&r2=924738&view=diff
==============================================================================
--- lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/model/DataModel.java (original)
+++ lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/model/DataModel.java Thu Mar 18 12:15:45 2010
@@ -163,6 +163,26 @@ public interface DataModel extends Refre
*/
void removePreference(long userID, long itemID) throws TasteException;
+ /**
+ * @return true iff this implementation actually stores and returns distinct preference values;
+ * that is, if it is not a 'boolean' DataModel
+ */
boolean hasPreferenceValues();
+
+ /**
+ * @return the maximum preference value that is possible in the current problem domain being evaluated. For
+ * example, if the domain is movie ratings on a scale of 1 to 5, this should be 5. While a
+ * {@link org.apache.mahout.cf.taste.recommender.Recommender} may estimate a preference value above 5.0, it
+ * isn't "fair" to consider that the system is actually suggesting an impossible rating of, say, 5.4 stars.
+ * In practice the application would cap this estimate to 5.0. Since evaluators evaluate
+ * the difference between estimated and actual value, this at least prevents this effect from unfairly
+ * penalizing a {@link org.apache.mahout.cf.taste.recommender.Recommender}
+ */
+ float getMaxPreference();
+
+ /**
+ * @see #getMaxPreference()
+ */
+ float getMinPreference();
}
Modified: lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/recommender/Recommender.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/recommender/Recommender.java?rev=924738&r1=924737&r2=924738&view=diff
==============================================================================
--- lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/recommender/Recommender.java (original)
+++ lucene/mahout/trunk/core/src/main/java/org/apache/mahout/cf/taste/recommender/Recommender.java Thu Mar 18 12:15:45 2010
@@ -91,7 +91,10 @@ public interface Recommender extends Ref
* if an error occurs while accessing the {@link DataModel}
*/
void removePreference(long userID, long itemID) throws TasteException;
-
+
+ /**
+ * @return underlying {@link DataModel} used by this implementation
+ */
DataModel getDataModel();
-
+
}
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=924738&r1=924737&r2=924738&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 Thu Mar 18 12:15:45 2010
@@ -48,11 +48,16 @@ public final class FileDataModelTest ext
"123,654,0.7",
"234,123,0.5",
"234,234,1.0",
+ "234,999,0.9",
"345,789,0.6",
"345,654,0.7",
"345,123,1.0",
"345,234,0.5",
- "456,456,0.1"};
+ "345,999,0.5",
+ "456,456,0.1",
+ "456,789,0.5",
+ "456,654,0.0",
+ "456,999,0.2",};
private DataModel model;
private File testFile;
@@ -96,10 +101,10 @@ public final class FileDataModelTest ext
public void testFile() throws Exception {
UserSimilarity userSimilarity = new PearsonCorrelationSimilarity(model);
- UserNeighborhood neighborhood = new NearestNUserNeighborhood(2, userSimilarity, model);
+ UserNeighborhood neighborhood = new NearestNUserNeighborhood(3, userSimilarity, model);
Recommender recommender = new GenericUserBasedRecommender(model, neighborhood, userSimilarity);
- assertEquals(2, recommender.recommend(123, 3).size());
- assertEquals(2, recommender.recommend(234, 3).size());
+ assertEquals(1, recommender.recommend(123, 3).size());
+ assertEquals(0, recommender.recommend(234, 3).size());
assertEquals(1, recommender.recommend(345, 3).size());
// Make sure this doesn't throw an exception
@@ -129,6 +134,8 @@ public final class FileDataModelTest ext
assertEquals(654, it.nextLong());
assertTrue(it.hasNext());
assertEquals(789, it.nextLong());
+ assertTrue(it.hasNext());
+ assertEquals(999, it.nextLong());
assertFalse(it.hasNext());
try {
it.next();
Modified: lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/recommender/GenericItemBasedRecommenderTest.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/recommender/GenericItemBasedRecommenderTest.java?rev=924738&r1=924737&r2=924738&view=diff
==============================================================================
--- lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/recommender/GenericItemBasedRecommenderTest.java (original)
+++ lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/recommender/GenericItemBasedRecommenderTest.java Thu Mar 18 12:15:45 2010
@@ -39,12 +39,12 @@ public final class GenericItemBasedRecom
assertEquals(1, recommended.size());
RecommendedItem firstRecommended = recommended.get(0);
assertEquals(2, firstRecommended.getItemID());
- assertEquals(0.18, firstRecommended.getValue(), EPSILON);
+ assertEquals(0.1f, firstRecommended.getValue(), EPSILON);
recommender.refresh(null);
recommended = recommender.recommend(1, 1);
firstRecommended = recommended.get(0);
assertEquals(2, firstRecommended.getItemID());
- assertEquals(0.18, firstRecommended.getValue(), EPSILON);
+ assertEquals(0.1f, firstRecommended.getValue(), EPSILON);
}
public void testHowMany() throws Exception {
@@ -113,7 +113,7 @@ public final class GenericItemBasedRecom
public void testEstimatePref() throws Exception {
Recommender recommender = buildRecommender();
- assertEquals(0.18, recommender.estimatePreference(1, 2), EPSILON);
+ assertEquals(0.1f, recommender.estimatePreference(1, 2), EPSILON);
}
/**
@@ -129,7 +129,7 @@ public final class GenericItemBasedRecom
RecommendedItem firstRecommended = recommended.get(0);
// item one should be recommended because it has a greater rating/score
assertEquals(2, firstRecommended.getItemID());
- assertEquals(0.18, firstRecommended.getValue(), EPSILON);
+ assertEquals(0.1f, firstRecommended.getValue(), EPSILON);
}
public void testMostSimilar() throws Exception {
@@ -140,9 +140,9 @@ public final class GenericItemBasedRecom
RecommendedItem first = similar.get(0);
RecommendedItem second = similar.get(1);
assertEquals(1, first.getItemID());
- assertEquals(1.0, first.getValue(), EPSILON);
+ assertEquals(1.0f, first.getValue(), EPSILON);
assertEquals(2, second.getItemID());
- assertEquals(0.5, second.getValue(), EPSILON);
+ assertEquals(0.5f, second.getValue(), EPSILON);
}
public void testMostSimilarToMultiple() throws Exception {
@@ -153,9 +153,9 @@ public final class GenericItemBasedRecom
RecommendedItem first = similar.get(0);
RecommendedItem second = similar.get(1);
assertEquals(2, first.getItemID());
- assertEquals(0.85, first.getValue(), EPSILON);
+ assertEquals(0.85f, first.getValue(), EPSILON);
assertEquals(3, second.getItemID());
- assertEquals(-0.3, second.getValue(), EPSILON);
+ assertEquals(-0.3f, second.getValue(), EPSILON);
}
public void testRecommendedBecause() throws Exception {
@@ -167,11 +167,11 @@ public final class GenericItemBasedRecom
RecommendedItem second = recommendedBecause.get(1);
RecommendedItem third = recommendedBecause.get(2);
assertEquals(2, first.getItemID());
- assertEquals(0.99, first.getValue(), EPSILON);
+ assertEquals(0.99f, first.getValue(), EPSILON);
assertEquals(3, second.getItemID());
- assertEquals(0.4, second.getValue(), EPSILON);
+ assertEquals(0.4f, second.getValue(), EPSILON);
assertEquals(0, third.getItemID());
- assertEquals(0.2, third.getValue(), EPSILON);
+ assertEquals(0.2f, third.getValue(), EPSILON);
}
private static ItemBasedRecommender buildRecommender() {
Modified: lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/recommender/GenericUserBasedRecommenderTest.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/recommender/GenericUserBasedRecommenderTest.java?rev=924738&r1=924737&r2=924738&view=diff
==============================================================================
--- lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/recommender/GenericUserBasedRecommenderTest.java (original)
+++ lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/recommender/GenericUserBasedRecommenderTest.java Thu Mar 18 12:15:45 2010
@@ -40,10 +40,10 @@ public final class GenericUserBasedRecom
assertEquals(1, recommended.size());
RecommendedItem firstRecommended = recommended.get(0);
assertEquals(2, firstRecommended.getItemID());
- assertEquals(0.3f, firstRecommended.getValue());
+ assertEquals(0.1f, firstRecommended.getValue());
recommender.refresh(null);
assertEquals(2, firstRecommended.getItemID());
- assertEquals(0.3f, firstRecommended.getValue());
+ assertEquals(0.1f, firstRecommended.getValue());
}
public void testHowMany() throws Exception {
@@ -76,10 +76,10 @@ public final class GenericUserBasedRecom
new Double[][] {
{0.1, 0.2},
{0.2, 0.3, 0.3, 0.6},
- {0.4, 0.4, 0.5, 0.9},
+ {0.4, 0.5, 0.5, 0.9},
});
UserSimilarity similarity = new PearsonCorrelationSimilarity(dataModel);
- UserNeighborhood neighborhood = new NearestNUserNeighborhood(1, similarity, dataModel);
+ UserNeighborhood neighborhood = new NearestNUserNeighborhood(2, similarity, dataModel);
Recommender recommender = new GenericUserBasedRecommender(dataModel, neighborhood, similarity);
List<RecommendedItem> originalRecommended = recommender.recommend(1, 2);
List<RecommendedItem> rescoredRecommended =
@@ -94,7 +94,7 @@ public final class GenericUserBasedRecom
public void testEstimatePref() throws Exception {
Recommender recommender = buildRecommender();
- assertEquals(0.3f, recommender.estimatePreference(1, 2));
+ assertEquals(0.1f, recommender.estimatePreference(1, 2));
}
public void testBestRating() throws Exception {
@@ -105,7 +105,7 @@ public final class GenericUserBasedRecom
RecommendedItem firstRecommended = recommended.get(0);
// item one should be recommended because it has a greater rating/score
assertEquals(2, firstRecommended.getItemID());
- assertEquals(0.3f, firstRecommended.getValue(), EPSILON);
+ assertEquals(0.1f, firstRecommended.getValue(), EPSILON);
}
public void testMostSimilar() throws Exception {
@@ -137,7 +137,7 @@ public final class GenericUserBasedRecom
private static UserBasedRecommender buildRecommender() throws TasteException {
DataModel dataModel = getDataModel();
UserSimilarity similarity = new PearsonCorrelationSimilarity(dataModel);
- UserNeighborhood neighborhood = new NearestNUserNeighborhood(1, similarity, dataModel);
+ UserNeighborhood neighborhood = new NearestNUserNeighborhood(2, similarity, dataModel);
return new GenericUserBasedRecommender(dataModel, neighborhood, similarity);
}
Modified: lucene/mahout/trunk/examples/src/main/java/org/apache/mahout/cf/taste/example/netflix/NetflixDataModel.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/examples/src/main/java/org/apache/mahout/cf/taste/example/netflix/NetflixDataModel.java?rev=924738&r1=924737&r2=924738&view=diff
==============================================================================
--- lucene/mahout/trunk/examples/src/main/java/org/apache/mahout/cf/taste/example/netflix/NetflixDataModel.java (original)
+++ lucene/mahout/trunk/examples/src/main/java/org/apache/mahout/cf/taste/example/netflix/NetflixDataModel.java Thu Mar 18 12:15:45 2010
@@ -170,6 +170,16 @@ public final class NetflixDataModel impl
public boolean hasPreferenceValues() {
return delegate.hasPreferenceValues();
}
+
+ @Override
+ public float getMaxPreference() {
+ return delegate.getMaxPreference();
+ }
+
+ @Override
+ public float getMinPreference() {
+ return delegate.getMinPreference();
+ }
private class MovieFilenameFilter implements FilenameFilter {
@Override
Modified: lucene/mahout/trunk/examples/src/main/java/org/apache/mahout/cf/taste/example/netflix/NetflixFileDataModel.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/examples/src/main/java/org/apache/mahout/cf/taste/example/netflix/NetflixFileDataModel.java?rev=924738&r1=924737&r2=924738&view=diff
==============================================================================
--- lucene/mahout/trunk/examples/src/main/java/org/apache/mahout/cf/taste/example/netflix/NetflixFileDataModel.java (original)
+++ lucene/mahout/trunk/examples/src/main/java/org/apache/mahout/cf/taste/example/netflix/NetflixFileDataModel.java Thu Mar 18 12:15:45 2010
@@ -139,6 +139,16 @@ public final class NetflixFileDataModel
public boolean hasPreferenceValues() {
return true;
}
+
+ @Override
+ public float getMaxPreference() {
+ return 0.0f; // TODO
+ }
+
+ @Override
+ public float getMinPreference() {
+ return 0.0f; // TODO
+ }
@Override
public String toString() {