You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mahout.apache.org by sr...@apache.org on 2008/05/09 23:35:17 UTC
svn commit: r654943 [8/9] - in /lucene/mahout/trunk/core: ./ lib/
src/main/examples/org/ src/main/examples/org/apache/
src/main/examples/org/apache/mahout/ src/main/examples/org/apache/mahout/cf/
src/main/examples/org/apache/mahout/cf/taste/ src/main/e...
Added: lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/common/RunningAverageTest.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/common/RunningAverageTest.java?rev=654943&view=auto
==============================================================================
--- lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/common/RunningAverageTest.java (added)
+++ lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/common/RunningAverageTest.java Fri May 9 14:35:12 2008
@@ -0,0 +1,67 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.mahout.cf.taste.impl.common;
+
+import org.apache.mahout.cf.taste.impl.TasteTestCase;
+
+/**
+ * <p>Tests {@link FullRunningAverage}.</p>
+ */
+public final class RunningAverageTest extends TasteTestCase {
+
+ public void testFull() {
+ doTestRunningAverage(new FullRunningAverage());
+ }
+
+ public void testCompact() {
+ doTestRunningAverage(new CompactRunningAverage());
+ }
+
+ private static void doTestRunningAverage(RunningAverage runningAverage) {
+
+ assertEquals(0, runningAverage.getCount());
+ assertTrue(Double.isNaN(runningAverage.getAverage()));
+ runningAverage.addDatum(1.0);
+ assertEquals(1, runningAverage.getCount());
+ assertEquals(1.0, runningAverage.getAverage());
+ runningAverage.addDatum(1.0);
+ assertEquals(2, runningAverage.getCount());
+ assertEquals(1.0, runningAverage.getAverage());
+ runningAverage.addDatum(4.0);
+ assertEquals(3, runningAverage.getCount());
+ assertEquals(2.0, runningAverage.getAverage());
+ runningAverage.addDatum(-4.0);
+ assertEquals(4, runningAverage.getCount());
+ assertEquals(0.5, runningAverage.getAverage());
+
+ runningAverage.removeDatum(-4.0);
+ assertEquals(3, runningAverage.getCount());
+ assertEquals(2.0, runningAverage.getAverage());
+ runningAverage.removeDatum(4.0);
+ assertEquals(2, runningAverage.getCount());
+ assertEquals(1.0, runningAverage.getAverage());
+
+ runningAverage.changeDatum(0.0);
+ assertEquals(2, runningAverage.getCount());
+ assertEquals(1.0, runningAverage.getAverage());
+ runningAverage.changeDatum(2.0);
+ assertEquals(2, runningAverage.getCount());
+ assertEquals(2.0, runningAverage.getAverage());
+ }
+
+}
Added: lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/correlation/AveragingPreferenceInferrerTest.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/correlation/AveragingPreferenceInferrerTest.java?rev=654943&view=auto
==============================================================================
--- lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/correlation/AveragingPreferenceInferrerTest.java (added)
+++ lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/correlation/AveragingPreferenceInferrerTest.java Fri May 9 14:35:12 2008
@@ -0,0 +1,45 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.mahout.cf.taste.impl.correlation;
+
+import org.apache.mahout.cf.taste.common.TasteException;
+import org.apache.mahout.cf.taste.correlation.PreferenceInferrer;
+import org.apache.mahout.cf.taste.impl.TasteTestCase;
+import org.apache.mahout.cf.taste.impl.model.GenericDataModel;
+import org.apache.mahout.cf.taste.impl.model.GenericItem;
+import org.apache.mahout.cf.taste.model.DataModel;
+import org.apache.mahout.cf.taste.model.Item;
+import org.apache.mahout.cf.taste.model.User;
+
+import java.util.Collections;
+
+/**
+ * <p>Tests {@link AveragingPreferenceInferrer}.</p>
+ */
+public final class AveragingPreferenceInferrerTest extends TasteTestCase {
+
+ public void testInferrer() throws TasteException {
+ User user1 = getUser("test1", 3.0, -2.0, 5.0);
+ Item item = new GenericItem<String>("3");
+ DataModel model = new GenericDataModel(Collections.singletonList(user1));
+ PreferenceInferrer inferrer = new AveragingPreferenceInferrer(model);
+ double inferred = inferrer.inferPreference(user1, item);
+ assertEquals(2.0, inferred);
+ }
+
+}
Added: lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/correlation/CorrelationTestCase.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/correlation/CorrelationTestCase.java?rev=654943&view=auto
==============================================================================
--- lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/correlation/CorrelationTestCase.java (added)
+++ lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/correlation/CorrelationTestCase.java Fri May 9 14:35:12 2008
@@ -0,0 +1,30 @@
+/**
+ * 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.correlation;
+
+import org.apache.mahout.cf.taste.impl.TasteTestCase;
+
+abstract class CorrelationTestCase extends TasteTestCase {
+
+ static void assertCorrelationEquals(double expected, double actual) {
+ assertTrue("Correlation > 1.0", actual <= 1.0);
+ assertTrue("Correlation < -1.0", actual >= -1.0);
+ assertEquals(expected, actual, EPSILON);
+ }
+
+}
Added: lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/correlation/GenericItemCorrelationTest.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/correlation/GenericItemCorrelationTest.java?rev=654943&view=auto
==============================================================================
--- lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/correlation/GenericItemCorrelationTest.java (added)
+++ lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/correlation/GenericItemCorrelationTest.java Fri May 9 14:35:12 2008
@@ -0,0 +1,65 @@
+/**
+ * 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.correlation;
+
+import org.apache.mahout.cf.taste.correlation.ItemCorrelation;
+import org.apache.mahout.cf.taste.impl.model.GenericItem;
+import org.apache.mahout.cf.taste.model.DataModel;
+import org.apache.mahout.cf.taste.model.Item;
+import org.apache.mahout.cf.taste.model.User;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * <p>Tests {@link GenericItemCorrelation}.</p>
+ */
+public final class GenericItemCorrelationTest extends CorrelationTestCase {
+
+ public void testSimple() {
+ Item item1 = new GenericItem<String>("1");
+ Item item2 = new GenericItem<String>("2");
+ Item item3 = new GenericItem<String>("3");
+ Item item4 = new GenericItem<String>("4");
+ List<GenericItemCorrelation.ItemItemCorrelation> correlations =
+ new ArrayList<GenericItemCorrelation.ItemItemCorrelation>(4);
+ correlations.add(new GenericItemCorrelation.ItemItemCorrelation(item1, item2, 0.5));
+ correlations.add(new GenericItemCorrelation.ItemItemCorrelation(item2, item1, 0.6));
+ correlations.add(new GenericItemCorrelation.ItemItemCorrelation(item1, item1, 0.5));
+ correlations.add(new GenericItemCorrelation.ItemItemCorrelation(item1, item3, 0.3));
+ GenericItemCorrelation itemCorrelation = new GenericItemCorrelation(correlations);
+ assertEquals(1.0, itemCorrelation.itemCorrelation(item1, item1));
+ assertEquals(0.6, itemCorrelation.itemCorrelation(item1, item2));
+ assertEquals(0.6, itemCorrelation.itemCorrelation(item2, item1));
+ assertEquals(0.3, itemCorrelation.itemCorrelation(item1, item3));
+ assertTrue(Double.isNaN(itemCorrelation.itemCorrelation(item3, item4)));
+ }
+
+ public void testFromCorrelation() throws Exception {
+ User user1 = getUser("test1", 1.0, 2.0);
+ User user2 = getUser("test2", 2.0, 5.0);
+ User user3 = getUser("test3", 3.0, 6.0);
+ DataModel dataModel = getDataModel(user1, user2, user3);
+ ItemCorrelation otherCorrelation = new PearsonCorrelation(dataModel);
+ ItemCorrelation itemCorrelation = new GenericItemCorrelation(otherCorrelation, dataModel);
+ assertCorrelationEquals(1.0,
+ itemCorrelation.itemCorrelation(dataModel.getItem("0"), dataModel.getItem("0")));
+ assertCorrelationEquals(0.960768922830523,
+ itemCorrelation.itemCorrelation(dataModel.getItem("0"), dataModel.getItem("1")));
+ }
+
+}
Added: lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/correlation/PearsonCorrelationTest.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/correlation/PearsonCorrelationTest.java?rev=654943&view=auto
==============================================================================
--- lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/correlation/PearsonCorrelationTest.java (added)
+++ lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/correlation/PearsonCorrelationTest.java Fri May 9 14:35:12 2008
@@ -0,0 +1,184 @@
+/**
+ * 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.correlation;
+
+import org.apache.mahout.cf.taste.correlation.ItemCorrelation;
+import org.apache.mahout.cf.taste.impl.model.GenericItem;
+import org.apache.mahout.cf.taste.impl.model.GenericPreference;
+import org.apache.mahout.cf.taste.impl.model.GenericUser;
+import org.apache.mahout.cf.taste.model.DataModel;
+import org.apache.mahout.cf.taste.model.Preference;
+import org.apache.mahout.cf.taste.model.User;
+
+import java.util.Collections;
+
+/**
+ * <p>Tests {@link PearsonCorrelation}.</p>
+ */
+public final class PearsonCorrelationTest extends CorrelationTestCase {
+
+ public void testFullCorrelation1() throws Exception {
+ User user1 = getUser("test1", 3.0, -2.0);
+ User user2 = getUser("test2", 3.0, -2.0);
+ DataModel dataModel = getDataModel(user1, user2);
+ double correlation = new PearsonCorrelation(dataModel).userCorrelation(user1, user2);
+ assertCorrelationEquals(1.0, correlation);
+ }
+
+ public void testFullCorrelation1Weighted() throws Exception {
+ User user1 = getUser("test1", 3.0, -2.0);
+ User user2 = getUser("test2", 3.0, -2.0);
+ DataModel dataModel = getDataModel(user1, user2);
+ double correlation = new PearsonCorrelation(dataModel, true).userCorrelation(user1, user2);
+ assertCorrelationEquals(1.0, correlation);
+ }
+
+ public void testFullCorrelation2() throws Exception {
+ User user1 = getUser("test1", 3.0, 3.0);
+ User user2 = getUser("test2", 3.0, 3.0);
+ DataModel dataModel = getDataModel(user1, user2);
+ double correlation = new PearsonCorrelation(dataModel).userCorrelation(user1, user2);
+ // Yeah, undefined in this case
+ assertTrue(Double.isNaN(correlation));
+ }
+
+ public void testNoCorrelation1() throws Exception {
+ User user1 = getUser("test1", 3.0, -2.0);
+ User user2 = getUser("test2", -3.0, 2.0);
+ DataModel dataModel = getDataModel(user1, user2);
+ double correlation = new PearsonCorrelation(dataModel).userCorrelation(user1, user2);
+ assertCorrelationEquals(-1.0, correlation);
+ }
+
+ public void testNoCorrelation1Weighted() throws Exception {
+ User user1 = getUser("test1", 3.0, -2.0);
+ User user2 = getUser("test2", -3.0, 2.0);
+ DataModel dataModel = getDataModel(user1, user2);
+ double correlation = new PearsonCorrelation(dataModel, true).userCorrelation(user1, user2);
+ assertCorrelationEquals(-1.0, correlation);
+ }
+
+ public void testNoCorrelation2() throws Exception {
+ Preference pref1 = new GenericPreference(null, new GenericItem<String>("1"), 1.0);
+ GenericUser<String> user1 = new GenericUser<String>("test1", Collections.singletonList(pref1));
+ Preference pref2 = new GenericPreference(null, new GenericItem<String>("2"), 1.0);
+ GenericUser<String> user2 = new GenericUser<String>("test2", Collections.singletonList(pref2));
+ DataModel dataModel = getDataModel(user1, user2);
+ double correlation = new PearsonCorrelation(dataModel).userCorrelation(user1, user2);
+ assertTrue(Double.isNaN(correlation));
+ }
+
+ public void testNoCorrelation3() throws Exception {
+ User user1 = getUser("test1", 90.0, 80.0, 70.0);
+ User user2 = getUser("test2", 70.0, 80.0, 90.0);
+ DataModel dataModel = getDataModel(user1, user2);
+ double correlation = new PearsonCorrelation(dataModel).userCorrelation(user1, user2);
+ assertCorrelationEquals(-1.0, correlation);
+ }
+
+ public void testSimple() throws Exception {
+ User user1 = getUser("test1", 1.0, 2.0, 3.0);
+ User user2 = getUser("test2", 2.0, 5.0, 6.0);
+ DataModel dataModel = getDataModel(user1, user2);
+ double correlation = new PearsonCorrelation(dataModel).userCorrelation(user1, user2);
+ assertCorrelationEquals(0.9607689228305227, correlation);
+ }
+
+ public void testSimpleWeighted() throws Exception {
+ User user1 = getUser("test1", 1.0, 2.0, 3.0);
+ User user2 = getUser("test2", 2.0, 5.0, 6.0);
+ DataModel dataModel = getDataModel(user1, user2);
+ double correlation = new PearsonCorrelation(dataModel, true).userCorrelation(user1, user2);
+ assertCorrelationEquals(0.9901922307076306, correlation);
+ }
+
+ public void testFullItemCorrelation1() throws Exception {
+ User user1 = getUser("test1", 3.0, 3.0);
+ User user2 = getUser("test2", -2.0, -2.0);
+ DataModel dataModel = getDataModel(user1, user2);
+ double correlation =
+ new PearsonCorrelation(dataModel).itemCorrelation(dataModel.getItem("0"), dataModel.getItem("1"));
+ assertCorrelationEquals(1.0, correlation);
+ }
+
+ public void testFullItemCorrelation2() throws Exception {
+ User user1 = getUser("test1", 3.0, 3.0);
+ User user2 = getUser("test2", 3.0, 3.0);
+ DataModel dataModel = getDataModel(user1, user2);
+ double correlation =
+ new PearsonCorrelation(dataModel).itemCorrelation(dataModel.getItem("0"), dataModel.getItem("1"));
+ // Yeah, undefined in this case
+ assertTrue(Double.isNaN(correlation));
+ }
+
+ public void testNoItemCorrelation1() throws Exception {
+ User user1 = getUser("test1", 3.0, -3.0);
+ User user2 = getUser("test2", -2.0, 2.0);
+ DataModel dataModel = getDataModel(user1, user2);
+ double correlation =
+ new PearsonCorrelation(dataModel).itemCorrelation(dataModel.getItem("0"), dataModel.getItem("1"));
+ assertCorrelationEquals(-1.0, correlation);
+ }
+
+ public void testNoItemCorrelation2() throws Exception {
+ Preference pref1 = new GenericPreference(null, new GenericItem<String>("1"), 1.0);
+ GenericUser<String> user1 = new GenericUser<String>("test1", Collections.singletonList(pref1));
+ Preference pref2 = new GenericPreference(null, new GenericItem<String>("2"), 1.0);
+ GenericUser<String> user2 = new GenericUser<String>("test2", Collections.singletonList(pref2));
+ DataModel dataModel = getDataModel(user1, user2);
+ double correlation =
+ new PearsonCorrelation(dataModel).itemCorrelation(dataModel.getItem("1"), dataModel.getItem("2"));
+ assertTrue(Double.isNaN(correlation));
+ }
+
+ public void testNoItemCorrelation3() throws Exception {
+ User user1 = getUser("test1", 90.0, 70.0);
+ User user2 = getUser("test2", 80.0, 80.0);
+ User user3 = getUser("test3", 70.0, 90.0);
+ DataModel dataModel = getDataModel(user1, user2, user3);
+ double correlation =
+ new PearsonCorrelation(dataModel).itemCorrelation(dataModel.getItem("0"), dataModel.getItem("1"));
+ assertCorrelationEquals(-1.0, correlation);
+ }
+
+ public void testSimpleItem() throws Exception {
+ User user1 = getUser("test1", 1.0, 2.0);
+ User user2 = getUser("test2", 2.0, 5.0);
+ User user3 = getUser("test3", 3.0, 6.0);
+ DataModel dataModel = getDataModel(user1, user2, user3);
+ double correlation =
+ new PearsonCorrelation(dataModel).itemCorrelation(dataModel.getItem("0"), dataModel.getItem("1"));
+ assertCorrelationEquals(0.9607689228305227, correlation);
+ }
+
+ public void testSimpleItemWeighted() throws Exception {
+ User user1 = getUser("test1", 1.0, 2.0);
+ User user2 = getUser("test2", 2.0, 5.0);
+ User user3 = getUser("test3", 3.0, 6.0);
+ DataModel dataModel = getDataModel(user1, user2, user3);
+ ItemCorrelation itemCorrelation = new PearsonCorrelation(dataModel, true);
+ double correlation = itemCorrelation.itemCorrelation(dataModel.getItem("0"), dataModel.getItem("1"));
+ assertCorrelationEquals(0.9901922307076306, correlation);
+ }
+
+ public void testRefresh() {
+ // Make sure this doesn't throw an exception
+ new PearsonCorrelation(getDataModel()).refresh();
+ }
+
+}
Added: lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/correlation/SpearmanCorrelationTest.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/correlation/SpearmanCorrelationTest.java?rev=654943&view=auto
==============================================================================
--- lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/correlation/SpearmanCorrelationTest.java (added)
+++ lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/correlation/SpearmanCorrelationTest.java Fri May 9 14:35:12 2008
@@ -0,0 +1,65 @@
+/**
+ * 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.correlation;
+
+import org.apache.mahout.cf.taste.model.DataModel;
+import org.apache.mahout.cf.taste.model.User;
+
+/**
+ * <p>Tests {@link SpearmanCorrelation}.</p>
+ */
+public final class SpearmanCorrelationTest extends CorrelationTestCase {
+
+ public void testFullCorrelation1() throws Exception {
+ User user1 = getUser("test1", 1.0, 2.0, 3.0);
+ User user2 = getUser("test2", 1.0, 2.0, 3.0);
+ DataModel dataModel = getDataModel(user1, user2);
+ double correlation = new SpearmanCorrelation(dataModel).userCorrelation(user1, user2);
+ assertCorrelationEquals(1.0, correlation);
+ }
+
+ public void testFullCorrelation2() throws Exception {
+ User user1 = getUser("test1", 1.0, 2.0, 3.0);
+ User user2 = getUser("test2", 4.0, 5.0, 6.0);
+ DataModel dataModel = getDataModel(user1, user2);
+ double correlation = new SpearmanCorrelation(dataModel).userCorrelation(user1, user2);
+ assertCorrelationEquals(1.0, correlation);
+ }
+
+ public void testAnticorrelation() throws Exception {
+ User user1 = getUser("test1", 1.0, 2.0, 3.0);
+ User user2 = getUser("test2", 3.0, 2.0, 1.0);
+ DataModel dataModel = getDataModel(user1, user2);
+ double correlation = new SpearmanCorrelation(dataModel).userCorrelation(user1, user2);
+ assertCorrelationEquals(-1.0, correlation);
+ }
+
+ public void testSimple() throws Exception {
+ User user1 = getUser("test1", 1.0, 2.0, 3.0);
+ User user2 = getUser("test2", 2.0, 3.0, 1.0);
+ DataModel dataModel = getDataModel(user1, user2);
+ double correlation = new SpearmanCorrelation(dataModel).userCorrelation(user1, user2);
+ assertCorrelationEquals(-0.5, correlation);
+ }
+
+ public void testRefresh() {
+ // Make sure this doesn't throw an exception
+ new SpearmanCorrelation(getDataModel()).refresh();
+ }
+
+}
Added: lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/eval/AverageAbsoluteDifferenceRecommenderEvaluatorTest.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/eval/AverageAbsoluteDifferenceRecommenderEvaluatorTest.java?rev=654943&view=auto
==============================================================================
--- lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/eval/AverageAbsoluteDifferenceRecommenderEvaluatorTest.java (added)
+++ lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/eval/AverageAbsoluteDifferenceRecommenderEvaluatorTest.java Fri May 9 14:35:12 2008
@@ -0,0 +1,43 @@
+/**
+ * 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.eval;
+
+import org.apache.mahout.cf.taste.common.TasteException;
+import org.apache.mahout.cf.taste.eval.RecommenderBuilder;
+import org.apache.mahout.cf.taste.eval.RecommenderEvaluator;
+import org.apache.mahout.cf.taste.impl.TasteTestCase;
+import org.apache.mahout.cf.taste.impl.recommender.slopeone.SlopeOneRecommender;
+import org.apache.mahout.cf.taste.model.DataModel;
+import org.apache.mahout.cf.taste.recommender.Recommender;
+
+public final class AverageAbsoluteDifferenceRecommenderEvaluatorTest extends TasteTestCase {
+
+ public void testEvaluate() throws Exception {
+ DataModel model = getDataModel();
+ RecommenderBuilder builder = new RecommenderBuilder() {
+ public Recommender buildRecommender(DataModel dataModel) throws TasteException {
+ return new SlopeOneRecommender(dataModel);
+ }
+ };
+ RecommenderEvaluator evaluator =
+ new AverageAbsoluteDifferenceRecommenderEvaluator();
+ double eval = evaluator.evaluate(builder, model, 0.75, 1.0);
+ assertEquals(0.26387685767414826, eval, EPSILON);
+ }
+
+}
Added: lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/eval/GenericRecommenderIRStatsEvaluatorImplTest.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/eval/GenericRecommenderIRStatsEvaluatorImplTest.java?rev=654943&view=auto
==============================================================================
--- lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/eval/GenericRecommenderIRStatsEvaluatorImplTest.java (added)
+++ lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/eval/GenericRecommenderIRStatsEvaluatorImplTest.java Fri May 9 14:35:12 2008
@@ -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.eval;
+
+import org.apache.mahout.cf.taste.common.TasteException;
+import org.apache.mahout.cf.taste.eval.IRStatistics;
+import org.apache.mahout.cf.taste.eval.RecommenderBuilder;
+import org.apache.mahout.cf.taste.eval.RecommenderIRStatsEvaluator;
+import org.apache.mahout.cf.taste.impl.TasteTestCase;
+import org.apache.mahout.cf.taste.impl.recommender.slopeone.SlopeOneRecommender;
+import org.apache.mahout.cf.taste.model.DataModel;
+import org.apache.mahout.cf.taste.recommender.Recommender;
+
+public final class GenericRecommenderIRStatsEvaluatorImplTest extends TasteTestCase {
+
+ public void testEvaluate() throws Exception {
+ DataModel model = getDataModel();
+ RecommenderBuilder builder = new RecommenderBuilder() {
+ public Recommender buildRecommender(DataModel dataModel) throws TasteException {
+ return new SlopeOneRecommender(dataModel);
+ }
+ };
+ RecommenderIRStatsEvaluator evaluator = new GenericRecommenderIRStatsEvaluator();
+ IRStatistics stats = evaluator.evaluate(builder, model, 5, 0.2, 1.0);
+ assertNotNull(stats);
+ assertEquals(0.2, stats.getPrecision(), EPSILON);
+ assertEquals(1.0, stats.getRecall(), EPSILON);
+ assertEquals(0.33333, stats.getF1Measure(), EPSILON);
+ }
+
+}
\ No newline at end of file
Added: lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/eval/RMSRecommenderEvaluatorTest.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/eval/RMSRecommenderEvaluatorTest.java?rev=654943&view=auto
==============================================================================
--- lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/eval/RMSRecommenderEvaluatorTest.java (added)
+++ lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/eval/RMSRecommenderEvaluatorTest.java Fri May 9 14:35:12 2008
@@ -0,0 +1,42 @@
+/**
+ * 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.eval;
+
+import org.apache.mahout.cf.taste.common.TasteException;
+import org.apache.mahout.cf.taste.eval.RecommenderBuilder;
+import org.apache.mahout.cf.taste.eval.RecommenderEvaluator;
+import org.apache.mahout.cf.taste.impl.TasteTestCase;
+import org.apache.mahout.cf.taste.impl.recommender.slopeone.SlopeOneRecommender;
+import org.apache.mahout.cf.taste.model.DataModel;
+import org.apache.mahout.cf.taste.recommender.Recommender;
+
+public final class RMSRecommenderEvaluatorTest extends TasteTestCase {
+
+ public void testEvaluate() throws Exception {
+ DataModel model = getDataModel();
+ RecommenderBuilder builder = new RecommenderBuilder() {
+ public Recommender buildRecommender(DataModel dataModel) throws TasteException {
+ return new SlopeOneRecommender(dataModel);
+ }
+ };
+ RecommenderEvaluator evaluator = new RMSRecommenderEvaluator();
+ double eval = evaluator.evaluate(builder, model, 0.75, 1.0);
+ assertEquals(0.26387685767414826, eval, EPSILON);
+ }
+
+}
\ No newline at end of file
Added: 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=654943&view=auto
==============================================================================
--- lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/model/file/FileDataModelTest.java (added)
+++ lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/model/file/FileDataModelTest.java Fri May 9 14:35:12 2008
@@ -0,0 +1,150 @@
+/**
+ * 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.file;
+
+import org.apache.mahout.cf.taste.common.TasteException;
+import org.apache.mahout.cf.taste.correlation.UserCorrelation;
+import org.apache.mahout.cf.taste.impl.TasteTestCase;
+import org.apache.mahout.cf.taste.impl.correlation.PearsonCorrelation;
+import org.apache.mahout.cf.taste.impl.neighborhood.NearestNUserNeighborhood;
+import org.apache.mahout.cf.taste.impl.recommender.GenericUserBasedRecommender;
+import org.apache.mahout.cf.taste.model.DataModel;
+import org.apache.mahout.cf.taste.model.Item;
+import org.apache.mahout.cf.taste.model.Preference;
+import org.apache.mahout.cf.taste.neighborhood.UserNeighborhood;
+import org.apache.mahout.cf.taste.recommender.Recommender;
+
+import java.io.File;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * <p>Tests {@link FileDataModel}.</p>
+ */
+public final class FileDataModelTest extends TasteTestCase {
+
+ private static final File testFile = new File("src/test/java/org/apache/mahout/cf/taste/impl/model/file/test1.txt");
+
+ private DataModel model;
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ model = new FileDataModel(testFile);
+ }
+
+ public void testFile() throws Exception {
+ UserCorrelation userCorrelation = new PearsonCorrelation(model);
+ UserNeighborhood neighborhood = new NearestNUserNeighborhood(2, userCorrelation, model);
+ Recommender recommender = new GenericUserBasedRecommender(model, neighborhood, userCorrelation);
+ assertEquals(2, recommender.recommend("A123", 3).size());
+ assertEquals(2, recommender.recommend("B234", 3).size());
+ assertEquals(1, recommender.recommend("C345", 3).size());
+
+ // Make sure this doesn't throw an exception
+ model.refresh();
+ }
+
+ public void testItem() throws Exception {
+ assertEquals("456", model.getItem("456").getID());
+ }
+
+ public void testGetItems() throws Exception {
+ Iterable<? extends Item> items = model.getItems();
+ assertNotNull(items);
+ Iterator<? extends Item> it = items.iterator();
+ assertNotNull(it);
+ assertTrue(it.hasNext());
+ assertEquals("123", it.next().getID());
+ assertTrue(it.hasNext());
+ assertEquals("234", it.next().getID());
+ assertTrue(it.hasNext());
+ assertEquals("456", it.next().getID());
+ assertTrue(it.hasNext());
+ assertEquals("654", it.next().getID());
+ assertTrue(it.hasNext());
+ assertEquals("789", it.next().getID());
+ assertFalse(it.hasNext());
+ try {
+ it.next();
+ fail("Should throw NoSuchElementException");
+ } catch (NoSuchElementException nsee) {
+ // good
+ }
+ }
+
+ public void testPreferencesForItem() throws Exception {
+ Iterable<? extends Preference> prefs = model.getPreferencesForItem("456");
+ assertNotNull(prefs);
+ Iterator<? extends Preference> it = prefs.iterator();
+ assertNotNull(it);
+ assertTrue(it.hasNext());
+ Preference pref1 = it.next();
+ assertEquals("A123", pref1.getUser().getID());
+ assertEquals("456", pref1.getItem().getID());
+ assertTrue(it.hasNext());
+ Preference pref2 = it.next();
+ assertEquals("D456", pref2.getUser().getID());
+ assertEquals("456", pref2.getItem().getID());
+ assertFalse(it.hasNext());
+ try {
+ it.next();
+ fail("Should throw NoSuchElementException");
+ } catch (NoSuchElementException nsee) {
+ // good
+ }
+ }
+
+ public void testGetNumUsers() throws Exception {
+ assertEquals(4, model.getNumUsers());
+ }
+
+ public void testSetPreference() throws Exception {
+ try {
+ model.setPreference(null, null, 0.0);
+ fail("Should have thrown UnsupportedOperationException");
+ } catch (UnsupportedOperationException uoe) {
+ // good
+ }
+ }
+
+ public void testRefresh() throws Exception {
+ final AtomicBoolean initialized = new AtomicBoolean(false);
+ Runnable initializer = new Runnable() {
+ public void run() {
+ try {
+ model.getNumUsers();
+ initialized.set(true);
+ } catch (TasteException te) {
+ // oops
+ }
+ }
+ };
+ new Thread(initializer).start();
+ Thread.sleep(1000L); // wait a second for thread to start and call getNumUsers()
+ model.getNumUsers(); // should block
+ assertTrue(initialized.get());
+ assertEquals(4, model.getNumUsers());
+ }
+
+ public void testToString() {
+ assertTrue(model.toString().length() > 0);
+ }
+
+}
Added: lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/model/file/test1.txt
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/model/file/test1.txt?rev=654943&view=auto
==============================================================================
--- lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/model/file/test1.txt (added)
+++ lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/model/file/test1.txt Fri May 9 14:35:12 2008
@@ -0,0 +1,10 @@
+A123,456,0.1
+A123,789,0.6
+A123,654,0.7
+B234,123,0.5
+B234,234,1.0
+C345,789,0.6
+C345,654,0.7
+C345,123,1.0
+C345,234,0.5
+D456,456,0.1
\ No newline at end of file
Added: lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/model/jdbc/MySQLJDBCDataModelTest.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/model/jdbc/MySQLJDBCDataModelTest.java?rev=654943&view=auto
==============================================================================
--- lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/model/jdbc/MySQLJDBCDataModelTest.java (added)
+++ lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/model/jdbc/MySQLJDBCDataModelTest.java Fri May 9 14:35:12 2008
@@ -0,0 +1,208 @@
+/**
+ * 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.jdbc;
+
+import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;
+import org.apache.mahout.cf.taste.correlation.UserCorrelation;
+import org.apache.mahout.cf.taste.impl.TasteTestCase;
+import org.apache.mahout.cf.taste.impl.correlation.PearsonCorrelation;
+import org.apache.mahout.cf.taste.impl.model.GenericItem;
+import org.apache.mahout.cf.taste.impl.model.GenericUser;
+import static org.apache.mahout.cf.taste.impl.model.jdbc.MySQLJDBCDataModel.DEFAULT_ITEM_ID_COLUMN;
+import static org.apache.mahout.cf.taste.impl.model.jdbc.MySQLJDBCDataModel.DEFAULT_PREFERENCE_COLUMN;
+import static org.apache.mahout.cf.taste.impl.model.jdbc.MySQLJDBCDataModel.DEFAULT_PREFERENCE_TABLE;
+import static org.apache.mahout.cf.taste.impl.model.jdbc.MySQLJDBCDataModel.DEFAULT_USER_ID_COLUMN;
+import org.apache.mahout.cf.taste.impl.neighborhood.NearestNUserNeighborhood;
+import org.apache.mahout.cf.taste.impl.recommender.GenericUserBasedRecommender;
+import org.apache.mahout.cf.taste.impl.recommender.slopeone.MemoryDiffStorage;
+import org.apache.mahout.cf.taste.impl.recommender.slopeone.SlopeOneRecommender;
+import org.apache.mahout.cf.taste.model.DataModel;
+import org.apache.mahout.cf.taste.model.Item;
+import org.apache.mahout.cf.taste.model.Preference;
+import org.apache.mahout.cf.taste.model.User;
+import org.apache.mahout.cf.taste.neighborhood.UserNeighborhood;
+import org.apache.mahout.cf.taste.recommender.Recommender;
+import org.apache.mahout.cf.taste.recommender.slopeone.DiffStorage;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+/**
+ * <p>Tests {@link MySQLJDBCDataModel}.</p>
+ *
+ * <p>Requires a MySQL 4.x+ database running on the localhost, with a passwordless user named "mysql" available,
+ * a database named "test".</p>
+ */
+public final class MySQLJDBCDataModelTest extends TasteTestCase {
+
+ private DataModel model;
+
+ @Override
+ public void setUp() throws Exception {
+
+ super.setUp();
+
+ MysqlDataSource dataSource = new MysqlDataSource();
+ dataSource.setUser("mysql");
+ dataSource.setDatabaseName("test");
+ dataSource.setServerName("localhost");
+
+ Connection connection = dataSource.getConnection();
+ try {
+
+ PreparedStatement dropStatement =
+ connection.prepareStatement("DROP TABLE IF EXISTS " + DEFAULT_PREFERENCE_TABLE);
+ try {
+ dropStatement.execute();
+ } finally {
+ dropStatement.close();
+ }
+
+ PreparedStatement createStatement =
+ connection.prepareStatement("CREATE TABLE " + DEFAULT_PREFERENCE_TABLE + " (" +
+ DEFAULT_USER_ID_COLUMN + " VARCHAR(4) NOT NULL, " +
+ DEFAULT_ITEM_ID_COLUMN + " VARCHAR(4) NOT NULL, " +
+ DEFAULT_PREFERENCE_COLUMN + " FLOAT NOT NULL, " +
+ "PRIMARY KEY (" + DEFAULT_USER_ID_COLUMN + ", " +
+ DEFAULT_ITEM_ID_COLUMN + "), " +
+ "INDEX (" + DEFAULT_USER_ID_COLUMN + "), " +
+ "INDEX (" + DEFAULT_ITEM_ID_COLUMN + ") )");
+ try {
+ createStatement.execute();
+ } finally {
+ createStatement.close();
+ }
+
+ PreparedStatement insertStatement =
+ connection.prepareStatement("INSERT INTO " + DEFAULT_PREFERENCE_TABLE + " VALUES (?, ?, ?)");
+ try {
+ String[] users =
+ new String[]{"A123", "A123", "A123", "B234", "B234", "C345", "C345", "C345", "C345", "D456"};
+ String[] itemIDs =
+ new String[]{"456", "789", "654", "123", "234", "789", "654", "123", "234", "456"};
+ double[] preferences = new double[]{0.1, 0.6, 0.7, 0.5, 1.0, 0.6, 0.7, 1.0, 0.5, 0.1};
+ for (int i = 0; i < users.length; i++) {
+ insertStatement.setString(1, users[i]);
+ insertStatement.setString(2, itemIDs[i]);
+ insertStatement.setDouble(3, preferences[i]);
+ insertStatement.execute();
+ }
+ } finally {
+ insertStatement.close();
+ }
+
+ } finally {
+ connection.close();
+ }
+
+ model = new MySQLJDBCDataModel(dataSource);
+ }
+
+ public void testStatements() throws Exception {
+ assertEquals(4, model.getNumUsers());
+ assertEquals(5, model.getNumItems());
+ assertEquals(new GenericUser<String>("A123", Collections.<Preference>emptyList()), model.getUser("A123"));
+ assertEquals(new GenericItem<String>("456"), model.getItem("456"));
+ Preference pref = model.getUser("A123").getPreferenceFor("456");
+ assertNotNull(pref);
+ assertEquals(0.1, pref.getValue(), EPSILON);
+ model.setPreference("A123", "456", 0.2);
+ Preference pref1 = model.getUser("A123").getPreferenceFor("456");
+ assertNotNull(pref1);
+ assertEquals(0.2, pref1.getValue(), EPSILON);
+ model.removePreference("A123", "456");
+ assertNull(model.getUser("A123").getPreferenceFor("456"));
+ }
+
+ public void testDatabase() throws Exception {
+ UserCorrelation userCorrelation = new PearsonCorrelation(model);
+ UserNeighborhood neighborhood = new NearestNUserNeighborhood(2, userCorrelation, model);
+ Recommender recommender = new GenericUserBasedRecommender(model, neighborhood, userCorrelation);
+ assertEquals(2, recommender.recommend("A123", 3).size());
+ assertEquals(2, recommender.recommend("B234", 3).size());
+ assertEquals(1, recommender.recommend("C345", 3).size());
+
+ // Make sure this doesn't throw an exception
+ model.refresh();
+ }
+
+ public void testItem() throws Exception {
+ assertEquals("456", model.getItem("456").getID());
+ }
+
+ public void testPreferencesForItem() throws Exception {
+ Iterable<? extends Preference> prefs = model.getPreferencesForItem("456");
+ assertNotNull(prefs);
+ Iterator<? extends Preference> it = prefs.iterator();
+ assertNotNull(it);
+ assertTrue(it.hasNext());
+ Preference pref1 = it.next();
+ assertEquals("A123", pref1.getUser().getID());
+ assertEquals("456", pref1.getItem().getID());
+ assertTrue(it.hasNext());
+ Preference pref2 = it.next();
+ assertEquals("D456", pref2.getUser().getID());
+ assertEquals("456", pref2.getItem().getID());
+ assertFalse(it.hasNext());
+ try {
+ it.next();
+ fail("Should throw NoSuchElementException");
+ } catch (NoSuchElementException nsee) {
+ // good
+ }
+ }
+
+ public void testPreferencesForItemOrder() throws Exception {
+ for (Item item : model.getItems()) {
+ Iterable<? extends Preference> prefs = model.getPreferencesForItem(item.getID());
+ User lastUser = null;
+ for (Preference pref : prefs) {
+ User thisUser = pref.getUser();
+ if (lastUser != null) {
+ String lastID = (String) lastUser.getID();
+ String ID = (String) thisUser.getID();
+ assertTrue(lastID.compareTo(ID) < 0);
+ }
+ lastUser = thisUser;
+ }
+ }
+ }
+
+ public void testSetPreference() throws Exception {
+ model.setPreference("A123", "409", 2.0);
+ Preference pref = model.getUser("A123").getPreferenceFor("409");
+ assertNotNull(pref);
+ assertEquals(2.0, pref.getValue());
+ model.setPreference("A123", "409", 1.0);
+ Preference pref1 = model.getUser("A123").getPreferenceFor("409");
+ assertNotNull(pref1);
+ assertEquals(1.0, pref1.getValue());
+ }
+
+ public void testSetPrefMemoryDiffUpdates() throws Exception {
+ DiffStorage diffStorage = new MemoryDiffStorage(model, false, false, Long.MAX_VALUE);
+ Recommender recommender = new SlopeOneRecommender(model, true, true, diffStorage);
+ assertEquals(0.5, diffStorage.getDiff("456", "789").getAverage(), EPSILON);
+ recommender.setPreference("A123", "456", 0.7);
+ assertEquals(-0.1, diffStorage.getDiff("456", "789").getAverage(), EPSILON);
+ }
+
+}
Added: lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/neighborhood/DummyCorrelation.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/neighborhood/DummyCorrelation.java?rev=654943&view=auto
==============================================================================
--- lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/neighborhood/DummyCorrelation.java (added)
+++ lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/neighborhood/DummyCorrelation.java Fri May 9 14:35:12 2008
@@ -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.neighborhood;
+
+import org.apache.mahout.cf.taste.correlation.ItemCorrelation;
+import org.apache.mahout.cf.taste.correlation.PreferenceInferrer;
+import org.apache.mahout.cf.taste.correlation.UserCorrelation;
+import org.apache.mahout.cf.taste.model.Item;
+import org.apache.mahout.cf.taste.model.User;
+
+final class DummyCorrelation implements UserCorrelation, ItemCorrelation {
+
+ public double userCorrelation(User user1, User user2) {
+ return 1.0 / Math.abs(user1.getPreferencesAsArray()[0].getValue() -
+ user2.getPreferencesAsArray()[0].getValue());
+ }
+
+ public double itemCorrelation(Item item1, Item item2) {
+ // Make up something wacky
+ return (double) (item1.hashCode() - item2.hashCode());
+ }
+
+ public void setPreferenceInferrer(PreferenceInferrer inferrer) {
+ throw new UnsupportedOperationException();
+ }
+
+ public void refresh() {
+ // do nothing
+ }
+
+}
Added: lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/neighborhood/NearestNNeighborhoodTest.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/neighborhood/NearestNNeighborhoodTest.java?rev=654943&view=auto
==============================================================================
--- lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/neighborhood/NearestNNeighborhoodTest.java (added)
+++ lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/neighborhood/NearestNNeighborhoodTest.java Fri May 9 14:35:12 2008
@@ -0,0 +1,68 @@
+/**
+ * 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.neighborhood;
+
+import org.apache.mahout.cf.taste.impl.model.GenericDataModel;
+import org.apache.mahout.cf.taste.impl.TasteTestCase;
+import org.apache.mahout.cf.taste.model.DataModel;
+import org.apache.mahout.cf.taste.model.User;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * <p>Tests {@link NearestNUserNeighborhood}.</p>
+ */
+public final class NearestNNeighborhoodTest extends TasteTestCase {
+
+ public void testNeighborhood() throws Exception {
+
+ List<User> users = getMockUsers();
+ DataModel dataModel = new GenericDataModel(users);
+
+ Collection<User> neighborhood =
+ new NearestNUserNeighborhood(1, new DummyCorrelation(), dataModel).getUserNeighborhood("test1");
+ assertNotNull(neighborhood);
+ assertEquals(1, neighborhood.size());
+ assertTrue(neighborhood.contains(users.get(1)));
+
+ Collection<User> neighborhood2 =
+ new NearestNUserNeighborhood(2, new DummyCorrelation(), dataModel).getUserNeighborhood("test2");
+ assertNotNull(neighborhood2);
+ assertEquals(2, neighborhood2.size());
+ assertTrue(neighborhood2.contains(users.get(0)));
+ assertTrue(neighborhood2.contains(users.get(2)));
+
+ Collection<User> neighborhood3 =
+ new NearestNUserNeighborhood(4, new DummyCorrelation(), dataModel).getUserNeighborhood("test4");
+ assertNotNull(neighborhood3);
+ assertEquals(3, neighborhood3.size());
+ assertTrue(neighborhood3.contains(users.get(0)));
+ assertTrue(neighborhood3.contains(users.get(1)));
+ assertTrue(neighborhood3.contains(users.get(2)));
+
+ }
+
+ public void testRefresh() throws Exception {
+ // Make sure this doesn't throw an exception
+ DataModel dataModel = new GenericDataModel(Collections.singletonList(getUser("test1", 0.1)));
+ new NearestNUserNeighborhood(1, new DummyCorrelation(), dataModel).refresh();
+ }
+
+}
Added: lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/neighborhood/ThresholdNeighborhoodTest.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/neighborhood/ThresholdNeighborhoodTest.java?rev=654943&view=auto
==============================================================================
--- lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/neighborhood/ThresholdNeighborhoodTest.java (added)
+++ lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/neighborhood/ThresholdNeighborhoodTest.java Fri May 9 14:35:12 2008
@@ -0,0 +1,66 @@
+/**
+ * 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.neighborhood;
+
+import org.apache.mahout.cf.taste.impl.model.GenericDataModel;
+import org.apache.mahout.cf.taste.impl.TasteTestCase;
+import org.apache.mahout.cf.taste.model.DataModel;
+import org.apache.mahout.cf.taste.model.User;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * <p>Tests {@link ThresholdUserNeighborhood}.</p>
+ */
+public final class ThresholdNeighborhoodTest extends TasteTestCase {
+
+ public void testNeighborhood() throws Exception {
+
+ List<User> users = getMockUsers();
+ DataModel dataModel = new GenericDataModel(users);
+
+ Collection<User> neighborhood =
+ new ThresholdUserNeighborhood(20.0, new DummyCorrelation(), dataModel).getUserNeighborhood("test1");
+ assertNotNull(neighborhood);
+ assertTrue(neighborhood.isEmpty());
+
+ Collection<User> neighborhood2 =
+ new ThresholdUserNeighborhood(10.0, new DummyCorrelation(), dataModel).getUserNeighborhood("test1");
+ assertNotNull(neighborhood2);
+ assertEquals(1, neighborhood2.size());
+ assertTrue(neighborhood2.contains(users.get(1)));
+
+ Collection<User> neighborhood3 =
+ new ThresholdUserNeighborhood(1.0, new DummyCorrelation(), dataModel).getUserNeighborhood("test2");
+ assertNotNull(neighborhood3);
+ assertEquals(3, neighborhood3.size());
+ assertTrue(neighborhood3.contains(users.get(0)));
+ assertTrue(neighborhood3.contains(users.get(2)));
+ assertTrue(neighborhood3.contains(users.get(3)));
+
+ }
+
+ public void testRefresh() throws Exception {
+ // Make sure this doesn't throw an exception
+ DataModel dataModel = new GenericDataModel(Collections.singletonList(getUser("test1", 0.1)));
+ new ThresholdUserNeighborhood(20.0, new DummyCorrelation(), dataModel).refresh();
+ }
+
+}
Added: lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/recommender/CachingRecommenderTest.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/recommender/CachingRecommenderTest.java?rev=654943&view=auto
==============================================================================
--- lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/recommender/CachingRecommenderTest.java (added)
+++ lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/recommender/CachingRecommenderTest.java Fri May 9 14:35:12 2008
@@ -0,0 +1,74 @@
+/**
+ * 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.Item;
+import org.apache.mahout.cf.taste.recommender.Recommender;
+import org.apache.mahout.cf.taste.recommender.Rescorer;
+import org.apache.mahout.cf.taste.impl.TasteTestCase;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * <p>Tests {@link CachingRecommender}.</p>
+ */
+public final class CachingRecommenderTest extends TasteTestCase {
+
+ public void testRecommender() throws Exception {
+ AtomicInteger recommendCount = new AtomicInteger();
+ Recommender mockRecommender = new MockRecommender(recommendCount);
+
+ Recommender cachingRecommender = new CachingRecommender(mockRecommender);
+ cachingRecommender.recommend("1", 1);
+ assertEquals(1, recommendCount.get());
+ cachingRecommender.recommend("2", 1);
+ assertEquals(2, recommendCount.get());
+ cachingRecommender.recommend("1", 1);
+ assertEquals(2, recommendCount.get());
+ cachingRecommender.recommend("2", 1);
+ assertEquals(2, recommendCount.get());
+ cachingRecommender.refresh();
+ cachingRecommender.recommend("1", 1);
+ assertEquals(3, recommendCount.get());
+ cachingRecommender.recommend("2", 1);
+ assertEquals(4, recommendCount.get());
+ cachingRecommender.recommend("3", 1);
+ assertEquals(5, recommendCount.get());
+
+ // Results from this recommend() method can't be cached:
+ Rescorer<Item> rescorer = NullRescorer.getItemInstance();
+ cachingRecommender.refresh();
+ cachingRecommender.recommend("1", 1, rescorer);
+ assertEquals(6, recommendCount.get());
+ cachingRecommender.recommend("2", 1, rescorer);
+ assertEquals(7, recommendCount.get());
+ cachingRecommender.recommend("1", 1, rescorer);
+ assertEquals(8, recommendCount.get());
+ cachingRecommender.recommend("2", 1, rescorer);
+ assertEquals(9, recommendCount.get());
+
+ cachingRecommender.refresh();
+ cachingRecommender.estimatePreference("test1", "1");
+ assertEquals(10, recommendCount.get());
+ cachingRecommender.estimatePreference("test1", "2");
+ assertEquals(11, recommendCount.get());
+ cachingRecommender.estimatePreference("test1", "2");
+ assertEquals(11, recommendCount.get());
+ }
+
+}
Added: 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=654943&view=auto
==============================================================================
--- lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/recommender/GenericItemBasedRecommenderTest.java (added)
+++ lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/recommender/GenericItemBasedRecommenderTest.java Fri May 9 14:35:12 2008
@@ -0,0 +1,216 @@
+/**
+ * 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.correlation.ItemCorrelation;
+import org.apache.mahout.cf.taste.impl.correlation.GenericItemCorrelation;
+import org.apache.mahout.cf.taste.impl.model.GenericDataModel;
+import org.apache.mahout.cf.taste.impl.model.GenericItem;
+import org.apache.mahout.cf.taste.impl.TasteTestCase;
+import org.apache.mahout.cf.taste.model.DataModel;
+import org.apache.mahout.cf.taste.model.Item;
+import org.apache.mahout.cf.taste.model.User;
+import org.apache.mahout.cf.taste.recommender.ItemBasedRecommender;
+import org.apache.mahout.cf.taste.recommender.RecommendedItem;
+import org.apache.mahout.cf.taste.recommender.Recommender;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * <p>Tests {@link GenericItemBasedRecommender}.</p>
+ */
+public final class GenericItemBasedRecommenderTest extends TasteTestCase {
+
+ public void testRecommender() throws Exception {
+ Recommender recommender = buildRecommender();
+ List<RecommendedItem> recommended = recommender.recommend("test1", 1);
+ assertNotNull(recommended);
+ assertEquals(1, recommended.size());
+ RecommendedItem firstRecommended = recommended.get(0);
+ assertEquals(new GenericItem<String>("2"), firstRecommended.getItem());
+ assertEquals(0.1, firstRecommended.getValue(), EPSILON);
+ }
+
+ public void testHowMany() throws Exception {
+ List<User> users = new ArrayList<User>(3);
+ users.add(getUser("test1", 0.1, 0.2));
+ users.add(getUser("test2", 0.2, 0.3, 0.3, 0.6));
+ users.add(getUser("test3", 0.4, 0.4, 0.5, 0.9));
+ users.add(getUser("test4", 0.1, 0.4, 0.5, 0.8, 0.9, 1.0));
+ users.add(getUser("test5", 0.2, 0.3, 0.6, 0.7, 0.1, 0.2));
+ DataModel dataModel = new GenericDataModel(users);
+ Collection<GenericItemCorrelation.ItemItemCorrelation> correlations =
+ new ArrayList<GenericItemCorrelation.ItemItemCorrelation>(6);
+ for (int i = 0; i < 6; i++) {
+ for (int j = i + 1; j < 6; j++) {
+ correlations.add(
+ new GenericItemCorrelation.ItemItemCorrelation(new GenericItem<String>(String.valueOf(i)),
+ new GenericItem<String>(String.valueOf(j)),
+ 1.0 / (1.0 + (double) i + (double) j)));
+ }
+ }
+ ItemCorrelation correlation = new GenericItemCorrelation(correlations);
+ Recommender recommender = new GenericItemBasedRecommender(dataModel, correlation);
+ List<RecommendedItem> fewRecommended = recommender.recommend("test1", 2);
+ List<RecommendedItem> moreRecommended = recommender.recommend("test1", 4);
+ for (int i = 0; i < fewRecommended.size(); i++) {
+ assertEquals(fewRecommended.get(i).getItem(), moreRecommended.get(i).getItem());
+ }
+ }
+
+ public void testRescorer() throws Exception {
+ List<User> users = new ArrayList<User>(3);
+ users.add(getUser("test1", 0.1, 0.2));
+ users.add(getUser("test2", 0.2, 0.3, 0.3, 0.6));
+ users.add(getUser("test3", 0.4, 0.4, 0.5, 0.9));
+ DataModel dataModel = new GenericDataModel(users);
+ Item item1 = new GenericItem<String>("0");
+ Item item2 = new GenericItem<String>("1");
+ Item item3 = new GenericItem<String>("2");
+ Item item4 = new GenericItem<String>("3");
+ Collection<GenericItemCorrelation.ItemItemCorrelation> correlations =
+ new ArrayList<GenericItemCorrelation.ItemItemCorrelation>(6);
+ correlations.add(new GenericItemCorrelation.ItemItemCorrelation(item1, item2, 1.0));
+ correlations.add(new GenericItemCorrelation.ItemItemCorrelation(item1, item3, 0.5));
+ correlations.add(new GenericItemCorrelation.ItemItemCorrelation(item1, item4, 0.2));
+ correlations.add(new GenericItemCorrelation.ItemItemCorrelation(item2, item3, 0.7));
+ correlations.add(new GenericItemCorrelation.ItemItemCorrelation(item2, item4, 0.5));
+ correlations.add(new GenericItemCorrelation.ItemItemCorrelation(item3, item4, 0.9));
+ ItemCorrelation correlation = new GenericItemCorrelation(correlations);
+ Recommender recommender = new GenericItemBasedRecommender(dataModel, correlation);
+ List<RecommendedItem> originalRecommended = recommender.recommend("test1", 2);
+ List<RecommendedItem> rescoredRecommended =
+ recommender.recommend("test1", 2, new ReversingRescorer<Item>());
+ assertNotNull(originalRecommended);
+ assertNotNull(rescoredRecommended);
+ assertEquals(2, originalRecommended.size());
+ assertEquals(2, rescoredRecommended.size());
+ assertEquals(originalRecommended.get(0).getItem(), rescoredRecommended.get(1).getItem());
+ assertEquals(originalRecommended.get(1).getItem(), rescoredRecommended.get(0).getItem());
+ }
+
+ public void testEstimatePref() throws Exception {
+ Recommender recommender = buildRecommender();
+ assertEquals(0.1, recommender.estimatePreference("test1", "2"), EPSILON);
+ }
+
+ /**
+ * Contributed test case that verifies fix for bug
+ * <a href="http://sourceforge.net/tracker/index.php?func=detail&aid=1396128&group_id=138771&atid=741665">
+ * 1396128</a>.
+ */
+ public void testBestRating() throws Exception {
+ Recommender recommender = buildRecommender();
+ List<RecommendedItem> recommended = recommender.recommend("test1", 1);
+ assertNotNull(recommended);
+ assertEquals(1, recommended.size());
+ RecommendedItem firstRecommended = recommended.get(0);
+ // item one should be recommended because it has a greater rating/score
+ assertEquals(new GenericItem<String>("2"), firstRecommended.getItem());
+ assertEquals(0.1, firstRecommended.getValue(), EPSILON);
+ }
+
+ public void testMostSimilar() throws Exception {
+ ItemBasedRecommender recommender = buildRecommender();
+ List<RecommendedItem> similar = recommender.mostSimilarItems("0", 2);
+ assertNotNull(similar);
+ assertEquals(2, similar.size());
+ RecommendedItem first = similar.get(0);
+ RecommendedItem second = similar.get(1);
+ assertEquals("1", first.getItem().getID());
+ assertEquals(1.0, first.getValue(), EPSILON);
+ assertEquals("2", second.getItem().getID());
+ assertEquals(0.5, second.getValue(), EPSILON);
+ }
+
+ public void testMostSimilarToMultiple() throws Exception {
+ ItemBasedRecommender recommender = buildRecommender2();
+ List<Object> itemIDs = new ArrayList<Object>(2);
+ itemIDs.add("0");
+ itemIDs.add("1");
+ List<RecommendedItem> similar = recommender.mostSimilarItems(itemIDs, 2);
+ assertNotNull(similar);
+ assertEquals(2, similar.size());
+ RecommendedItem first = similar.get(0);
+ RecommendedItem second = similar.get(1);
+ assertEquals("2", first.getItem().getID());
+ assertEquals(0.85, first.getValue(), EPSILON);
+ assertEquals("3", second.getItem().getID());
+ assertEquals(-0.3, second.getValue(), EPSILON);
+ }
+
+ public void testRecommendedBecause() throws Exception {
+ ItemBasedRecommender recommender = buildRecommender2();
+ List<RecommendedItem> recommendedBecause = recommender.recommendedBecause("test1", "4", 3);
+ assertNotNull(recommendedBecause);
+ assertEquals(3, recommendedBecause.size());
+ RecommendedItem first = recommendedBecause.get(0);
+ RecommendedItem second = recommendedBecause.get(1);
+ RecommendedItem third = recommendedBecause.get(2);
+ assertEquals("2", first.getItem().getID());
+ assertEquals(0.99, first.getValue(), EPSILON);
+ assertEquals("3", second.getItem().getID());
+ assertEquals(0.4, second.getValue(), EPSILON);
+ assertEquals("0", third.getItem().getID());
+ assertEquals(0.2, third.getValue(), EPSILON);
+ }
+
+ private static ItemBasedRecommender buildRecommender() {
+ DataModel dataModel = new GenericDataModel(getMockUsers());
+ Collection<GenericItemCorrelation.ItemItemCorrelation> correlations =
+ new ArrayList<GenericItemCorrelation.ItemItemCorrelation>(2);
+ Item item1 = new GenericItem<String>("0");
+ Item item2 = new GenericItem<String>("1");
+ Item item3 = new GenericItem<String>("2");
+ correlations.add(new GenericItemCorrelation.ItemItemCorrelation(item1, item2, 1.0));
+ correlations.add(new GenericItemCorrelation.ItemItemCorrelation(item1, item3, 0.5));
+ ItemCorrelation correlation = new GenericItemCorrelation(correlations);
+ return new GenericItemBasedRecommender(dataModel, correlation);
+ }
+
+ private static ItemBasedRecommender buildRecommender2() {
+ List<User> users = new ArrayList<User>(4);
+ users.add(getUser("test1", 0.1, 0.3, 0.9, 0.8));
+ users.add(getUser("test2", 0.2, 0.3, 0.3, 0.4));
+ users.add(getUser("test3", 0.4, 0.3, 0.5, 0.1, 0.1));
+ users.add(getUser("test4", 0.7, 0.3, 0.8, 0.5, 0.6));
+ DataModel dataModel = new GenericDataModel(users);
+ Collection<GenericItemCorrelation.ItemItemCorrelation> correlations =
+ new ArrayList<GenericItemCorrelation.ItemItemCorrelation>(10);
+ Item item1 = new GenericItem<String>("0");
+ Item item2 = new GenericItem<String>("1");
+ Item item3 = new GenericItem<String>("2");
+ Item item4 = new GenericItem<String>("3");
+ Item item5 = new GenericItem<String>("4");
+ correlations.add(new GenericItemCorrelation.ItemItemCorrelation(item1, item2, 1.0));
+ correlations.add(new GenericItemCorrelation.ItemItemCorrelation(item1, item3, 0.8));
+ correlations.add(new GenericItemCorrelation.ItemItemCorrelation(item1, item4, -0.6));
+ correlations.add(new GenericItemCorrelation.ItemItemCorrelation(item1, item5, 1.0));
+ correlations.add(new GenericItemCorrelation.ItemItemCorrelation(item2, item3, 0.9));
+ correlations.add(new GenericItemCorrelation.ItemItemCorrelation(item2, item4, 0.0));
+ correlations.add(new GenericItemCorrelation.ItemItemCorrelation(item2, item2, 1.0));
+ correlations.add(new GenericItemCorrelation.ItemItemCorrelation(item3, item4, -0.1));
+ correlations.add(new GenericItemCorrelation.ItemItemCorrelation(item3, item5, 0.1));
+ correlations.add(new GenericItemCorrelation.ItemItemCorrelation(item4, item5, -0.5));
+ ItemCorrelation correlation = new GenericItemCorrelation(correlations);
+ return new GenericItemBasedRecommender(dataModel, correlation);
+ }
+
+}
Added: 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=654943&view=auto
==============================================================================
--- lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/recommender/GenericUserBasedRecommenderTest.java (added)
+++ lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/recommender/GenericUserBasedRecommenderTest.java Fri May 9 14:35:12 2008
@@ -0,0 +1,140 @@
+/**
+ * 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.correlation.UserCorrelation;
+import org.apache.mahout.cf.taste.impl.correlation.PearsonCorrelation;
+import org.apache.mahout.cf.taste.impl.model.GenericDataModel;
+import org.apache.mahout.cf.taste.impl.model.GenericItem;
+import org.apache.mahout.cf.taste.impl.neighborhood.NearestNUserNeighborhood;
+import org.apache.mahout.cf.taste.impl.TasteTestCase;
+import org.apache.mahout.cf.taste.model.DataModel;
+import org.apache.mahout.cf.taste.model.Item;
+import org.apache.mahout.cf.taste.model.User;
+import org.apache.mahout.cf.taste.neighborhood.UserNeighborhood;
+import org.apache.mahout.cf.taste.recommender.RecommendedItem;
+import org.apache.mahout.cf.taste.recommender.Recommender;
+import org.apache.mahout.cf.taste.recommender.UserBasedRecommender;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * <p>Tests {@link GenericUserBasedRecommender}.</p>
+ */
+public final class GenericUserBasedRecommenderTest extends TasteTestCase {
+
+ public void testRecommender() throws Exception {
+ Recommender recommender = buildRecommender();
+ List<RecommendedItem> recommended = recommender.recommend("test1", 1);
+ assertNotNull(recommended);
+ assertEquals(1, recommended.size());
+ RecommendedItem firstRecommended = recommended.get(0);
+ assertEquals(new GenericItem<String>("2"), firstRecommended.getItem());
+ assertEquals(0.3, firstRecommended.getValue());
+ }
+
+ public void testHowMany() throws Exception {
+ List<User> users = new ArrayList<User>(3);
+ users.add(getUser("test1", 0.1, 0.2));
+ users.add(getUser("test2", 0.2, 0.3, 0.3, 0.6));
+ users.add(getUser("test3", 0.4, 0.4, 0.5, 0.9));
+ users.add(getUser("test4", 0.1, 0.4, 0.5, 0.8, 0.9, 1.0));
+ users.add(getUser("test5", 0.2, 0.3, 0.6, 0.7, 0.1, 0.2));
+ DataModel dataModel = new GenericDataModel(users);
+ UserCorrelation correlation = new PearsonCorrelation(dataModel);
+ UserNeighborhood neighborhood = new NearestNUserNeighborhood(2, correlation, dataModel);
+ Recommender recommender = new GenericUserBasedRecommender(dataModel, neighborhood, correlation);
+ List<RecommendedItem> fewRecommended = recommender.recommend("test1", 2);
+ List<RecommendedItem> moreRecommended = recommender.recommend("test1", 4);
+ for (int i = 0; i < fewRecommended.size(); i++) {
+ assertEquals(fewRecommended.get(i).getItem(), moreRecommended.get(i).getItem());
+ }
+ }
+
+ public void testRescorer() throws Exception {
+ List<User> users = new ArrayList<User>(3);
+ users.add(getUser("test1", 0.1, 0.2));
+ users.add(getUser("test2", 0.2, 0.3, 0.3, 0.6));
+ users.add(getUser("test3", 0.4, 0.4, 0.5, 0.9));
+ DataModel dataModel = new GenericDataModel(users);
+ UserCorrelation correlation = new PearsonCorrelation(dataModel);
+ UserNeighborhood neighborhood = new NearestNUserNeighborhood(1, correlation, dataModel);
+ Recommender recommender = new GenericUserBasedRecommender(dataModel, neighborhood, correlation);
+ List<RecommendedItem> originalRecommended = recommender.recommend("test1", 2);
+ List<RecommendedItem> rescoredRecommended =
+ recommender.recommend("test1", 2, new ReversingRescorer<Item>());
+ assertNotNull(originalRecommended);
+ assertNotNull(rescoredRecommended);
+ assertEquals(2, originalRecommended.size());
+ assertEquals(2, rescoredRecommended.size());
+ assertEquals(originalRecommended.get(0).getItem(), rescoredRecommended.get(1).getItem());
+ assertEquals(originalRecommended.get(1).getItem(), rescoredRecommended.get(0).getItem());
+ }
+
+ public void testEstimatePref() throws Exception {
+ Recommender recommender = buildRecommender();
+ assertEquals(0.3, recommender.estimatePreference("test1", "2"));
+ }
+
+ public void testBestRating() throws Exception {
+ Recommender recommender = buildRecommender();
+ List<RecommendedItem> recommended = recommender.recommend("test1", 1);
+ assertNotNull(recommended);
+ assertEquals(1, recommended.size());
+ RecommendedItem firstRecommended = recommended.get(0);
+ // item one should be recommended because it has a greater rating/score
+ assertEquals(new GenericItem<String>("2"), firstRecommended.getItem());
+ assertEquals(0.3, firstRecommended.getValue(), EPSILON);
+ }
+
+ public void testMostSimilar() throws Exception {
+ UserBasedRecommender recommender = buildRecommender();
+ List<User> similar = recommender.mostSimilarUsers("test1", 2);
+ assertNotNull(similar);
+ assertEquals(2, similar.size());
+ User first = similar.get(0);
+ User second = similar.get(1);
+ assertEquals("test2", first.getID());
+ assertEquals("test3", second.getID());
+ }
+
+ public void testIsolatedUser() throws Exception {
+ List<User> users = new ArrayList<User>(3);
+ users.add(getUser("test1", 0.1, 0.2));
+ users.add(getUser("test2", 0.2, 0.3, 0.3, 0.6));
+ users.add(getUser("test3", 0.4, 0.4, 0.5, 0.9));
+ users.add(getUser("test4"));
+ DataModel dataModel = new GenericDataModel(users);
+ UserCorrelation correlation = new PearsonCorrelation(dataModel);
+ UserNeighborhood neighborhood = new NearestNUserNeighborhood(3, correlation, dataModel);
+ UserBasedRecommender recommender = new GenericUserBasedRecommender(dataModel, neighborhood, correlation);
+ Collection<User> mostSimilar = recommender.mostSimilarUsers("test4", 3);
+ assertNotNull(mostSimilar);
+ assertEquals(0, mostSimilar.size());
+ }
+
+ private static UserBasedRecommender buildRecommender() throws Exception {
+ DataModel dataModel = new GenericDataModel(getMockUsers());
+ UserCorrelation correlation = new PearsonCorrelation(dataModel);
+ UserNeighborhood neighborhood = new NearestNUserNeighborhood(1, correlation, dataModel);
+ return new GenericUserBasedRecommender(dataModel, neighborhood, correlation);
+ }
+
+}
Added: lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/recommender/MockRecommender.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/recommender/MockRecommender.java?rev=654943&view=auto
==============================================================================
--- lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/recommender/MockRecommender.java (added)
+++ lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/recommender/MockRecommender.java Fri May 9 14:35:12 2008
@@ -0,0 +1,85 @@
+/**
+ * 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.impl.model.GenericDataModel;
+import org.apache.mahout.cf.taste.impl.model.GenericItem;
+import org.apache.mahout.cf.taste.impl.model.GenericUser;
+import org.apache.mahout.cf.taste.model.DataModel;
+import org.apache.mahout.cf.taste.model.Item;
+import org.apache.mahout.cf.taste.model.Preference;
+import org.apache.mahout.cf.taste.model.User;
+import org.apache.mahout.cf.taste.recommender.RecommendedItem;
+import org.apache.mahout.cf.taste.recommender.Recommender;
+import org.apache.mahout.cf.taste.recommender.Rescorer;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+
+
+final class MockRecommender implements Recommender {
+
+ private final AtomicInteger recommendCount;
+
+ MockRecommender(AtomicInteger recommendCount) {
+ this.recommendCount = recommendCount;
+ }
+
+ public List<RecommendedItem> recommend(Object userID, int howMany) {
+ recommendCount.incrementAndGet();
+ return Collections.<RecommendedItem>singletonList(
+ new GenericRecommendedItem(new GenericItem<String>("1"), 1.0));
+ }
+
+ public List<RecommendedItem> recommend(Object userID,
+ int howMany,
+ Rescorer<Item> rescorer) {
+ return recommend(userID, howMany);
+ }
+
+ public double estimatePreference(Object userID, Object itemID) {
+ recommendCount.incrementAndGet();
+ return 0.0;
+ }
+
+ public void setPreference(Object userID, Object itemID, double value) {
+ // do nothing
+ }
+
+ public void removePreference(Object userID, Object itemID) {
+ // do nothing
+ }
+
+ public DataModel getDataModel() {
+ User user1 = new GenericUser<String>("1", Collections.<Preference>emptyList());
+ User user2 = new GenericUser<String>("2", Collections.<Preference>emptyList());
+ User user3 = new GenericUser<String>("3", Collections.<Preference>emptyList());
+ List<User> users = new ArrayList<User>(3);
+ users.add(user1);
+ users.add(user2);
+ users.add(user3);
+ return new GenericDataModel(users);
+ }
+
+ public void refresh() {
+ // do nothing
+ }
+
+}
Added: lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/recommender/NullRescorerTest.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/recommender/NullRescorerTest.java?rev=654943&view=auto
==============================================================================
--- lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/recommender/NullRescorerTest.java (added)
+++ lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/recommender/NullRescorerTest.java Fri May 9 14:35:12 2008
@@ -0,0 +1,55 @@
+/**
+ * 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 junit.framework.TestCase;
+import org.apache.mahout.cf.taste.impl.model.GenericItem;
+import org.apache.mahout.cf.taste.impl.model.GenericUser;
+import org.apache.mahout.cf.taste.model.Item;
+import org.apache.mahout.cf.taste.model.Preference;
+import org.apache.mahout.cf.taste.model.User;
+import org.apache.mahout.cf.taste.recommender.Rescorer;
+
+import java.util.Collections;
+
+/**
+ * <p>Tests {@link NullRescorer}.</p>
+ */
+public final class NullRescorerTest extends TestCase {
+
+ public void testItemRescorer() throws Exception {
+ Rescorer<Item> rescorer = NullRescorer.getItemInstance();
+ assertNotNull(rescorer);
+ Item item = new GenericItem<String>("test");
+ assertEquals(1.0, rescorer.rescore(item, 1.0));
+ assertEquals(1.0, rescorer.rescore(null, 1.0));
+ assertEquals(0.0, rescorer.rescore(item, 0.0));
+ assertTrue(Double.isNaN(rescorer.rescore(item, Double.NaN)));
+ }
+
+ public void testUserRescorer() throws Exception {
+ Rescorer<User> rescorer = NullRescorer.getUserInstance();
+ assertNotNull(rescorer);
+ User user = new GenericUser<String>("test", Collections.<Preference>emptyList());
+ assertEquals(1.0, rescorer.rescore(user, 1.0));
+ assertEquals(1.0, rescorer.rescore(null, 1.0));
+ assertEquals(0.0, rescorer.rescore(user, 0.0));
+ assertTrue(Double.isNaN(rescorer.rescore(user, Double.NaN)));
+ }
+
+}
Added: lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/recommender/ReversingRescorer.java
URL: http://svn.apache.org/viewvc/lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/recommender/ReversingRescorer.java?rev=654943&view=auto
==============================================================================
--- lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/recommender/ReversingRescorer.java (added)
+++ lucene/mahout/trunk/core/src/test/java/org/apache/mahout/cf/taste/impl/recommender/ReversingRescorer.java Fri May 9 14:35:12 2008
@@ -0,0 +1,36 @@
+/**
+ * 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.recommender.Rescorer;
+
+/**
+ * <p>Simple {@link Rescorer} which negates the given score, thus reversing
+ * order of rankings.</p>
+ */
+public final class ReversingRescorer<T> implements Rescorer<T> {
+
+ public double rescore(T thing, double originalScore) {
+ return Double.isNaN(originalScore) ? Double.NaN : -originalScore;
+ }
+
+ public boolean isFiltered(T thing) {
+ return false;
+ }
+
+}