recommendations 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,22 @@
1
+ module Recommendations
2
+ class Item
3
+ module Similarity
4
+ def similars(count = Recommendations.configuration.similar_count)
5
+ Recommendations.redis.zrange("recommendations:similars:#{id}", 0, count - 1)
6
+ end
7
+
8
+ def update_similars
9
+ Recommendations.redis.del("recommendations:similars:#{id}")
10
+
11
+ categories.each do |category, score|
12
+ items = Recommendations.redis.hgetall("recommendations:categories:#{category}")
13
+
14
+ items.reject {|k, v| k == id}.each do |item, item_score|
15
+ difference = (Float(item_score) - Float(score)).abs
16
+ Recommendations.redis.zincrby("recommendations:similars:#{id}", difference, item)
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -1,9 +1,10 @@
1
1
  module Recommendations
2
2
  class Item
3
+ include Item::Similarity
3
4
  attr_accessor :id
4
5
  attr_writer :categories
5
6
 
6
- def initialize(id, categories)
7
+ def initialize(id, categories = {})
7
8
  @id, @categories = id, categories
8
9
  end
9
10
 
@@ -11,23 +12,6 @@ module Recommendations
11
12
  @categories || {}
12
13
  end
13
14
 
14
- def similars(count = Recommendations.configuration.similar_count)
15
- Recommendations.redis.zrange("recommendations:similars:#{id}", 0, count - 1)
16
- end
17
-
18
- def update_similars
19
- Recommendations.redis.del("recommendations:similars:#{id}")
20
-
21
- categories.each do |category, score|
22
- items = Recommendations.redis.hgetall("recommendations:categories:#{category}")
23
-
24
- items.reject {|k, v| k == id}.each do |item, item_score|
25
- difference = (Float(item_score) - Float(score)).abs
26
- Recommendations.redis.zincrby("recommendations:similars:#{id}", difference, item)
27
- end
28
- end
29
- end
30
-
31
15
  def save!
32
16
  Recommendations.redis.hmset("recommendations:item:#{id}", *categories.flatten)
33
17
 
@@ -0,0 +1,13 @@
1
+ module Recommendations
2
+ class User
3
+ module Ratings
4
+ def rate(item_id, rating)
5
+ Recommendations.redis.hset("recommendations:ratings:#{id}", item_id, rating)
6
+ end
7
+
8
+ def ratings
9
+ Recommendations.redis.hgetall("recommendations:ratings:#{id}")
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,36 @@
1
+ module Recommendations
2
+ MAX_VAL = 2
3
+
4
+ class User
5
+ include User::Ratings
6
+
7
+ attr_accessor :id
8
+
9
+ def initialize(id)
10
+ @id = id
11
+ end
12
+
13
+ def recommendations
14
+ Recommendations.redis.hgetall("recommendations:user:#{id}")
15
+ end
16
+
17
+ def update_recommendations
18
+ ratings = self.ratings
19
+
20
+ recommendations = ratings.inject({}) do |buffer, (item_id, score)|
21
+ similars = Item.find(item_id).similars
22
+ similars.reject! {|i| ratings.key?(i)}
23
+
24
+ similars.each do |similar|
25
+ buffer[similar] ||= 0
26
+ buffer[similar] += (Float(score) - 3) # 0..5 score => -2..2
27
+ end
28
+
29
+ buffer
30
+ end
31
+
32
+ Recommendations.redis.hmset("recommendations:user:#{id}", *recommendations.flatten)
33
+ end
34
+ end
35
+ end
36
+
@@ -1,3 +1,3 @@
1
1
  module Recommendations
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
@@ -2,6 +2,9 @@ require "redis"
2
2
 
3
3
  require "recommendations/version"
4
4
  require "recommendations/configuration"
5
+ require "recommendations/user/ratings"
6
+ require "recommendations/user"
7
+ require "recommendations/item/similarity"
5
8
  require "recommendations/item"
6
9
 
7
10
  module Recommendations
@@ -0,0 +1,32 @@
1
+ require "spec_helper"
2
+
3
+ describe Recommendations::Item do
4
+ subject {Recommendations::Item.new("1", violent: 100, romantic: 25)}
5
+
6
+ describe "#initialize" do
7
+ its(:id) {should == "1"}
8
+ its(:categories) {should == {violent: 100, romantic: 25}}
9
+ end
10
+
11
+ describe "#similars" do
12
+ context "when count was not specified" do
13
+ let(:count) {Recommendations.configuration.similar_count - 1}
14
+
15
+ it "gets sorted set range from similar count configuration" do
16
+ Recommendations.redis.should_receive(:zrange)
17
+ .with("recommendations:similars:1", 0, count)
18
+ .and_return ["2", "3", "4"]
19
+ subject.similars.should == ["2", "3", "4"]
20
+ end
21
+ end
22
+
23
+ context "when count was specified" do
24
+ it "gets sorted set range until count" do
25
+ Recommendations.redis.should_receive(:zrange)
26
+ .with("recommendations:similars:1", 0, 9)
27
+ .and_return ["2", "3", "4"]
28
+ subject.similars(10).should == ["2", "3", "4"]
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,32 @@
1
+ require "spec_helper"
2
+
3
+ describe Recommendations::User::Ratings do
4
+ subject {Recommendations::User.new("1")}
5
+
6
+ describe "#rate" do
7
+ it "stores a user rating for this item" do
8
+ subject.rate("890", 4.5)
9
+ Recommendations.redis.hget("recommendations:ratings:1", "890").should == "4.5"
10
+ end
11
+ end
12
+
13
+ describe "#ratings" do
14
+ let :ratings do
15
+ {
16
+ "1" => "5",
17
+ "2" => "4",
18
+ "3" => "3",
19
+ "4" => "2",
20
+ "5" => "1"
21
+ }
22
+ end
23
+
24
+ before do
25
+ ratings.each {|k, v| subject.rate(k, v)}
26
+ end
27
+
28
+ it "returns all ratings" do
29
+ subject.ratings.should == ratings
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,25 @@
1
+ require "spec_helper"
2
+
3
+ describe Recommendations::User do
4
+ describe "#update_recommendations" do
5
+ subject {Recommendations::User.new("1")}
6
+
7
+ before do
8
+ i1 = Recommendations::Item.new("1", violento: 100, romantico: 0, acao: 50)
9
+ i2 = Recommendations::Item.new("2", violento: 50, romantico: 0, acao: 50) # 1.50
10
+ i3 = Recommendations::Item.new("3", violento: 100, romantico: 100, acao: 0) # 1.150, 2.200
11
+ i4 = Recommendations::Item.new("4", violento: 70, romantico: 30, acao: 20) # 1.90, 2.80
12
+
13
+ items = [i1, i2, i3, i4]
14
+ items.each(&:save!)
15
+ items.each(&:update_similars)
16
+
17
+ subject.rate("1", 5)
18
+ end
19
+
20
+ it "updates recommendations" do
21
+ subject.update_recommendations
22
+ subject.recommendations.should == {"2" => "2.0", "4" => "2.0", "3" => "2.0"}
23
+ end
24
+ end
25
+ end
data/spec/spec_helper.rb CHANGED
@@ -1 +1,8 @@
1
1
  require "rspec"
2
+ require "recommendations"
3
+
4
+ RSpec.configure do |config|
5
+ config.before do
6
+ Recommendations.redis.flushdb
7
+ end
8
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: recommendations
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-05-16 00:00:00.000000000Z
12
+ date: 2012-05-18 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec
16
- requirement: &70243608433720 !ruby/object:Gem::Requirement
16
+ requirement: &70235365846640 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '2.10'
22
22
  type: :development
23
23
  prerelease: false
24
- version_requirements: *70243608433720
24
+ version_requirements: *70235365846640
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: redis
27
- requirement: &70243608433280 !ruby/object:Gem::Requirement
27
+ requirement: &70235365823420 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,7 +32,7 @@ dependencies:
32
32
  version: '0'
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *70243608433280
35
+ version_requirements: *70235365823420
36
36
  description: recommendations between similar items
37
37
  email:
38
38
  - victorc.rodrigues@gmail.com
@@ -50,8 +50,14 @@ files:
50
50
  - lib/recommendations.rb
51
51
  - lib/recommendations/configuration.rb
52
52
  - lib/recommendations/item.rb
53
+ - lib/recommendations/item/similarity.rb
54
+ - lib/recommendations/user.rb
55
+ - lib/recommendations/user/ratings.rb
53
56
  - lib/recommendations/version.rb
54
57
  - recommendations.gemspec
58
+ - spec/recommendations/item_spec.rb
59
+ - spec/recommendations/user/ratings_spec.rb
60
+ - spec/recommendations/user_spec.rb
55
61
  - spec/recommendations_spec.rb
56
62
  - spec/spec_helper.rb
57
63
  homepage: ''
@@ -79,5 +85,8 @@ signing_key:
79
85
  specification_version: 3
80
86
  summary: ''
81
87
  test_files:
88
+ - spec/recommendations/item_spec.rb
89
+ - spec/recommendations/user/ratings_spec.rb
90
+ - spec/recommendations/user_spec.rb
82
91
  - spec/recommendations_spec.rb
83
92
  - spec/spec_helper.rb