octorecommender 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e8c71b55542fbe8ecfc53e19f2943491a5a1510d
4
+ data.tar.gz: 320d5056ee304ab7b94f82a71496d8b660c86d21
5
+ SHA512:
6
+ metadata.gz: 3fa4e9b0d64fa9e6838d46924e89a92e8a5e6a79d19a2fdd3fb67c9a428084870836cca057fee2428c8525c75fb6794a42ce8c4cfb8b2018ca22d7ec400bac19
7
+ data.tar.gz: a437e579d27d2e103a9ff4f6a75bb14ba00b876174fecfae784753032ee2e382ec5f23fd5275dce1095ef36df73bc4d80bffb17b3da5fbd199d2f089c1d3d214
File without changes
@@ -0,0 +1,20 @@
1
+ require 'predictor'
2
+ require 'octocore'
3
+
4
+ require 'octorecommender/recommenders'
5
+ require 'octorecommender/version'
6
+ require 'octorecommender/helpers'
7
+ require 'octorecommender/octohooks'
8
+ require 'octorecommender/scheduler'
9
+
10
+ module Octo
11
+
12
+ # Override Octo's default connection to include
13
+ # connection to Predictor as well
14
+ # See Octo#connect
15
+ def self.connect(configuration)
16
+ self._connect(configuration)
17
+ Predictor.redis = Cequel::Record.redis
18
+ end
19
+
20
+ end
@@ -0,0 +1,2 @@
1
+ require 'octorecommender/helpers/record'
2
+ require 'octorecommender/helpers/generic'
@@ -0,0 +1,11 @@
1
+ module Octo
2
+
3
+ private
4
+
5
+ # Generate the recommender instance
6
+ # @return [Octo::Recommender]
7
+ def recommender
8
+ @recommender = Octo::Recommender.new unless @recommender
9
+ @recommender
10
+ end
11
+ end
@@ -0,0 +1,20 @@
1
+ # Overriding Product class so as to add
2
+ # recommender related helper methods
3
+ module Octo
4
+ module Record
5
+
6
+ def similarities(opts={})
7
+ eid = self.enterprise.id
8
+ recommender.similar_products self, opts
9
+ end
10
+
11
+ private
12
+
13
+ # Generate the recommender instance
14
+ # @return [Octo::Recommender]
15
+ def recommender
16
+ @recommender = Octo::Recommender.new unless @recommender
17
+ @recommender
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,31 @@
1
+ require 'octocore/callbacks'
2
+
3
+ module Octo
4
+
5
+ module OctoHooks
6
+
7
+ # Define the custom tasks that need to be done
8
+ # upon various hooks
9
+ Octo::Callbacks.after_productpage_view lambda { |opts|
10
+ update_recommenders opts
11
+ }
12
+
13
+ # Extend the methods here
14
+ module ClassMethods
15
+
16
+ # Updates the recommenders
17
+ # @param [Hash] opts The options hash as passed
18
+ def update_recommenders(opts)
19
+ user = opts[:user]
20
+ product = opts[:product]
21
+
22
+ if user and product
23
+ recommender = Octo::Recommender.new
24
+ recommender.register_user_product_view(user, product)
25
+ recommender.register_user_action_time(user, Time.now.floor)
26
+ end
27
+ end
28
+
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,143 @@
1
+ require 'predictor'
2
+ require 'octorecommender/recommenders/product_recommender'
3
+ require 'octorecommender/recommenders/time_recommender'
4
+
5
+
6
+ module Octo
7
+ class Recommender
8
+
9
+ # Queue for resque worker processing
10
+ @queue = :recommender
11
+
12
+ # Time format to convert a Time into HHMM format
13
+ TIME_HHMM = '%H%M'
14
+
15
+ # Initializes the Recommender.
16
+ def initialize
17
+ @product_recommenders = {}
18
+ @time_recommenders = {}
19
+
20
+ # This option chosen as ruby seems to take a LOOOOOOOOOOT of time
21
+ # in processing.
22
+ Octo::Recommenders::ProductRecommender.processing_technique(:union)
23
+ Octo::Recommenders::ProductRecommender.processing_technique :union
24
+
25
+ Octo::Enterprise.each do |enterprise|
26
+ @product_recommenders[enterprise.id] = Octo::Recommenders::ProductRecommender.new(enterprise.id)
27
+ @time_recommenders[enterprise.id] = Octo::Recommenders::TimeRecommender.new(enterprise.id)
28
+ end
29
+ end
30
+
31
+ # Register a user, product view relation.
32
+ # @param [Octo::User] user The user object
33
+ # @param [Octo::Product] product The product object
34
+ def register_user_product_view(user, product)
35
+ @product_recommenders[user.enterprise_id].add_to_matrix(:users,
36
+ user.id,
37
+ product.id
38
+ )
39
+
40
+ register_product product
41
+ end
42
+
43
+ # Register a Product for recommendation
44
+ # @param [Octo::Product] product The product object
45
+ def register_product(product)
46
+ eid = product.enterprise_id
47
+ product.categories.each do |cat_text|
48
+ @product_recommenders[eid].add_to_matrix(:categories,
49
+ cat_text,
50
+ product.id
51
+ )
52
+ end
53
+ product.tags.each do |tag_text|
54
+ @product_recommenders[eid].add_to_matrix(:tags,
55
+ tag_text,
56
+ product.id
57
+ )
58
+ end
59
+ end
60
+
61
+ # Register a user, action-time view relation.
62
+ # @param [Octo::User] user The user object
63
+ # @param [Time] ts The time at which user takes some action
64
+ def register_user_action_time(user, ts = Time.now.floor)
65
+ eid = user.enterprise_id
66
+ @time_recommenders[eid].add_to_matrix(:users,
67
+ user.id,
68
+ ts.to_i
69
+ )
70
+
71
+ @time_recommenders[eid].add_to_matrix(:hourminutes,
72
+ ts.strftime(TIME_HHMM),
73
+ ts.to_i
74
+ )
75
+
76
+ @time_recommenders[eid].add_to_matrix(:days,
77
+ ts.strftime('%A'),
78
+ ts.to_i
79
+ )
80
+ end
81
+
82
+ # Get recommended products for a user
83
+ # @param [Octo::User] user The user object for whom product
84
+ # recommendations to be fetched
85
+ # @return [Array<Octo::Product>] An array of Octo::Product recommended
86
+ def recommended_products(user)
87
+ eid = user.enterprise_id
88
+ recommendations = @product_recommenders[eid].predictions_for(
89
+ user.id,
90
+ matrix_label: :users
91
+ )
92
+ recommendations.collect do |x|
93
+ args = { enterprise_id: eid, id: x.to_i}
94
+ Octo::Product.get_cached(args)
95
+ end
96
+ end
97
+
98
+ # Get similar products for products
99
+ # @param [Octo::Product] product The product for which similarities
100
+ # have to be found
101
+ # @return [Array<Octo::Product>] An array containing similar
102
+ # products
103
+ def similar_products(product, opts={})
104
+ eid = product.enterprise.id
105
+ @product_recommenders[eid].similarities_for(product.id, opts)
106
+ end
107
+
108
+ # Get recommended time for a user
109
+ # @param [Octo::User] user The user for whom time to be fetched
110
+ # @return [Array<Time>] The array of time recommended
111
+ def recommended_time(user)
112
+ eid = user.enterprise_id
113
+ recommendations = @time_recommenders[eid].predictions_for(user.id, matrix_label: :users)
114
+ recommendations.map do |ts|
115
+ convert_to_future(Time.at(ts.to_i))
116
+ end
117
+ end
118
+
119
+ # Creates a delayed job to process all the recommenders for all the
120
+ # enterprises or can provide specific options as well
121
+ def process!(opts = {})
122
+ @product_recommenders.values.each do |recomm|
123
+ recomm.process!
124
+ end
125
+ @time_recommenders.values.each do |recomm|
126
+ recomm.process!
127
+ end
128
+ end
129
+
130
+ # Converts a time from past to a similar time in future.
131
+ # This is necessary as CF would return one of the dates
132
+ # from past. We need sometime from future.
133
+ def convert_to_future(ts)
134
+ ts + (Time.now.beginning_of_day - ts.beginning_of_day) + 7.day
135
+ end
136
+
137
+ # Callback method for resque worker
138
+ def self.perform
139
+ self.new.process!
140
+ end
141
+
142
+ end
143
+ end
@@ -0,0 +1,33 @@
1
+ require 'predictor'
2
+ require 'octorecommender'
3
+
4
+ module Octo
5
+ module Recommenders
6
+ # The product recommender class. This class is responsible for recommending
7
+ # a (user, product)
8
+ class ProductRecommender
9
+ include Predictor::Base
10
+
11
+ def initialize(prefix)
12
+ @prefix = prefix
13
+ end
14
+
15
+ def get_redis_prefix
16
+ @prefix
17
+ end
18
+
19
+ limit_similarities_to 20
20
+
21
+ # Stores the user and product relation
22
+ input_matrix :users, weight: 3.0
23
+
24
+ # Store the relation between products asserted by their tags
25
+ input_matrix :tags, weight: 2.0
26
+
27
+ # Store the relation between products asserted by their
28
+ # categories
29
+ input_matrix :categories, weight: 1.0
30
+ end
31
+ end
32
+
33
+ end
@@ -0,0 +1,41 @@
1
+ require 'predictor'
2
+ require 'octorecommender'
3
+
4
+ module Octo
5
+
6
+ module Recommenders
7
+
8
+ # The time recommender class. This class would be responsible for recommending
9
+ # the next set of time for a (user, action)
10
+ class TimeRecommender
11
+ include Predictor::Base
12
+
13
+ def initialize(prefix)
14
+ @prefix = prefix
15
+ end
16
+
17
+ def get_redis_prefix
18
+ @prefix
19
+ end
20
+
21
+ limit_similarities_to 20
22
+
23
+ # This matrix stores the user and their action
24
+ input_matrix :users, weight: 1.0
25
+
26
+ # This matrix stores the relation between times in terms of
27
+ # HHMM.
28
+ # Ex:
29
+ # 11/3/2016 11:30 and 12/3/2016 11:30 have the same HHMM
30
+ input_matrix :hourminutes, weight: 3.0
31
+
32
+ # This matrix stores the relation between times in terms of
33
+ # days.
34
+ # Ex:
35
+ # 4/4/2016 (Monday) and 11/4/2016 (Monday) have the same day
36
+ input_matrix :days, weight: 2.0
37
+ end
38
+
39
+ end
40
+
41
+ end
@@ -0,0 +1,19 @@
1
+
2
+ module Octo
3
+ module Scheduler
4
+
5
+ # Setup Schedule for recommenders
6
+ def schedule_recommender
7
+ name = 'recommender_processing'
8
+ config = {
9
+ class: 'Octo::Recommender',
10
+ args: [],
11
+ cron: '0,30 * * * *',
12
+ persist: true,
13
+ queue: 'recommender'
14
+ }
15
+ Resque.set_schedule name, config
16
+ end
17
+
18
+ end
19
+ end
@@ -0,0 +1,7 @@
1
+ module Octo
2
+ module Recommenders
3
+
4
+ # The version of Recommender module
5
+ VERSION = '0.0.1'
6
+ end
7
+ end
metadata ADDED
@@ -0,0 +1,97 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: octorecommender
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Pranav Prakash
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-07-27 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: predictor
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 2.3.1
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 2.3.0
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: 2.3.1
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 2.3.0
33
+ - !ruby/object:Gem::Dependency
34
+ name: octocore
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: 0.0.1
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: 0.0.1
43
+ type: :runtime
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - "~>"
48
+ - !ruby/object:Gem::Version
49
+ version: 0.0.1
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: 0.0.1
53
+ description: |2
54
+ Contains recommendation specific stuff
55
+ email: pp@octo.ai
56
+ executables: []
57
+ extensions: []
58
+ extra_rdoc_files:
59
+ - README.md
60
+ files:
61
+ - README.md
62
+ - lib/octorecommender.rb
63
+ - lib/octorecommender/helpers.rb
64
+ - lib/octorecommender/helpers/generic.rb
65
+ - lib/octorecommender/helpers/record.rb
66
+ - lib/octorecommender/octohooks.rb
67
+ - lib/octorecommender/recommenders.rb
68
+ - lib/octorecommender/recommenders/product_recommender.rb
69
+ - lib/octorecommender/recommenders/time_recommender.rb
70
+ - lib/octorecommender/scheduler.rb
71
+ - lib/octorecommender/version.rb
72
+ homepage: http://phab.octo.ai/diffusion/GEMS/
73
+ licenses:
74
+ - MIT
75
+ metadata: {}
76
+ post_install_message:
77
+ rdoc_options: []
78
+ require_paths:
79
+ - lib
80
+ required_ruby_version: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ version: '2.0'
85
+ required_rubygems_version: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ requirements: []
91
+ rubyforge_project:
92
+ rubygems_version: 2.4.6
93
+ signing_key:
94
+ specification_version: 4
95
+ summary: Octo Recommender(s) Module
96
+ test_files: []
97
+ has_rdoc: true