predictor 1.0.0 → 2.0.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Changelog.md +13 -0
- data/Gemfile +1 -1
- data/README.md +75 -32
- data/docs/READMEv1.md +206 -0
- data/lib/predictor/base.rb +128 -60
- data/lib/predictor/input_matrix.rb +29 -82
- data/lib/predictor/version.rb +1 -1
- data/spec/base_spec.rb +160 -94
- data/spec/input_matrix_spec.rb +30 -160
- data/spec/predictor_spec.rb +1 -1
- metadata +6 -4
@@ -3,6 +3,10 @@ class Predictor::InputMatrix
|
|
3
3
|
@opts = opts
|
4
4
|
end
|
5
5
|
|
6
|
+
def parent_redis_key(*append)
|
7
|
+
([@opts.fetch(:redis_prefix)] + append).flatten.compact.join(":")
|
8
|
+
end
|
9
|
+
|
6
10
|
def redis_key(*append)
|
7
11
|
([@opts.fetch(:redis_prefix), @opts.fetch(:key)] + append).flatten.compact.join(":")
|
8
12
|
end
|
@@ -11,30 +15,19 @@ class Predictor::InputMatrix
|
|
11
15
|
(@opts[:weight] || 1).to_f
|
12
16
|
end
|
13
17
|
|
14
|
-
def
|
15
|
-
|
16
|
-
item_ids.each { |item| add_single_nomulti(set_id, item) }
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
def add_set!(set_id, item_ids)
|
21
|
-
add_set(set_id, item_ids)
|
22
|
-
item_ids.each { |item_id| process_item!(item_id) }
|
23
|
-
end
|
24
|
-
|
25
|
-
def add_single(set_id, item_id)
|
18
|
+
def add_to_set(set, *items)
|
19
|
+
items = items.flatten if items.count == 1 && items[0].is_a?(Array)
|
26
20
|
Predictor.redis.multi do
|
27
|
-
add_single_nomulti(
|
21
|
+
items.each { |item| add_single_nomulti(set, item) }
|
28
22
|
end
|
29
23
|
end
|
30
24
|
|
31
|
-
def
|
32
|
-
|
33
|
-
process_item!(item_id)
|
25
|
+
def add_set(set, items)
|
26
|
+
add_to_set(set, *items)
|
34
27
|
end
|
35
28
|
|
36
|
-
def
|
37
|
-
|
29
|
+
def add_single(set, item)
|
30
|
+
add_to_set(set, item)
|
38
31
|
end
|
39
32
|
|
40
33
|
def items_for(set)
|
@@ -45,81 +38,26 @@ class Predictor::InputMatrix
|
|
45
38
|
Predictor.redis.sunion redis_key(:sets, item)
|
46
39
|
end
|
47
40
|
|
48
|
-
def related_items(
|
49
|
-
sets = Predictor.redis.smembers(redis_key(:sets,
|
41
|
+
def related_items(item)
|
42
|
+
sets = Predictor.redis.smembers(redis_key(:sets, item))
|
50
43
|
keys = sets.map { |set| redis_key(:items, set) }
|
51
|
-
|
52
|
-
Predictor.redis.sunion(keys) - [item_id]
|
53
|
-
else
|
54
|
-
[]
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
def similarity(item1, item2)
|
59
|
-
Predictor.redis.zscore(redis_key(:similarities, item1), item2)
|
60
|
-
end
|
61
|
-
|
62
|
-
# calculate all similarities to other items in the matrix for item1
|
63
|
-
def similarities_for(item1, with_scores: false, offset: 0, limit: -1)
|
64
|
-
Predictor.redis.zrevrange(redis_key(:similarities, item1), offset, limit == -1 ? limit : offset + (limit - 1), with_scores: with_scores)
|
65
|
-
end
|
66
|
-
|
67
|
-
def process_item!(item)
|
68
|
-
cache_similarities_for(item)
|
69
|
-
end
|
70
|
-
|
71
|
-
def process!
|
72
|
-
all_items.each do |item|
|
73
|
-
process_item!(item)
|
74
|
-
end
|
44
|
+
keys.length > 0 ? Predictor.redis.sunion(keys) - [item] : []
|
75
45
|
end
|
76
46
|
|
77
|
-
# delete
|
78
|
-
def delete_item
|
79
|
-
Predictor.redis.
|
80
|
-
|
81
|
-
sets = Predictor.redis.smembers(redis_key(:sets, item_id))
|
82
|
-
items = Predictor.redis.zrange(redis_key(:similarities, item_id), 0, -1)
|
47
|
+
# delete item from the matrix
|
48
|
+
def delete_item(item)
|
49
|
+
Predictor.redis.watch(redis_key(:sets, item)) do
|
50
|
+
sets = Predictor.redis.smembers(redis_key(:sets, item))
|
83
51
|
Predictor.redis.multi do |multi|
|
84
52
|
sets.each do |set|
|
85
|
-
multi.srem(redis_key(:items, set),
|
53
|
+
multi.srem(redis_key(:items, set), item)
|
86
54
|
end
|
87
55
|
|
88
|
-
|
89
|
-
multi.zrem(redis_key(:similarities, item), item_id)
|
90
|
-
end
|
91
|
-
|
92
|
-
multi.del redis_key(:sets, item_id), redis_key(:similarities, item_id)
|
56
|
+
multi.del redis_key(:sets, item)
|
93
57
|
end
|
94
58
|
end
|
95
59
|
end
|
96
60
|
|
97
|
-
private
|
98
|
-
|
99
|
-
def add_single_nomulti(set_id, item_id)
|
100
|
-
Predictor.redis.sadd(redis_key(:all_items), item_id)
|
101
|
-
Predictor.redis.sadd(redis_key(:items, set_id), item_id)
|
102
|
-
# add the set_id to the item_id's set--inverting the sets
|
103
|
-
Predictor.redis.sadd(redis_key(:sets, item_id), set_id)
|
104
|
-
end
|
105
|
-
|
106
|
-
def cache_similarity(item1, item2)
|
107
|
-
score = calculate_jaccard(item1, item2)
|
108
|
-
|
109
|
-
if score > 0
|
110
|
-
Predictor.redis.multi do |multi|
|
111
|
-
multi.zadd(redis_key(:similarities, item1), score, item2)
|
112
|
-
multi.zadd(redis_key(:similarities, item2), score, item1)
|
113
|
-
end
|
114
|
-
end
|
115
|
-
end
|
116
|
-
|
117
|
-
def cache_similarities_for(item)
|
118
|
-
related_items(item).each do |related_item|
|
119
|
-
cache_similarity(item, related_item)
|
120
|
-
end
|
121
|
-
end
|
122
|
-
|
123
61
|
def calculate_jaccard(item1, item2)
|
124
62
|
x = nil
|
125
63
|
y = nil
|
@@ -135,4 +73,13 @@ class Predictor::InputMatrix
|
|
135
73
|
return 0.0
|
136
74
|
end
|
137
75
|
end
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
def add_single_nomulti(set, item)
|
80
|
+
Predictor.redis.sadd(parent_redis_key(:all_items), item)
|
81
|
+
Predictor.redis.sadd(redis_key(:items, set), item)
|
82
|
+
# add the set to the item's set--inverting the sets
|
83
|
+
Predictor.redis.sadd(redis_key(:sets, item), set)
|
84
|
+
end
|
138
85
|
end
|
data/lib/predictor/version.rb
CHANGED
data/spec/base_spec.rb
CHANGED
@@ -8,6 +8,7 @@ describe Predictor::Base do
|
|
8
8
|
before(:each) do
|
9
9
|
flush_redis!
|
10
10
|
BaseRecommender.input_matrices = {}
|
11
|
+
BaseRecommender.limit_similarities_to(nil)
|
11
12
|
end
|
12
13
|
|
13
14
|
describe "configuration" do
|
@@ -16,6 +17,11 @@ describe Predictor::Base do
|
|
16
17
|
BaseRecommender.input_matrices.keys.should == [:myinput]
|
17
18
|
end
|
18
19
|
|
20
|
+
it "should allow a similarity limit" do
|
21
|
+
BaseRecommender.limit_similarities_to(100)
|
22
|
+
BaseRecommender.similarity_limit.should == 100
|
23
|
+
end
|
24
|
+
|
19
25
|
it "should retrieve an input_matrix on a new instance" do
|
20
26
|
BaseRecommender.input_matrix(:myinput)
|
21
27
|
sm = BaseRecommender.new
|
@@ -37,67 +43,56 @@ describe Predictor::Base do
|
|
37
43
|
end
|
38
44
|
end
|
39
45
|
|
40
|
-
describe "
|
41
|
-
it "
|
42
|
-
BaseRecommender.input_matrix(:
|
43
|
-
BaseRecommender.input_matrix(:
|
44
|
-
sm = BaseRecommender.new
|
45
|
-
sm.myfirstinput.should_receive(:process_item!).with("fnorditem").and_return([["fooitem",0.5]])
|
46
|
-
sm.mysecondinput.should_receive(:process_item!).with("fnorditem").and_return([["fooitem",0.5]])
|
47
|
-
sm.process_item!("fnorditem")
|
48
|
-
end
|
49
|
-
|
50
|
-
it "should call process_item! on each input_matrix and add all outputs to the similarity matrix" do
|
51
|
-
BaseRecommender.input_matrix(:myfirstinput)
|
52
|
-
BaseRecommender.input_matrix(:mysecondinput)
|
46
|
+
describe "all_items" do
|
47
|
+
it "returns all items across all matrices" do
|
48
|
+
BaseRecommender.input_matrix(:anotherinput)
|
49
|
+
BaseRecommender.input_matrix(:yetanotherinput)
|
53
50
|
sm = BaseRecommender.new
|
54
|
-
sm.
|
55
|
-
sm.
|
56
|
-
sm.
|
51
|
+
sm.add_to_matrix(:anotherinput, 'a', "foo", "bar")
|
52
|
+
sm.add_to_matrix(:yetanotherinput, 'b', "fnord", "shmoo", "bar")
|
53
|
+
sm.all_items.should include('foo', 'bar', 'fnord', 'shmoo')
|
54
|
+
sm.all_items.length.should == 4
|
57
55
|
end
|
56
|
+
end
|
58
57
|
|
59
|
-
|
60
|
-
|
61
|
-
BaseRecommender.input_matrix(:
|
58
|
+
describe "add_to_matrix" do
|
59
|
+
it "calls add_to_set on the given matrix" do
|
60
|
+
BaseRecommender.input_matrix(:anotherinput)
|
62
61
|
sm = BaseRecommender.new
|
63
|
-
sm.
|
64
|
-
sm.
|
65
|
-
sm.process_item!("fnorditem")
|
62
|
+
sm.anotherinput.should_receive(:add_to_set).with('a', 'foo', 'bar')
|
63
|
+
sm.add_to_matrix(:anotherinput, 'a', 'foo', 'bar')
|
66
64
|
end
|
67
|
-
end
|
68
65
|
|
69
|
-
|
70
|
-
it "should retrieve all items from all input matrices" do
|
66
|
+
it "adds the items to the all_items storage" do
|
71
67
|
BaseRecommender.input_matrix(:anotherinput)
|
72
|
-
BaseRecommender.input_matrix(:yetanotherinput)
|
73
68
|
sm = BaseRecommender.new
|
74
|
-
sm.anotherinput
|
75
|
-
sm.
|
76
|
-
sm.all_items.length.should == 4
|
77
|
-
sm.all_items.should include("foo", "bar", "fnord", "shmoo")
|
69
|
+
sm.add_to_matrix(:anotherinput, 'a', 'foo', 'bar')
|
70
|
+
sm.all_items.should include('foo', 'bar')
|
78
71
|
end
|
72
|
+
end
|
79
73
|
|
80
|
-
|
74
|
+
describe "add_to_matrix!" do
|
75
|
+
it "calls add_to_matrix and process_items! for the given items" do
|
81
76
|
BaseRecommender.input_matrix(:anotherinput)
|
82
|
-
BaseRecommender.input_matrix(:yetanotherinput)
|
83
77
|
sm = BaseRecommender.new
|
84
|
-
sm.
|
85
|
-
sm.
|
86
|
-
sm.
|
87
|
-
sm.all_items.should include("foo", "bar", "fnord")
|
78
|
+
sm.should_receive(:add_to_matrix).with(:anotherinput, 'a', 'foo')
|
79
|
+
sm.should_receive(:process_items!).with('foo')
|
80
|
+
sm.add_to_matrix!(:anotherinput, 'a', 'foo')
|
88
81
|
end
|
89
82
|
end
|
90
83
|
|
91
|
-
describe "
|
92
|
-
it "
|
84
|
+
describe "related_items" do
|
85
|
+
it "returns items in the sets across all matrices that the given item is also in" do
|
93
86
|
BaseRecommender.input_matrix(:anotherinput)
|
94
87
|
BaseRecommender.input_matrix(:yetanotherinput)
|
88
|
+
BaseRecommender.input_matrix(:finalinput)
|
95
89
|
sm = BaseRecommender.new
|
96
|
-
sm.anotherinput.
|
97
|
-
sm.yetanotherinput.
|
98
|
-
sm.
|
99
|
-
sm.yetanotherinput.should_receive(:process!).exactly(1).times
|
90
|
+
sm.anotherinput.add_to_set('a', "foo", "bar")
|
91
|
+
sm.yetanotherinput.add_to_set('b', "fnord", "shmoo", "bar")
|
92
|
+
sm.finalinput.add_to_set('c', "nada")
|
100
93
|
sm.process!
|
94
|
+
sm.related_items("bar").should include("foo", "fnord", "shmoo")
|
95
|
+
sm.related_items("bar").length.should == 3
|
101
96
|
end
|
102
97
|
end
|
103
98
|
|
@@ -106,13 +101,13 @@ describe Predictor::Base do
|
|
106
101
|
BaseRecommender.input_matrix(:users, weight: 4.0)
|
107
102
|
BaseRecommender.input_matrix(:tags, weight: 1.0)
|
108
103
|
sm = BaseRecommender.new
|
109
|
-
sm.users.
|
110
|
-
sm.users.
|
111
|
-
sm.users.
|
112
|
-
sm.users.
|
113
|
-
sm.tags.
|
114
|
-
sm.tags.
|
115
|
-
sm.tags.
|
104
|
+
sm.users.add_to_set('me', "foo", "bar", "fnord")
|
105
|
+
sm.users.add_to_set('not_me', "foo", "shmoo")
|
106
|
+
sm.users.add_to_set('another', "fnord", "other")
|
107
|
+
sm.users.add_to_set('another', "nada")
|
108
|
+
sm.tags.add_to_set('tag1', "foo", "fnord", "shmoo")
|
109
|
+
sm.tags.add_to_set('tag2', "bar", "shmoo")
|
110
|
+
sm.tags.add_to_set('tag3', "shmoo", "nada")
|
116
111
|
sm.process!
|
117
112
|
predictions = sm.predictions_for('me', matrix_label: :users)
|
118
113
|
predictions.should == ["shmoo", "other", "nada"]
|
@@ -123,39 +118,9 @@ describe Predictor::Base do
|
|
123
118
|
predictions = sm.predictions_for('me', matrix_label: :users, offset: 1)
|
124
119
|
predictions.should == ["other", "nada"]
|
125
120
|
end
|
126
|
-
|
127
|
-
it "correctly normalizes predictions" do
|
128
|
-
BaseRecommender.input_matrix(:users, weight: 1.0)
|
129
|
-
BaseRecommender.input_matrix(:tags, weight: 2.0)
|
130
|
-
BaseRecommender.input_matrix(:topics, weight: 4.0)
|
131
|
-
|
132
|
-
sm = BaseRecommender.new
|
133
|
-
|
134
|
-
sm.users.add_set('user1', ["c1", "c2", "c4"])
|
135
|
-
sm.users.add_set('user2', ["c3", "c4"])
|
136
|
-
sm.topics.add_set('topic1', ["c1", "c4"])
|
137
|
-
sm.topics.add_set('topic2', ["c2", "c3"])
|
138
|
-
sm.tags.add_set('tag1', ["c1", "c2", "c4"])
|
139
|
-
sm.tags.add_set('tag2', ["c1", "c4"])
|
140
|
-
|
141
|
-
sm.process!
|
142
|
-
|
143
|
-
predictions = sm.predictions_for('user1', matrix_label: :users, with_scores: true, normalize: false)
|
144
|
-
predictions.should eq([["c3", 4.5]])
|
145
|
-
predictions = sm.predictions_for('user2', matrix_label: :users, with_scores: true, normalize: false)
|
146
|
-
predictions.should eq([["c1", 6.5], ["c2", 5.5]])
|
147
|
-
predictions = sm.predictions_for('user1', matrix_label: :users, with_scores: true, normalize: true)
|
148
|
-
predictions[0][0].should eq("c3")
|
149
|
-
predictions[0][1].should be_within(0.001).of(0.592)
|
150
|
-
predictions = sm.predictions_for('user2', matrix_label: :users, with_scores: true, normalize: true)
|
151
|
-
predictions[0][0].should eq("c2")
|
152
|
-
predictions[0][1].should be_within(0.001).of(1.065)
|
153
|
-
predictions[1][0].should eq("c1")
|
154
|
-
predictions[1][1].should be_within(0.001).of(0.764)
|
155
|
-
end
|
156
121
|
end
|
157
122
|
|
158
|
-
describe "similarities_for
|
123
|
+
describe "similarities_for" do
|
159
124
|
it "should not throw exception for non existing items" do
|
160
125
|
sm = BaseRecommender.new
|
161
126
|
sm.similarities_for("not_existing_item").length.should == 0
|
@@ -168,12 +133,12 @@ describe Predictor::Base do
|
|
168
133
|
|
169
134
|
sm = BaseRecommender.new
|
170
135
|
|
171
|
-
sm.users.
|
172
|
-
sm.users.
|
173
|
-
sm.topics.
|
174
|
-
sm.topics.
|
175
|
-
sm.tags.
|
176
|
-
sm.tags.
|
136
|
+
sm.users.add_to_set('user1', "c1", "c2", "c4")
|
137
|
+
sm.users.add_to_set('user2', "c3", "c4")
|
138
|
+
sm.topics.add_to_set('topic1', "c1", "c4")
|
139
|
+
sm.topics.add_to_set('topic2', "c2", "c3")
|
140
|
+
sm.tags.add_to_set('tag1', "c1", "c2", "c4")
|
141
|
+
sm.tags.add_to_set('tag2', "c1", "c4")
|
177
142
|
|
178
143
|
sm.process!
|
179
144
|
sm.similarities_for("c1", with_scores: true).should eq([["c4", 6.5], ["c2", 2.0]])
|
@@ -188,24 +153,125 @@ describe Predictor::Base do
|
|
188
153
|
BaseRecommender.input_matrix(:set1)
|
189
154
|
BaseRecommender.input_matrix(:set2)
|
190
155
|
sm = BaseRecommender.new
|
191
|
-
sm.set1.
|
192
|
-
sm.set1.
|
193
|
-
sm.set2.
|
156
|
+
sm.set1.add_to_set "item1", "foo", "bar"
|
157
|
+
sm.set1.add_to_set "item2", "nada", "bar"
|
158
|
+
sm.set2.add_to_set "item3", "bar", "other"
|
194
159
|
sm.sets_for("bar").length.should == 3
|
195
160
|
sm.sets_for("bar").should include("item1", "item2", "item3")
|
196
161
|
sm.sets_for("other").should == ["item3"]
|
197
162
|
end
|
198
163
|
end
|
199
164
|
|
165
|
+
describe "process_items!" do
|
166
|
+
context "with no similarity_limit" do
|
167
|
+
it "calculates the similarity between the item and all related_items (other items in a set the given item is in)" do
|
168
|
+
BaseRecommender.input_matrix(:myfirstinput)
|
169
|
+
BaseRecommender.input_matrix(:mysecondinput)
|
170
|
+
BaseRecommender.input_matrix(:mythirdinput, weight: 3.0)
|
171
|
+
sm = BaseRecommender.new
|
172
|
+
sm.myfirstinput.add_to_set 'set1', 'item1', 'item2'
|
173
|
+
sm.mysecondinput.add_to_set 'set2', 'item2', 'item3'
|
174
|
+
sm.mythirdinput.add_to_set 'set3', 'item2', 'item3'
|
175
|
+
sm.mythirdinput.add_to_set 'set4', 'item1', 'item2', 'item3'
|
176
|
+
sm.similarities_for('item2').should be_empty
|
177
|
+
sm.process_items!('item2')
|
178
|
+
similarities = sm.similarities_for('item2', with_scores: true)
|
179
|
+
similarities.should include(["item3", 4.0], ["item1", 2.5])
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
context "with a similarity_limit" do
|
184
|
+
it "calculates the similarity between the item and all related_items (other items in a set the given item is in), but obeys the similarity_limit" do
|
185
|
+
BaseRecommender.input_matrix(:myfirstinput)
|
186
|
+
BaseRecommender.input_matrix(:mysecondinput)
|
187
|
+
BaseRecommender.input_matrix(:mythirdinput, weight: 3.0)
|
188
|
+
BaseRecommender.limit_similarities_to(1)
|
189
|
+
sm = BaseRecommender.new
|
190
|
+
sm.myfirstinput.add_to_set 'set1', 'item1', 'item2'
|
191
|
+
sm.mysecondinput.add_to_set 'set2', 'item2', 'item3'
|
192
|
+
sm.mythirdinput.add_to_set 'set3', 'item2', 'item3'
|
193
|
+
sm.mythirdinput.add_to_set 'set4', 'item1', 'item2', 'item3'
|
194
|
+
sm.similarities_for('item2').should be_empty
|
195
|
+
sm.process_items!('item2')
|
196
|
+
similarities = sm.similarities_for('item2', with_scores: true)
|
197
|
+
similarities.should include(["item3", 4.0])
|
198
|
+
similarities.length.should == 1
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
describe "process!" do
|
204
|
+
it "should call process_items for all_items's" do
|
205
|
+
BaseRecommender.input_matrix(:anotherinput)
|
206
|
+
BaseRecommender.input_matrix(:yetanotherinput)
|
207
|
+
sm = BaseRecommender.new
|
208
|
+
sm.anotherinput.add_to_set('a', "foo", "bar")
|
209
|
+
sm.yetanotherinput.add_to_set('b', "fnord", "shmoo")
|
210
|
+
sm.all_items.should include("foo", "bar", "fnord", "shmoo")
|
211
|
+
sm.should_receive(:process_items!).with(*sm.all_items)
|
212
|
+
sm.process!
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
describe "delete_from_matrix!" do
|
217
|
+
it "calls delete_item on the matrix" do
|
218
|
+
BaseRecommender.input_matrix(:anotherinput)
|
219
|
+
BaseRecommender.input_matrix(:yetanotherinput)
|
220
|
+
sm = BaseRecommender.new
|
221
|
+
sm.anotherinput.add_to_set('a', "foo", "bar")
|
222
|
+
sm.yetanotherinput.add_to_set('b', "bar", "shmoo")
|
223
|
+
sm.process!
|
224
|
+
sm.similarities_for('bar').should include('foo', 'shmoo')
|
225
|
+
sm.anotherinput.should_receive(:delete_item).with('foo')
|
226
|
+
sm.delete_from_matrix!(:anotherinput, 'foo')
|
227
|
+
end
|
228
|
+
|
229
|
+
it "updates similarities" do
|
230
|
+
BaseRecommender.input_matrix(:anotherinput)
|
231
|
+
BaseRecommender.input_matrix(:yetanotherinput)
|
232
|
+
sm = BaseRecommender.new
|
233
|
+
sm.anotherinput.add_to_set('a', "foo", "bar")
|
234
|
+
sm.yetanotherinput.add_to_set('b', "bar", "shmoo")
|
235
|
+
sm.process!
|
236
|
+
sm.similarities_for('bar').should include('foo', 'shmoo')
|
237
|
+
sm.delete_from_matrix!(:anotherinput, 'foo')
|
238
|
+
sm.similarities_for('bar').should == ['shmoo']
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
200
242
|
describe "delete_item!" do
|
201
243
|
it "should call delete_item on each input_matrix" do
|
202
244
|
BaseRecommender.input_matrix(:myfirstinput)
|
203
245
|
BaseRecommender.input_matrix(:mysecondinput)
|
204
246
|
sm = BaseRecommender.new
|
205
|
-
sm.myfirstinput.should_receive(:delete_item
|
206
|
-
sm.mysecondinput.should_receive(:delete_item
|
247
|
+
sm.myfirstinput.should_receive(:delete_item).with("fnorditem")
|
248
|
+
sm.mysecondinput.should_receive(:delete_item).with("fnorditem")
|
207
249
|
sm.delete_item!("fnorditem")
|
208
250
|
end
|
251
|
+
|
252
|
+
it "should remove the item from all_items" do
|
253
|
+
BaseRecommender.input_matrix(:anotherinput)
|
254
|
+
sm = BaseRecommender.new
|
255
|
+
sm.anotherinput.add_to_set('a', "foo", "bar")
|
256
|
+
sm.process!
|
257
|
+
sm.all_items.should include('foo')
|
258
|
+
sm.delete_item!('foo')
|
259
|
+
sm.all_items.should_not include('foo')
|
260
|
+
end
|
261
|
+
|
262
|
+
it "should remove the item's similarities and also remove the item from related_items' similarities" do
|
263
|
+
BaseRecommender.input_matrix(:anotherinput)
|
264
|
+
BaseRecommender.input_matrix(:yetanotherinput)
|
265
|
+
sm = BaseRecommender.new
|
266
|
+
sm.anotherinput.add_to_set('a', "foo", "bar")
|
267
|
+
sm.yetanotherinput.add_to_set('b', "bar", "shmoo")
|
268
|
+
sm.process!
|
269
|
+
sm.similarities_for('bar').should include('foo', 'shmoo')
|
270
|
+
sm.similarities_for('shmoo').should include('bar')
|
271
|
+
sm.delete_item!('shmoo')
|
272
|
+
sm.similarities_for('bar').should_not include('shmoo')
|
273
|
+
sm.similarities_for('shmoo').should be_empty
|
274
|
+
end
|
209
275
|
end
|
210
276
|
|
211
277
|
describe "clean!" do
|
@@ -213,9 +279,9 @@ describe Predictor::Base do
|
|
213
279
|
BaseRecommender.input_matrix(:set1)
|
214
280
|
BaseRecommender.input_matrix(:set2)
|
215
281
|
sm = BaseRecommender.new
|
216
|
-
sm.set1.
|
217
|
-
sm.set1.
|
218
|
-
sm.set2.
|
282
|
+
sm.set1.add_to_set "item1", "foo", "bar"
|
283
|
+
sm.set1.add_to_set "item2", "nada", "bar"
|
284
|
+
sm.set2.add_to_set "item3", "bar", "other"
|
219
285
|
Predictor.redis.keys("#{sm.redis_prefix}:*").should_not be_empty
|
220
286
|
sm.clean!
|
221
287
|
Predictor.redis.keys("#{sm.redis_prefix}:*").should be_empty
|