Permalink
Browse files

Don't recommend rated items - Fixes #55

Signed-off-by: David Celis <david@davidcelis.com>
  • Loading branch information...
1 parent e706631 commit 55b43d6fbe59179bb1a29dfef671cca16d7234a6 David Celis committed Oct 11, 2012
View
@@ -18,7 +18,7 @@ Add the following to your application's `Gemfile`:
gem 'recommendable'
```
-For correct detection of your ORM, you may need to place Recommendable below your ORM in the Gemfile.
+You may need to place Recommendable below your ORM and queueing system in the Gemfile.
After bundling, you should configure Recommendable. Do this somewhere after you've required it, but before it's actually used. For example, Rails users would create an initializer (`config/initializers/recommendable.rb`):
@@ -45,6 +45,7 @@ def update_similarities_for(user_id)
relevant_user_ids = Recommendable.config.ratable_classes.inject([]) do |memo, klass|
liked_set = Recommendable::Helpers::RedisKeyMapper.liked_set_for(klass, user_id)
disliked_set = Recommendable::Helpers::RedisKeyMapper.disliked_set_for(klass, user_id)
+
item_ids = Recommendable.redis.sunion(liked_set, disliked_set)
unless item_ids.empty?
@@ -76,16 +77,34 @@ def update_similarities_for(user_id)
def update_recommendations_for(user_id)
nearest_neighbors = Recommendable.config.nearest_neighbors || Recommendable.config.user_class.count
Recommendable.config.ratable_classes.each do |klass|
- similarity_set = Recommendable::Helpers::RedisKeyMapper.similarity_set_for(user_id)
+ rated_sets = [
+ Recommendable::Helpers::RedisKeyMapper.liked_set_for(klass, user_id),
+ Recommendable::Helpers::RedisKeyMapper.disliked_set_for(klass, user_id),
+ Recommendable::Helpers::RedisKeyMapper.hidden_set_for(klass, user_id),
+ Recommendable::Helpers::RedisKeyMapper.bookmarked_set_for(klass, user_id)
+ ]
+ temp_set = Recommendable::Helpers::RedisKeyMapper.temp_set_for(Recommendable.config.user_class, user_id)
+ similarity_set = Recommendable::Helpers::RedisKeyMapper.similarity_set_for(user_id)
recommended_set = Recommendable::Helpers::RedisKeyMapper.recommended_set_for(klass, user_id)
- similar_user_ids = Recommendable.redis.zrevrange(similarity_set, 0, nearest_neighbors - 1)
+ most_similar_user_ids = Recommendable.redis.zrevrange(similarity_set, 0, nearest_neighbors - 1)
+ least_similar_user_ids = Recommendable.redis.zrange(similarity_set, 0, nearest_neighbors - 1)
- sets_to_union = similar_user_ids.inject([]) do |sets, id|
+ # Get likes from the most similar users
+ sets_to_union = most_similar_user_ids.inject([]) do |sets, id|
sets << Recommendable::Helpers::RedisKeyMapper.liked_set_for(klass, id)
end
+ # Get dislikes from the least similar users
+ least_similar_user_ids.inject(sets_to_union) do |sets, id|
+ sets << Recommendable::Helpers::RedisKeyMapper.disliked_set_for(klass, id)
+ end
+
return if sets_to_union.empty?
- scores = Recommendable.redis.sunion(sets_to_union).map { |id| [predict_for(user_id, klass, id), id] }
+
+ # SDIFF rated items so they aren't recommended
+ Recommendable.redis.sunionstore(temp_set, sets_to_union)
+ item_ids = Recommendable.redis.sdiff(temp_set, rated_sets)
+ scores = item_ids.map { |id| [predict_for(user_id, klass, id), id] }
scores.each do |s|
Recommendable.redis.zadd(recommended_set, s[0], s[1])
end
@@ -13,16 +13,20 @@ def similarity_set_for(id)
end
def liked_by_set_for(klass, id)
- [Recommendable.config.redis_namespace, klass.to_s.tableize, id, "liked_by"].compact.join(':')
+ [Recommendable.config.redis_namespace, klass.to_s.tableize, id, 'liked_by'].compact.join(':')
end
def disliked_by_set_for(klass, id)
- [Recommendable.config.redis_namespace, klass.to_s.tableize, id, "disliked_by"].compact.join(':')
+ [Recommendable.config.redis_namespace, klass.to_s.tableize, id, 'disliked_by'].compact.join(':')
end
def score_set_for(klass)
[Recommendable.config.redis_namespace, klass.to_s.tableize, 'scores'].join(':')
end
+
+ def temp_set_for(klass, id)
+ [Recommendable.config.redis_namespace, klass.to_s.tableize, id, 'temp'].compact.join(':')
+ end
end
end
end
@@ -40,6 +40,10 @@ def test_similarity_between_calculates_correctly
assert_equal Recommendable::Helpers::Calculations.similarity_between(@user.id, @user5.id), -1.0
end
+ def test_update_recommendations_ignores_rated_items
+
+ end
+
def teardown
Recommendable.redis.flushdb
end

0 comments on commit 55b43d6

Please sign in to comment.