recommendable 2.0.0 → 2.0.0.20121011

Sign up to get free protection for your applications and to get access to all the features.
@@ -45,6 +45,7 @@ module Recommendable
45
45
  relevant_user_ids = Recommendable.config.ratable_classes.inject([]) do |memo, klass|
46
46
  liked_set = Recommendable::Helpers::RedisKeyMapper.liked_set_for(klass, user_id)
47
47
  disliked_set = Recommendable::Helpers::RedisKeyMapper.disliked_set_for(klass, user_id)
48
+
48
49
  item_ids = Recommendable.redis.sunion(liked_set, disliked_set)
49
50
 
50
51
  unless item_ids.empty?
@@ -76,18 +77,37 @@ module Recommendable
76
77
  def update_recommendations_for(user_id)
77
78
  nearest_neighbors = Recommendable.config.nearest_neighbors || Recommendable.config.user_class.count
78
79
  Recommendable.config.ratable_classes.each do |klass|
79
- similarity_set = Recommendable::Helpers::RedisKeyMapper.similarity_set_for(user_id)
80
+ rated_sets = [
81
+ Recommendable::Helpers::RedisKeyMapper.liked_set_for(klass, user_id),
82
+ Recommendable::Helpers::RedisKeyMapper.disliked_set_for(klass, user_id),
83
+ Recommendable::Helpers::RedisKeyMapper.hidden_set_for(klass, user_id),
84
+ Recommendable::Helpers::RedisKeyMapper.bookmarked_set_for(klass, user_id)
85
+ ]
86
+ temp_set = Recommendable::Helpers::RedisKeyMapper.temp_set_for(Recommendable.config.user_class, user_id)
87
+ similarity_set = Recommendable::Helpers::RedisKeyMapper.similarity_set_for(user_id)
80
88
  recommended_set = Recommendable::Helpers::RedisKeyMapper.recommended_set_for(klass, user_id)
81
- similar_user_ids = Recommendable.redis.zrevrange(similarity_set, 0, nearest_neighbors - 1)
89
+ most_similar_user_ids = Recommendable.redis.zrevrange(similarity_set, 0, nearest_neighbors - 1)
90
+ least_similar_user_ids = Recommendable.redis.zrange(similarity_set, 0, nearest_neighbors - 1)
82
91
 
83
- sets_to_union = similar_user_ids.inject([]) do |sets, id|
92
+ # Get likes from the most similar users
93
+ sets_to_union = most_similar_user_ids.inject([]) do |sets, id|
84
94
  sets << Recommendable::Helpers::RedisKeyMapper.liked_set_for(klass, id)
85
95
  end
86
96
 
87
- next if sets_to_union.empty?
88
- scores = Recommendable.redis.sunion(sets_to_union).map { |id| [predict_for(user_id, klass, id), id] }
89
- next if scores.empty?
90
- Recommendable.redis.zadd(recommended_set, scores)
97
+ # Get dislikes from the least similar users
98
+ least_similar_user_ids.inject(sets_to_union) do |sets, id|
99
+ sets << Recommendable::Helpers::RedisKeyMapper.disliked_set_for(klass, id)
100
+ end
101
+
102
+ return if sets_to_union.empty?
103
+
104
+ # SDIFF rated items so they aren't recommended
105
+ Recommendable.redis.sunionstore(temp_set, sets_to_union)
106
+ item_ids = Recommendable.redis.sdiff(temp_set, rated_sets)
107
+ scores = item_ids.map { |id| [predict_for(user_id, klass, id), id] }
108
+ scores.each do |s|
109
+ Recommendable.redis.zadd(recommended_set, s[0], s[1])
110
+ end
91
111
  end
92
112
 
93
113
  true
@@ -13,16 +13,20 @@ module Recommendable
13
13
  end
14
14
 
15
15
  def liked_by_set_for(klass, id)
16
- [Recommendable.config.redis_namespace, klass.to_s.tableize, id, "liked_by"].compact.join(':')
16
+ [Recommendable.config.redis_namespace, klass.to_s.tableize, id, 'liked_by'].compact.join(':')
17
17
  end
18
18
 
19
19
  def disliked_by_set_for(klass, id)
20
- [Recommendable.config.redis_namespace, klass.to_s.tableize, id, "disliked_by"].compact.join(':')
20
+ [Recommendable.config.redis_namespace, klass.to_s.tableize, id, 'disliked_by'].compact.join(':')
21
21
  end
22
22
 
23
23
  def score_set_for(klass)
24
24
  [Recommendable.config.redis_namespace, klass.to_s.tableize, 'scores'].join(':')
25
25
  end
26
+
27
+ def temp_set_for(klass, id)
28
+ [Recommendable.config.redis_namespace, klass.to_s.tableize, id, 'temp'].compact.join(':')
29
+ end
26
30
  end
27
31
  end
28
32
  end
@@ -2,7 +2,7 @@ module Recommendable
2
2
  MAJOR = 2
3
3
  MINOR = 0
4
4
  PATCH = 0
5
- PRE = nil
5
+ PRE = 20121011
6
6
 
7
7
  VERSION = [MAJOR, MINOR, PATCH, PRE].compact.join '.'
8
8
  end
@@ -1,8 +1,10 @@
1
1
  module Recommendable
2
2
  module Workers
3
3
  class Sidekiq
4
- include ::Sidekiq::Worker
5
- sidekiq_options :unique => true, :queue => :recommendable
4
+ if defined?(::Sidekiq)
5
+ include ::Sidekiq::Worker
6
+ sidekiq_options :unique => true, :queue => :recommendable
7
+ end
6
8
 
7
9
  def perform(user_id)
8
10
  Recommendable::Helpers::Calculations.update_similarities_for(user_id)
data/lib/recommendable.rb CHANGED
@@ -7,6 +7,11 @@ require 'recommendable/helpers'
7
7
  require 'recommendable/rater'
8
8
  require 'recommendable/ratable'
9
9
 
10
+ require 'recommendable/workers/sidekiq'
11
+ require 'recommendable/workers/resque'
12
+ require 'recommendable/workers/delayed_job'
13
+ require 'recommendable/workers/rails'
14
+
10
15
  module Recommendable
11
16
  class << self
12
17
  def redis() config.redis end
@@ -21,18 +26,14 @@ module Recommendable
21
26
  user_id = user_id.id if user_id.is_a?(Recommendable.config.user_class)
22
27
 
23
28
  if defined?(::Sidekiq)
24
- require 'recommendable/workers/sidekiq'
25
29
  Recommendable::Workers::Sidekiq.perform_async(user_id)
26
30
  elsif defined?(::Resque)
27
- require 'recommendable/workers/resque'
28
31
  Resque.enqueue(Recommendable::Workers::Resque, user_id)
29
32
  elsif defined?(::Delayed::Job)
30
- require 'recommendable/workers/delayed_job'
31
33
  Delayed::Job.enqueue(Recommendable::Workers::DelayedJob.new(user_id))
32
34
  elsif defined?(::Rails::Queueing)
33
- require 'recommendable/workers/rails'
34
35
  unless Rails.queue.any? { |w| w.user_id == user_id }
35
- Rails.queue.push(Recommendable::Workers::Rails.new(user_idid))
36
+ Rails.queue.push(Recommendable::Workers::Rails.new(user_id))
36
37
  Rails.application.queue_consumer.start
37
38
  end
38
39
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: recommendable
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 2.0.0.20121011
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-10-09 00:00:00.000000000 Z
12
+ date: 2012-10-11 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
@@ -213,4 +213,3 @@ signing_key:
213
213
  specification_version: 3
214
214
  summary: A Like/Dislike recommendation engine for Ruby apps using Redis
215
215
  test_files: []
216
- has_rdoc: yard