recommendify 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +9 -0
- data/Gemfile.lock +24 -0
- data/README.md +154 -0
- data/Rakefile +12 -0
- data/doc/example.png +0 -0
- data/doc/example.rb +84 -0
- data/doc/example_data.csv +120048 -0
- data/lib/recommendify.rb +9 -0
- data/lib/recommendify/base.rb +80 -0
- data/lib/recommendify/cc_matrix.rb +46 -0
- data/lib/recommendify/cosine_input_matrix.rb +7 -0
- data/lib/recommendify/input_matrix.rb +47 -0
- data/lib/recommendify/jaccard_input_matrix.rb +35 -0
- data/lib/recommendify/neighbor.rb +19 -0
- data/lib/recommendify/recommendify.rb +25 -0
- data/lib/recommendify/similarity_matrix.rb +61 -0
- data/lib/recommendify/sparse_matrix.rb +45 -0
- data/spec/base_spec.rb +161 -0
- data/spec/cc_matrix_shared.rb +54 -0
- data/spec/cosine_input_matrix_spec.rb +18 -0
- data/spec/input_matrix_shared.rb +27 -0
- data/spec/input_matrix_spec.rb +29 -0
- data/spec/jaccard_input_matrix_spec.rb +78 -0
- data/spec/recommendify_spec.rb +28 -0
- data/spec/similarity_matrix_spec.rb +93 -0
- data/spec/sparse_matrix_spec.rb +78 -0
- data/spec/spec_helper.rb +42 -0
- metadata +132 -0
@@ -0,0 +1,54 @@
|
|
1
|
+
share_examples_for Recommendify::CCMatrix do
|
2
|
+
|
3
|
+
it "should build a sparsematrix with the correct key" do
|
4
|
+
@matrix.ccmatrix.redis_key.should == "recommendify-test:mymatrix:ccmatrix"
|
5
|
+
end
|
6
|
+
|
7
|
+
it "should increment all item counts on set addition" do
|
8
|
+
Recommendify.redis.hset("recommendify-test:mymatrix:items", "bar", 2)
|
9
|
+
@matrix.add_set("user123", ["foo", "bar"])
|
10
|
+
Recommendify.redis.hget("recommendify-test:mymatrix:items", "bar").to_i.should == 3
|
11
|
+
Recommendify.redis.hget("recommendify-test:mymatrix:items", "foo").to_i.should == 1
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should increment all item<->item pairs on set addition" do
|
15
|
+
@matrix.ccmatrix["bar", "foo"] = 2
|
16
|
+
res = @matrix.add_set("user123", ["foo", "bar", "fnord"])
|
17
|
+
res.length.should == 3
|
18
|
+
@matrix.ccmatrix["bar", "foo"].should == 3
|
19
|
+
@matrix.ccmatrix["foo", "fnord"].should == 1
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should increment all item<->item paris on single item addition"
|
23
|
+
it "should increment the item count on single item addition"
|
24
|
+
|
25
|
+
it "should calculate all item<->item pairs (3)" do
|
26
|
+
res = @matrix.send(:all_pairs, ["foo", "bar", "fnord"])
|
27
|
+
res.length.should == 3
|
28
|
+
res.should include("bar:foo")
|
29
|
+
res.should include("fnord:foo")
|
30
|
+
res.should include("bar:fnord")
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should calculate all item<->item pairs (6)" do
|
34
|
+
res = @matrix.send(:all_pairs, ["foo", "bar", "fnord", "blubb"])
|
35
|
+
res.length.should == 6
|
36
|
+
res.should include("bar:foo")
|
37
|
+
res.should include("fnord:foo")
|
38
|
+
res.should include("bar:fnord")
|
39
|
+
res.should include("blubb:foo")
|
40
|
+
res.should include("blubb:fnord")
|
41
|
+
res.should include("bar:blubb")
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should return all_items" do
|
45
|
+
@matrix.add_set("user42", ["fnord", "blubb"])
|
46
|
+
@matrix.add_set("user23", ["hans", "wurst"])
|
47
|
+
@matrix.all_items.length.should == 4
|
48
|
+
@matrix.all_items.should include("wurst")
|
49
|
+
@matrix.all_items.should include("fnord")
|
50
|
+
@matrix.all_items.should include("hans")
|
51
|
+
@matrix.all_items.should include("wurst")
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require ::File.expand_path('../spec_helper', __FILE__)
|
2
|
+
|
3
|
+
describe Recommendify::CosineInputMatrix do
|
4
|
+
|
5
|
+
before(:all) do
|
6
|
+
@matrix = Recommendify::CosineInputMatrix.new(:redis_prefix => "recommendify-test", :key => "mymatrix")
|
7
|
+
end
|
8
|
+
|
9
|
+
before(:each) do
|
10
|
+
flush_redis!
|
11
|
+
end
|
12
|
+
|
13
|
+
it_should_behave_like Recommendify::InputMatrix
|
14
|
+
it_should_behave_like Recommendify::CCMatrix
|
15
|
+
|
16
|
+
it "should calculate the correct cosine similarity (here be dragons)"
|
17
|
+
|
18
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
share_examples_for Recommendify::InputMatrix do
|
2
|
+
|
3
|
+
it "should build the correct keys" do
|
4
|
+
@matrix.redis_key.should == "recommendify-test:mymatrix"
|
5
|
+
end
|
6
|
+
|
7
|
+
it "should respond to add_set" do
|
8
|
+
@matrix.respond_to?(:add_set).should == true
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should respond to add_single" do
|
12
|
+
@matrix.respond_to?(:add_single).should == true
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should respond to similarity" do
|
16
|
+
@matrix.respond_to?(:similarity).should == true
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should respond to similarities_for" do
|
20
|
+
@matrix.respond_to?(:similarities_for).should == true
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should respond to all_items" do
|
24
|
+
@matrix.respond_to?(:all_items).should == true
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require ::File.expand_path('../spec_helper', __FILE__)
|
2
|
+
|
3
|
+
describe Recommendify::InputMatrix do
|
4
|
+
|
5
|
+
before(:all) do
|
6
|
+
@matrix = Recommendify::InputMatrix.new(:redis_prefix => "recommendify-test", :key => "mymatrix")
|
7
|
+
end
|
8
|
+
|
9
|
+
before(:each) do
|
10
|
+
flush_redis!
|
11
|
+
end
|
12
|
+
|
13
|
+
it_should_behave_like Recommendify::InputMatrix
|
14
|
+
|
15
|
+
describe "object creation" do
|
16
|
+
|
17
|
+
it "should create an object with the correct class" do
|
18
|
+
obj = Recommendify::InputMatrix.create(:key => "fubar", :similarity_func => :jaccard)
|
19
|
+
obj.should be_a(Recommendify::JaccardInputMatrix)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should create an object with the correct class and pass opts" do
|
23
|
+
obj = Recommendify::InputMatrix.create(:key => "fubar", :similarity_func => :jaccard)
|
24
|
+
obj.instance_variable_get(:@opts)[:key].should == "fubar"
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require ::File.expand_path('../spec_helper', __FILE__)
|
2
|
+
|
3
|
+
describe Recommendify::JaccardInputMatrix do
|
4
|
+
|
5
|
+
before(:all) do
|
6
|
+
@matrix = Recommendify::JaccardInputMatrix.new(:redis_prefix => "recommendify-test", :key => "mymatrix")
|
7
|
+
end
|
8
|
+
|
9
|
+
before(:each) do
|
10
|
+
flush_redis!
|
11
|
+
end
|
12
|
+
|
13
|
+
it_should_behave_like Recommendify::InputMatrix
|
14
|
+
it_should_behave_like Recommendify::CCMatrix
|
15
|
+
|
16
|
+
it "should calculate the correct jaccard index" do
|
17
|
+
@matrix.send(:calculate_jaccard,
|
18
|
+
["foo", "bar", "fnord", "blubb"],
|
19
|
+
["bar", "fnord", "shmoo", "snafu"]
|
20
|
+
).should == 2.0/6.0
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should calculate the correct similarity between to items" do
|
24
|
+
add_two_item_test_data!(@matrix)
|
25
|
+
# sim(fnord,blubb) = (users(fnord) & users(blub)) / (users(fnord) + users(blubb))
|
26
|
+
# => {user42 user48} / {user42 user46 user48 user50} + {user42 user44 user48}
|
27
|
+
# => {user42 user48} / {user42 user44 user46 user48 user50}
|
28
|
+
# => 2 / 5 => 0.4
|
29
|
+
@matrix.similarity("fnord", "blubb").should == 0.4
|
30
|
+
@matrix.similarity("blubb", "fnord").should == 0.4
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should calculate all similarities for an item (1/3)" do
|
34
|
+
add_three_item_test_data!(@matrix)
|
35
|
+
res = @matrix.similarities_for("fnord")
|
36
|
+
res.length.should == 2
|
37
|
+
res.should include ["shmoo", 0.75]
|
38
|
+
res.should include ["blubb", 0.4]
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should calculate all similarities for an item (2/3)" do
|
42
|
+
add_three_item_test_data!(@matrix)
|
43
|
+
res = @matrix.similarities_for("shmoo")
|
44
|
+
res.length.should == 2
|
45
|
+
res.should include ["blubb", 0.2]
|
46
|
+
res.should include ["fnord", 0.75]
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
it "should calculate all similarities for an item (3/3)" do
|
51
|
+
add_three_item_test_data!(@matrix)
|
52
|
+
res = @matrix.similarities_for("blubb")
|
53
|
+
res.length.should == 2
|
54
|
+
res.should include ["shmoo", 0.2]
|
55
|
+
res.should include ["fnord", 0.4]
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def add_two_item_test_data!(matrix)
|
61
|
+
matrix.add_set("user42", ["fnord", "blubb"])
|
62
|
+
matrix.add_set("user44", ["blubb"])
|
63
|
+
matrix.add_set("user46", ["fnord"])
|
64
|
+
matrix.add_set("user48", ["fnord", "blubb"])
|
65
|
+
matrix.add_set("user50", ["fnord"])
|
66
|
+
end
|
67
|
+
|
68
|
+
def add_three_item_test_data!(matrix)
|
69
|
+
matrix.add_set("user42", ["fnord", "blubb", "shmoo"])
|
70
|
+
matrix.add_set("user44", ["blubb"])
|
71
|
+
matrix.add_set("user46", ["fnord", "shmoo"])
|
72
|
+
matrix.add_set("user48", ["fnord", "blubb"])
|
73
|
+
matrix.add_set("user50", ["fnord", "shmoo"])
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require ::File.expand_path('../spec_helper', __FILE__)
|
2
|
+
|
3
|
+
describe Recommendify do
|
4
|
+
|
5
|
+
it "should store a redis connection" do
|
6
|
+
Recommendify.redis = "asd"
|
7
|
+
Recommendify.redis.should == "asd"
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should raise an exception if unconfigured redis connection is accessed" do
|
11
|
+
Recommendify.redis = nil
|
12
|
+
lambda{ ecommendify.redis }.should raise_error
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should capitalize a string" do
|
16
|
+
Recommendify.capitalize("fuubar").should == "Fuubar"
|
17
|
+
Recommendify.capitalize("fuUBar").should == "Fuubar"
|
18
|
+
Recommendify.capitalize("FUUBAR").should == "Fuubar"
|
19
|
+
Recommendify.capitalize("Fuubar").should == "Fuubar"
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should constantize a string" do
|
23
|
+
obj = Recommendify.constantize("JaccardInputMatrix")
|
24
|
+
# should_be doesn't work here...
|
25
|
+
obj.inspect.should == "Recommendify::JaccardInputMatrix"
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
require ::File.expand_path('../spec_helper', __FILE__)
|
2
|
+
|
3
|
+
describe Recommendify::SimilarityMatrix do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
flush_redis!
|
7
|
+
@matrix = Recommendify::SimilarityMatrix.new(:redis_prefix => "recommendify-test", :key => "mymatrix")
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "sorted sets per item" do
|
11
|
+
|
12
|
+
it "should store member similarities" do
|
13
|
+
@matrix.update("item_foo", [["item_bar", 0.7], ["item_fnord", 0.3]])
|
14
|
+
@matrix.write_queue["item_foo"].length.should == 2
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should store member similarities uniquely" do
|
18
|
+
@matrix.update("item_fnord", [["item_bar", 0.7], ["item_bar", 0.3]])
|
19
|
+
@matrix.write_queue["item_fnord"].length.should == 1
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should store member similarities uniquely and sum the scores" do
|
23
|
+
@matrix.update("item_fnord", [["item_bar", 0.7], ["item_bar", 0.3]])
|
24
|
+
@matrix.write_queue["item_fnord"].should == {"item_bar" => 1.0}
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should store multiple member similarities uniquely and sum the scores" do
|
28
|
+
@matrix.update("item_fnord", [["item_bar", 0.7], ["item_bar", 0.3], ["item_foo", 0.75]])
|
29
|
+
@matrix.write_queue["item_fnord"].should == {"item_bar" => 1.0, "item_foo" => 0.75}
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should store multiple member similarities uniquely and sum the scores on multiple updates" do
|
33
|
+
@matrix.update("item_fnord", [["item_bar", 0.7], ["item_foo", 0.75]])
|
34
|
+
@matrix.update("item_fnord", [["item_fnord", 0.3], ["item_bar", 0.3], ["item_foo", 0.75]])
|
35
|
+
@matrix.write_queue["item_fnord"].should == {"item_bar" => 1.0, "item_foo" => 1.5, "item_fnord" => 0.3}
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should retrieve the members" do
|
39
|
+
@matrix.update("item_fnord", [["item_bar", 0.7], ["item_bar", 0.3], ["item_foo", 0.75]])
|
40
|
+
@matrix["item_fnord"].should == {"item_bar" => 1.0, "item_foo" => 0.75}
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
describe "serialization/loading to/from redis" do
|
46
|
+
|
47
|
+
it "should serialize a member of the write_queue correctly" do
|
48
|
+
@matrix.update("item_fnord", [["item_fnord", 0.3], ["item_bar", 0.3], ["item_foo", 0.75]])
|
49
|
+
@matrix.update("item_fnord", [["item_bar", 0.7], ["item_bar", 0.3]])
|
50
|
+
@matrix.send(:serialize_item, "item_fnord").should == "item_bar:1.3|item_foo:0.75|item_fnord:0.3"
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should write the n-most similar members and scores to redis on commit_item!" do
|
54
|
+
@matrix.update("item_fnord", [["item_fnord", 0.3], ["item_bar", 0.3], ["item_foo", 0.75]])
|
55
|
+
@matrix.update("item_fnord", [["item_bar", 0.7], ["item_bar", 0.3]])
|
56
|
+
@matrix.commit_item!("item_fnord")
|
57
|
+
Recommendify.redis.hget("recommendify-test:mymatrix", "item_fnord").should == "item_bar:1.3|item_foo:0.75|item_fnord:0.3"
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should not write more than max_neighbors scores to redis on commit_item!" do
|
61
|
+
60.times{ |n| @matrix.update("item_fnord", [["item_#{n}", n.to_f/100.0]]) }
|
62
|
+
@matrix.commit_item!("item_fnord")
|
63
|
+
Recommendify.redis.hget("recommendify-test:mymatrix", "item_fnord").split("|").length.should == 50
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should not write more neighbors with zero-scores to redis on commit_item!" do
|
67
|
+
@matrix.update("item_fnord", [["item_fnord", 0.0], ["item_bar", 0.3], ["item_foo", 0.75]])
|
68
|
+
@matrix.update("item_fnord", [["item_bar", 0.7], ["item_bar", 0.3]])
|
69
|
+
@matrix.commit_item!("item_fnord")
|
70
|
+
Recommendify.redis.hget("recommendify-test:mymatrix", "item_fnord").split("|").length.should == 2
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should clear the item from the write_queue after commit_item!" do
|
74
|
+
60.times{ |n| @matrix.update("item_fnord", [["item_#{n}", n.to_f/100.0]]) }
|
75
|
+
@matrix.write_queue["item_fnord"].length.should == 60
|
76
|
+
@matrix.commit_item!("item_fnord")
|
77
|
+
@matrix.write_queue["item_fnord"].length.should == 0
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should retrieve the n-most similar neighbors after stored" do
|
81
|
+
Recommendify.redis.hset("recommendify-test:mymatrix", "item_fnord", "item_blubb:0.6|item_foo:0.4")
|
82
|
+
@matrix["item_fnord"].keys.should include("item_blubb")
|
83
|
+
@matrix["item_fnord"].keys.should include("item_foo")
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should retrieve the n-most similar neighbors after stored with scores" do
|
87
|
+
Recommendify.redis.hset("recommendify-test:mymatrix", "item_fnord", "item_blubb:0.6|item_foo:0.4")
|
88
|
+
@matrix["item_fnord"].should == {"item_blubb" => 0.6, "item_foo" => 0.4}
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require ::File.expand_path('../spec_helper', __FILE__)
|
2
|
+
|
3
|
+
describe Recommendify::SparseMatrix do
|
4
|
+
|
5
|
+
before(:all) do
|
6
|
+
@sm = Recommendify::SparseMatrix.new(:redis_prefix => "recommendify-test", :key => "mysparsematrix")
|
7
|
+
end
|
8
|
+
|
9
|
+
before(:each) do
|
10
|
+
flush_redis!
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should build the correct keys" do
|
14
|
+
@sm.redis_key.should == "recommendify-test:mysparsematrix"
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should retrieve a value" do
|
18
|
+
Recommendify.redis.hset("recommendify-test:mysparsematrix", "bar:foo", 43)
|
19
|
+
@sm["bar", "foo"].to_i.should == 43
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should retrieve a value regardless of parameter order" do
|
23
|
+
Recommendify.redis.hset("recommendify-test:mysparsematrix", "one:two", 14)
|
24
|
+
@sm["one", "two"].to_i.should == 14
|
25
|
+
@sm["two", "one"].to_i.should == 14
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should store a value" do
|
29
|
+
@sm["bar", "foo"] = 123
|
30
|
+
Recommendify.redis.hget("recommendify-test:mysparsematrix", "bar:foo").to_i.should == 123
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should store a value regardless of parameter order" do
|
34
|
+
@sm["foo", "bar"] = 126
|
35
|
+
Recommendify.redis.hget("recommendify-test:mysparsematrix", "bar:foo").to_i.should == 126
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should return 0 if the key is not found" do
|
39
|
+
@sm["not", "set"].should == 0
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should increment a value" do
|
43
|
+
@sm["foo", "bar"] = 1000
|
44
|
+
@sm.incr("foo", "bar")
|
45
|
+
Recommendify.redis.hget("recommendify-test:mysparsematrix", "bar:foo").to_i.should == 1001
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should increment a value regardless of parameter order" do
|
49
|
+
@sm["foo", "bar"] = 2000
|
50
|
+
@sm.incr("bar", "foo")
|
51
|
+
Recommendify.redis.hget("recommendify-test:mysparsematrix", "bar:foo").to_i.should == 2001
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should not create unneseccary keys" do
|
55
|
+
@sm["foo", "bar"] = 90
|
56
|
+
@sm["5asd6", "bar"] = 260
|
57
|
+
@sm["foo", "bar"] = 45
|
58
|
+
@sm["foo", "jefs"] = 26
|
59
|
+
Recommendify.redis.hkeys("recommendify-test:mysparsematrix").length.should == 3
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should create a key if the value is not 0" do
|
63
|
+
@sm["foo", "jefs"] = 26
|
64
|
+
Recommendify.redis.hkeys("recommendify-test:mysparsematrix").length.should == 1
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should not create a key if the value is 0" do
|
68
|
+
@sm["foo", "jefs"] = 0
|
69
|
+
Recommendify.redis.hkeys("recommendify-test:mysparsematrix").length.should == 0
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should delete a key if the value is set to 0" do
|
73
|
+
Recommendify.redis.hset("recommendify-test:mysparsematrix", "bar:foo", 43)
|
74
|
+
@sm["bar", "foo"] = 0
|
75
|
+
Recommendify.redis.hkeys("recommendify-test:mysparsematrix").length.should == 0
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
require "rspec"
|
2
|
+
require "redis"
|
3
|
+
|
4
|
+
require ::File.expand_path('../../lib/recommendify', __FILE__)
|
5
|
+
|
6
|
+
require ::File.expand_path('../input_matrix_shared.rb', __FILE__)
|
7
|
+
require ::File.expand_path('../cc_matrix_shared.rb', __FILE__)
|
8
|
+
|
9
|
+
def flush_redis!
|
10
|
+
Recommendify.redis = Redis.new
|
11
|
+
Recommendify.redis.keys("recommendify-test*").each do |k|
|
12
|
+
Recommendify.redis.del(k)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class Recommendify::Base
|
17
|
+
|
18
|
+
def redis_prefix
|
19
|
+
"recommendify-test"
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
class TestRecommender < Recommendify::Base
|
26
|
+
|
27
|
+
input_matrix :jaccard_one,
|
28
|
+
:similarity_func => :jaccard
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
class Recommendify::TestInputMatrix
|
33
|
+
|
34
|
+
def initialize(opts)
|
35
|
+
@opts = opts
|
36
|
+
end
|
37
|
+
|
38
|
+
def method_missing(method, *args)
|
39
|
+
@opts[method]
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|