recommendable 2.0.4.20130313 → 2.1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/recommendable.rb +0 -1
- data/lib/recommendable/configuration.rb +47 -15
- data/lib/recommendable/helpers/calculations.rb +12 -0
- data/lib/recommendable/ratable.rb +13 -12
- data/lib/recommendable/rater/recommender.rb +20 -17
- data/lib/recommendable/version.rb +3 -3
- metadata +2 -3
- data/lib/recommendable/workers/rails.rb +0 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 91c45d80ed7ced8b477f8753ad6611b716e0395a
|
4
|
+
data.tar.gz: 7103dd3d7eb386ce8e019b45caade3139b7c8ea9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: eca1215ebbdc0944e24a168ea6ee5a069300dbe7a7cf06051461cc4226eebcf4686ff321aacd07a932a96b08797d65c57084f52421b55ba292d4015095972c97
|
7
|
+
data.tar.gz: 50e043455fb3f7780727a54b7292e4c78045c3691c091ebb79af2204dc10df1e919a2255524b05210fed90186df812fe68cb20e2411cb5998e2de36f518436b5
|
data/lib/recommendable.rb
CHANGED
@@ -5,43 +5,75 @@ module Recommendable
|
|
5
5
|
# The ORM you are using. Currently supported: `:activerecord`, `:mongoid`, ':sequel', ':mongo-mapper' and `:datamapper`
|
6
6
|
attr_accessor :orm
|
7
7
|
|
8
|
-
# Recommendable's connection to Redis
|
8
|
+
# Recommendable's connection to Redis.
|
9
|
+
#
|
10
|
+
# Default: localhost:6379/0
|
9
11
|
attr_accessor :redis
|
10
12
|
|
11
|
-
# A prefix for all keys Recommendable uses
|
13
|
+
# A prefix for all keys Recommendable uses.
|
14
|
+
#
|
15
|
+
# Default: recommendable
|
12
16
|
attr_accessor :redis_namespace
|
13
17
|
|
14
18
|
# Whether or not to automatically enqueue users to have their recommendations
|
15
|
-
# refreshed after they like/dislike an item
|
19
|
+
# refreshed after they like/dislike an item.
|
20
|
+
#
|
21
|
+
# Default: true
|
16
22
|
attr_accessor :auto_enqueue
|
17
23
|
|
18
|
-
# The name of the queue that background jobs will be placed in
|
19
|
-
attr_accessor :queue_name
|
20
|
-
|
21
24
|
# The number of nearest neighbors (k-NN) to check when updating
|
22
25
|
# recommendations for a user. Set to `nil` if you want to check all
|
23
|
-
# neighbors as opposed to a subset of the nearest ones.
|
26
|
+
# neighbors as opposed to a subset of the nearest ones. Set this to a lower
|
27
|
+
# number to improve Redis memory usage.
|
28
|
+
#
|
29
|
+
# Default: nil
|
24
30
|
attr_accessor :nearest_neighbors
|
25
31
|
|
32
|
+
# Like kNN, but also uses some number of most dissimilar users when
|
33
|
+
# updating recommendations for a user. Because, hey, disagreements are
|
34
|
+
# just as important as agreements, right? If `nearest_neighbors` is set to
|
35
|
+
# `nil`, this configuration is ignored. Set this to a lower number
|
36
|
+
# to improve Redis memory usage.
|
37
|
+
#
|
38
|
+
# Default: nil
|
39
|
+
attr_accessor :furthest_neighbors
|
40
|
+
|
41
|
+
# The number of recommendations to store per user. Set this to a lower
|
42
|
+
# number to improve Redis memory usage.
|
43
|
+
#
|
44
|
+
# Default: 100
|
45
|
+
attr_accessor :recommendations_to_store
|
46
|
+
|
26
47
|
attr_accessor :ratable_classes, :user_class
|
27
48
|
|
28
49
|
# Default values
|
29
50
|
def initialize
|
30
|
-
@redis
|
31
|
-
@redis_namespace
|
32
|
-
@auto_enqueue
|
33
|
-
@
|
34
|
-
@
|
35
|
-
@
|
51
|
+
@redis = Redis.new
|
52
|
+
@redis_namespace = :recommendable
|
53
|
+
@auto_enqueue = true
|
54
|
+
@ratable_classes = []
|
55
|
+
@nearest_neighbors = nil
|
56
|
+
@furthest_neihbors = nil
|
57
|
+
@recommendations_to_store = 100
|
58
|
+
end
|
59
|
+
|
60
|
+
def queue_name
|
61
|
+
warn "Recommendable.config.queue_name has been deprecated. Jobs will always be placed in a queue named 'recommendable'."
|
62
|
+
end
|
63
|
+
|
64
|
+
def queue_name=(queue_name)
|
65
|
+
warn "Recommendable.config.queue_name has been deprecated. Jobs will always be placed in a queue named 'recommendable'."
|
36
66
|
end
|
37
67
|
end
|
38
68
|
|
39
69
|
class << self
|
40
|
-
attr_accessor :config
|
41
|
-
|
42
70
|
def configure
|
43
71
|
@config ||= Configuration.new
|
44
72
|
yield @config
|
45
73
|
end
|
74
|
+
|
75
|
+
def config
|
76
|
+
@config ||= Configuration.new
|
77
|
+
end
|
46
78
|
end
|
47
79
|
end
|
@@ -67,6 +67,13 @@ module Recommendable
|
|
67
67
|
Recommendable.redis.zadd(similarity_set, similarity_between(user_id, id), id)
|
68
68
|
end
|
69
69
|
|
70
|
+
if knn = Recommendable.config.nearest_neighbors
|
71
|
+
length = Recommendable.redis.zcard(similarity_set)
|
72
|
+
kfn = Recommendable.config.furthest_neighbors || 0
|
73
|
+
|
74
|
+
Recommendable.redis.zremrangebyrank(similarity_set, kfn, length - knn - 1)
|
75
|
+
end
|
76
|
+
|
70
77
|
true
|
71
78
|
end
|
72
79
|
|
@@ -110,6 +117,11 @@ module Recommendable
|
|
110
117
|
end
|
111
118
|
|
112
119
|
Recommendable.redis.del(temp_set)
|
120
|
+
|
121
|
+
if number_recommendations = Recommendable.config.recommendations_to_store
|
122
|
+
length = Recommendable.redis.zcard(recommended_set)
|
123
|
+
Recommendable.redis.zremrangebyrank(recommended_set, 0, length - number_recommendations - 1)
|
124
|
+
end
|
113
125
|
end
|
114
126
|
|
115
127
|
true
|
@@ -29,7 +29,6 @@ module Recommendable
|
|
29
29
|
warn "Model #{self} is not using a supported ORM. You must handle removal from Redis manually when destroying instances."
|
30
30
|
end
|
31
31
|
|
32
|
-
|
33
32
|
# Whether or not items belonging to this class can be recommended.
|
34
33
|
#
|
35
34
|
# @return true if a user class `recommends :this`
|
@@ -58,26 +57,28 @@ module Recommendable
|
|
58
57
|
# Completely removes this item from redis. Called from a before_destroy hook.
|
59
58
|
# @private
|
60
59
|
def remove_from_recommendable!
|
60
|
+
sets = [] # SREM needed
|
61
|
+
zsets = [] # ZREM needed
|
62
|
+
keys = [] # DEL needed
|
61
63
|
# Remove this item from the score zset
|
62
|
-
Recommendable
|
64
|
+
zsets << Recommendable::Helpers::RedisKeyMapper.score_set_for(self.class)
|
63
65
|
|
64
66
|
# Remove this item's liked_by/disliked_by sets
|
65
|
-
|
66
|
-
|
67
|
-
Recommendable.redis.del(set)
|
68
|
-
end
|
67
|
+
keys << Recommendable::Helpers::RedisKeyMapper.liked_by_set_for(self.class, id)
|
68
|
+
keys << Recommendable::Helpers::RedisKeyMapper.disliked_by_set_for(self.class, id)
|
69
69
|
|
70
70
|
# Remove this item from any user's like/dislike/hidden/bookmark sets
|
71
71
|
%w[liked disliked hidden bookmarked].each do |action|
|
72
|
-
|
73
|
-
Recommendable.redis.keys(set).each do |set|
|
74
|
-
Recommendable.redis.srem(set, id)
|
75
|
-
end
|
72
|
+
sets += Recommendable.redis.keys(Recommendable::Helpers::RedisKeyMapper.send("#{action}_set_for", self.class, '*'))
|
76
73
|
end
|
77
74
|
|
78
75
|
# Remove this item from any user's recommendation zset
|
79
|
-
Recommendable.redis.keys(Recommendable::Helpers::RedisKeyMapper.recommended_set_for(self.class, '*'))
|
80
|
-
|
76
|
+
zsets += Recommendable.redis.keys(Recommendable::Helpers::RedisKeyMapper.recommended_set_for(self.class, '*'))
|
77
|
+
|
78
|
+
Recommendable.redis.pipelined do |redis|
|
79
|
+
sets.each { |set| redis.srem(set, id) }
|
80
|
+
zsets.each { |zset| redis.zrem(zset, id) }
|
81
|
+
redis.del(*keys)
|
81
82
|
end
|
82
83
|
end
|
83
84
|
end
|
@@ -36,31 +36,34 @@ module Recommendable
|
|
36
36
|
# Removes a user from Recommendable. Called internally on a before_destroy hook.
|
37
37
|
# @private
|
38
38
|
def remove_from_recommendable!
|
39
|
-
|
40
|
-
|
39
|
+
sets = [] # SREM needed
|
40
|
+
zsets = [] # ZREM needed
|
41
|
+
keys = [] # DEL needed
|
41
42
|
|
42
43
|
# Remove from other users' similarity ZSETs
|
43
|
-
Recommendable.redis.keys(Recommendable::Helpers::RedisKeyMapper.similarity_set_for('*'))
|
44
|
-
|
45
|
-
|
44
|
+
zsets += Recommendable.redis.keys(Recommendable::Helpers::RedisKeyMapper.similarity_set_for('*'))
|
45
|
+
|
46
|
+
# Remove this user's similarity ZSET
|
47
|
+
keys << Recommendable::Helpers::RedisKeyMapper.similarity_set_for(id)
|
46
48
|
|
47
49
|
# For each ratable class...
|
48
50
|
Recommendable.config.ratable_classes.each do |klass|
|
49
51
|
# Remove this user from any class member's liked_by/disliked_by sets
|
50
|
-
Recommendable.redis.keys(Recommendable::Helpers::RedisKeyMapper.liked_by_set_for(klass, '*'))
|
51
|
-
|
52
|
-
end
|
53
|
-
|
54
|
-
Recommendable.redis.keys(Recommendable::Helpers::RedisKeyMapper.disliked_by_set_for(klass, '*')).each do |set|
|
55
|
-
Recommendable.redis.srem(set, id)
|
56
|
-
end
|
52
|
+
sets += Recommendable.redis.keys(Recommendable::Helpers::RedisKeyMapper.liked_by_set_for(klass, '*'))
|
53
|
+
sets += Recommendable.redis.keys(Recommendable::Helpers::RedisKeyMapper.disliked_by_set_for(klass, '*'))
|
57
54
|
|
58
55
|
# Remove this user's liked/disliked/hidden/bookmarked/recommended sets for the class
|
59
|
-
Recommendable
|
60
|
-
Recommendable
|
61
|
-
Recommendable
|
62
|
-
Recommendable
|
63
|
-
Recommendable
|
56
|
+
keys << Recommendable::Helpers::RedisKeyMapper.liked_set_for(klass, id)
|
57
|
+
keys << Recommendable::Helpers::RedisKeyMapper.disliked_set_for(klass, id)
|
58
|
+
keys << Recommendable::Helpers::RedisKeyMapper.hidden_set_for(klass, id)
|
59
|
+
keys << Recommendable::Helpers::RedisKeyMapper.bookmarked_set_for(klass, id)
|
60
|
+
keys << Recommendable::Helpers::RedisKeyMapper.recommended_set_for(klass, id)
|
61
|
+
end
|
62
|
+
|
63
|
+
Recommendable.redis.pipelined do |redis|
|
64
|
+
sets.each { |set| redis.srem(set, id) }
|
65
|
+
zsets.each { |zset| redis.zrem(zset, id) }
|
66
|
+
redis.del(*keys)
|
64
67
|
end
|
65
68
|
end
|
66
69
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: recommendable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.
|
4
|
+
version: 2.1.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Celis
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-03-
|
11
|
+
date: 2013-03-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -165,7 +165,6 @@ files:
|
|
165
165
|
- lib/recommendable/rater.rb
|
166
166
|
- lib/recommendable/version.rb
|
167
167
|
- lib/recommendable/workers/delayed_job.rb
|
168
|
-
- lib/recommendable/workers/rails.rb
|
169
168
|
- lib/recommendable/workers/resque.rb
|
170
169
|
- lib/recommendable/workers/sidekiq.rb
|
171
170
|
- lib/recommendable/workers/torque_box.rb
|
@@ -1,16 +0,0 @@
|
|
1
|
-
module Recommendable
|
2
|
-
module Workers
|
3
|
-
class Rails
|
4
|
-
attr_accessor :user_id
|
5
|
-
|
6
|
-
def initialize(user_id)
|
7
|
-
@user_id = user_id
|
8
|
-
end
|
9
|
-
|
10
|
-
def run
|
11
|
-
Recommendable::Helpers::Calculations.update_similarities_for(user_id)
|
12
|
-
Recommendable::Helpers::Calculations.update_recommendations_for(user_id)
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|