recommendable 2.0.4.20130313 → 2.1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|