inferx 0.2.3 → 0.2.4
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/inferx.rb +2 -4
- data/lib/inferx/categories.rb +173 -18
- data/lib/inferx/category.rb +40 -76
- data/lib/inferx/category/complementary.rb +48 -0
- data/lib/inferx/version.rb +1 -1
- data/spec/inferx/categories_spec.rb +325 -59
- data/spec/inferx/category/complementary_spec.rb +76 -0
- data/spec/inferx/category_spec.rb +60 -119
- data/spec/inferx_spec.rb +1 -9
- data/spec/spec_helper.rb +7 -0
- metadata +5 -11
- data/lib/inferx/adapter.rb +0 -64
- data/lib/inferx/complementary/categories.rb +0 -14
- data/lib/inferx/complementary/category.rb +0 -108
- data/spec/inferx/adapter_spec.rb +0 -92
- data/spec/inferx/complementary/categories_spec.rb +0 -25
- data/spec/inferx/complementary/category_spec.rb +0 -139
@@ -1,108 +0,0 @@
|
|
1
|
-
require 'inferx/category'
|
2
|
-
|
3
|
-
class Inferx
|
4
|
-
module Complementary
|
5
|
-
class Category < Inferx::Category
|
6
|
-
|
7
|
-
# Inject the words to the training data of the category.
|
8
|
-
#
|
9
|
-
# @param [Array<String>] words an array of words
|
10
|
-
alias inject train
|
11
|
-
|
12
|
-
# Eject the words from the training data of the category.
|
13
|
-
#
|
14
|
-
# @param [Array<String>] words an array of words
|
15
|
-
alias eject untrain
|
16
|
-
|
17
|
-
# Prepare to inject the words to the training data of the category. Use
|
18
|
-
# for high performance.
|
19
|
-
#
|
20
|
-
# @yield [train] process something
|
21
|
-
# @yieldparam [Proc] inject inject the words to the training data of the
|
22
|
-
# category
|
23
|
-
ready_for :inject
|
24
|
-
|
25
|
-
# Prepare to eject the words from the training data of the category. Use
|
26
|
-
# for high performance.
|
27
|
-
#
|
28
|
-
# @yield [train] process something
|
29
|
-
# @yieldparam [Proc] eject eject the words from the training data of the
|
30
|
-
# category
|
31
|
-
ready_for :eject
|
32
|
-
|
33
|
-
# Enhance the training data of other categories giving words.
|
34
|
-
#
|
35
|
-
# @param [Array<String>] words an array of words
|
36
|
-
def train(words)
|
37
|
-
return if words.empty?
|
38
|
-
|
39
|
-
increase = words.size
|
40
|
-
words = collect(words)
|
41
|
-
|
42
|
-
category_names = get_other_category_names
|
43
|
-
return if category_names.empty?
|
44
|
-
|
45
|
-
@redis.pipelined do
|
46
|
-
category_names.each do |category_name|
|
47
|
-
category_key = make_category_key(category_name)
|
48
|
-
words.each { |word, count| @redis.zincrby(category_key, count, word) }
|
49
|
-
hincrby(category_name, increase)
|
50
|
-
end
|
51
|
-
|
52
|
-
@redis.save unless manual?
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
# Attenuate the training data of other categories giving words.
|
57
|
-
#
|
58
|
-
# @param [Array<String>] words an array of words
|
59
|
-
def untrain(words)
|
60
|
-
return if words.empty?
|
61
|
-
|
62
|
-
decrease = words.size
|
63
|
-
words = collect(words)
|
64
|
-
|
65
|
-
category_names = get_other_category_names
|
66
|
-
return if category_names.empty?
|
67
|
-
|
68
|
-
scores = @redis.pipelined do
|
69
|
-
category_names.each do |category_name|
|
70
|
-
category_key = make_category_key(category_name)
|
71
|
-
words.each { |word, count| @redis.zincrby(category_key, -count, word) }
|
72
|
-
@redis.zremrangebyscore(category_key, '-inf', 0)
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
length = words.size
|
77
|
-
decreases_by_category = {}
|
78
|
-
|
79
|
-
category_names.each_with_index do |category_name, index|
|
80
|
-
decrease_by_category = decrease
|
81
|
-
|
82
|
-
scores[index * (length + 1), length].each do |score|
|
83
|
-
score = score.to_i
|
84
|
-
decrease_by_category += score if score < 0
|
85
|
-
end
|
86
|
-
|
87
|
-
decreases_by_category[category_name] = decrease_by_category if decrease_by_category > 0
|
88
|
-
end
|
89
|
-
|
90
|
-
return if decreases_by_category.empty?
|
91
|
-
|
92
|
-
@redis.pipelined do
|
93
|
-
decreases_by_category.each do |category_name, decrease|
|
94
|
-
hincrby(category_name, -decrease)
|
95
|
-
end
|
96
|
-
|
97
|
-
@redis.save unless manual?
|
98
|
-
end
|
99
|
-
end
|
100
|
-
|
101
|
-
private
|
102
|
-
|
103
|
-
def get_other_category_names
|
104
|
-
hkeys.reject { |category_name| category_name == name }
|
105
|
-
end
|
106
|
-
end
|
107
|
-
end
|
108
|
-
end
|
data/spec/inferx/adapter_spec.rb
DELETED
@@ -1,92 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require 'inferx/adapter'
|
3
|
-
|
4
|
-
describe Inferx::Adapter, '#initialize' do
|
5
|
-
it 'sets the instance of Redis to @redis' do
|
6
|
-
redis = redis_stub
|
7
|
-
adapter = described_class.new(redis)
|
8
|
-
adapter.instance_eval { @redis }.should == redis
|
9
|
-
end
|
10
|
-
|
11
|
-
it 'sets nil to @namespace' do
|
12
|
-
adapter = described_class.new(redis_stub)
|
13
|
-
adapter.instance_eval { @namespace }.should be_nil
|
14
|
-
end
|
15
|
-
|
16
|
-
it 'sets false to @manual' do
|
17
|
-
adapter = described_class.new(redis_stub)
|
18
|
-
adapter.should_not be_manual
|
19
|
-
end
|
20
|
-
|
21
|
-
context 'with namespace option' do
|
22
|
-
it 'sets the value of namespace option to @namespace' do
|
23
|
-
adapter = described_class.new(redis_stub, :namespace => 'example')
|
24
|
-
adapter.instance_eval { @namespace }.should == 'example'
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
context 'with manual option' do
|
29
|
-
it 'sets the value of manual option to @manual' do
|
30
|
-
adapter = described_class.new(redis_stub, :manual => true)
|
31
|
-
adapter.should be_manual
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
describe Inferx::Adapter, '#categories_key' do
|
37
|
-
it "calls #{described_class}#make_category_key" do
|
38
|
-
adapter = described_class.new(redis_stub)
|
39
|
-
adapter.should_receive(:make_categories_key)
|
40
|
-
adapter.categories_key
|
41
|
-
end
|
42
|
-
|
43
|
-
it "calls #{described_class}#make_category_key once in same instance" do
|
44
|
-
adapter = described_class.new(redis_stub)
|
45
|
-
adapter.should_receive(:make_categories_key).and_return('inferx:categories')
|
46
|
-
adapter.categories_key
|
47
|
-
adapter.categories_key
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
describe Inferx::Adapter, '#make_categories_key' do
|
52
|
-
it 'returns the key for access to categories' do
|
53
|
-
adapter = described_class.new(redis_stub)
|
54
|
-
adapter.categories_key.should == 'inferx:categories'
|
55
|
-
end
|
56
|
-
|
57
|
-
context 'with namespace' do
|
58
|
-
it 'returns the key included the namespace' do
|
59
|
-
adapter = described_class.new(redis_stub, :namespace => 'example')
|
60
|
-
adapter.categories_key.should == 'inferx:example:categories'
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
describe Inferx::Adapter, '#make_category_key' do
|
66
|
-
it 'returns the key for access to scores stored each by word' do
|
67
|
-
adapter = described_class.new(redis_stub)
|
68
|
-
adapter.make_category_key('red').should == 'inferx:categories:red'
|
69
|
-
end
|
70
|
-
|
71
|
-
context 'with namespace' do
|
72
|
-
it 'returns the key included the namespace' do
|
73
|
-
adapter = described_class.new(redis_stub, :namespace => 'example')
|
74
|
-
adapter.make_category_key('red').should == 'inferx:example:categories:red'
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
describe Inferx::Adapter, '#spawn' do
|
80
|
-
it 'calls constructor of the class with the instance variables and the arguments' do
|
81
|
-
redis = redis_stub
|
82
|
-
adapter = described_class.new(redis, :namespace => 'example')
|
83
|
-
klass = mock.tap { |m| m.should_receive(:new).with(redis, 'arg1', 'arg2', :namespace => 'example') }
|
84
|
-
adapter.spawn(klass, 'arg1', 'arg2')
|
85
|
-
end
|
86
|
-
|
87
|
-
it 'returns an instance of the class' do
|
88
|
-
adapter = described_class.new(redis_stub)
|
89
|
-
klass = stub.tap { |s| s.stub!(:new => 'klass') }
|
90
|
-
adapter.spawn(klass).should == 'klass'
|
91
|
-
end
|
92
|
-
end
|
@@ -1,25 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require 'inferx/complementary/categories'
|
3
|
-
|
4
|
-
describe Inferx::Complementary::Categories do
|
5
|
-
it 'inherits Inferx::Categories' do
|
6
|
-
described_class.superclass.should == Inferx::Categories
|
7
|
-
end
|
8
|
-
end
|
9
|
-
|
10
|
-
describe Inferx::Complementary::Categories, '#spawn_category' do
|
11
|
-
before do
|
12
|
-
@categories = described_class.new(redis_stub).tap do |s|
|
13
|
-
s.stub!(:spawn => 'category')
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
it 'calls #spawn with Inferx::Complementary::Category, the categories and the arguments' do
|
18
|
-
@categories.should_receive(:spawn).with(Inferx::Complementary::Category, 'arg1', 'arg2')
|
19
|
-
@categories.__send__(:spawn_category, 'arg1', 'arg2')
|
20
|
-
end
|
21
|
-
|
22
|
-
it 'returns the return value from #spawn' do
|
23
|
-
@categories.__send__(:spawn_category, 'arg1', 'arg2').should == 'category'
|
24
|
-
end
|
25
|
-
end
|
@@ -1,139 +0,0 @@
|
|
1
|
-
require 'inferx/complementary/category'
|
2
|
-
|
3
|
-
describe Inferx::Complementary::Category, '#ready_to_inject' do
|
4
|
-
it 'calls #inject with the words to inject block' do
|
5
|
-
category = described_class.new(redis_stub, 'red', 2)
|
6
|
-
category.should_receive(:inject).with(%w(word1 word2 word3))
|
7
|
-
|
8
|
-
category.ready_to_inject do |inject|
|
9
|
-
inject[%w(word1)]
|
10
|
-
inject[%w(word2)]
|
11
|
-
inject[%w(word3)]
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
describe Inferx::Complementary::Category, '#ready_to_eject' do
|
17
|
-
it 'calls #eject with the words to eject block' do
|
18
|
-
category = described_class.new(redis_stub, 'red', 2)
|
19
|
-
category.should_receive(:eject).with(%w(word1 word2 word3))
|
20
|
-
|
21
|
-
category.ready_to_eject do |eject|
|
22
|
-
eject[%w(word1)]
|
23
|
-
eject[%w(word2)]
|
24
|
-
eject[%w(word3)]
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
describe Inferx::Complementary::Category, '#train' do
|
30
|
-
it 'calls Redis#zincrby and Redis#hincrby for other categories' do
|
31
|
-
redis = redis_stub do |s|
|
32
|
-
s.stub!(:hkeys => %w(red green blue))
|
33
|
-
s.should_receive(:zincrby).with('inferx:categories:green', 2, 'apple')
|
34
|
-
s.should_receive(:zincrby).with('inferx:categories:green', 3, 'strawberry')
|
35
|
-
s.should_receive(:hincrby).with('inferx:categories', 'green', 5)
|
36
|
-
s.should_receive(:zincrby).with('inferx:categories:blue', 2, 'apple')
|
37
|
-
s.should_receive(:zincrby).with('inferx:categories:blue', 3, 'strawberry')
|
38
|
-
s.should_receive(:hincrby).with('inferx:categories', 'blue', 5)
|
39
|
-
s.should_receive(:save)
|
40
|
-
end
|
41
|
-
|
42
|
-
category = described_class.new(redis, 'red', 2)
|
43
|
-
category.train(%w(apple strawberry apple strawberry strawberry))
|
44
|
-
end
|
45
|
-
|
46
|
-
context 'with no update' do
|
47
|
-
it 'does not call Redis#hincrby' do
|
48
|
-
redis = redis_stub do |s|
|
49
|
-
s.should_not_receive(:hincrby)
|
50
|
-
s.should_not_receive(:save)
|
51
|
-
end
|
52
|
-
|
53
|
-
category = described_class.new(redis, 'red', 2)
|
54
|
-
category.train([])
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
context 'with manual save' do
|
59
|
-
it 'does not call Redis#save' do
|
60
|
-
redis = redis_stub do |s|
|
61
|
-
s.stub!(:hkeys => %w(red green blue))
|
62
|
-
s.stub!(:zincrby)
|
63
|
-
s.stub!(:hincrby)
|
64
|
-
s.should_not_receive(:save)
|
65
|
-
end
|
66
|
-
|
67
|
-
category = described_class.new(redis, 'red', 2, :manual => true)
|
68
|
-
category.train(%w(apple strawberry apple strawberry strawberry))
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
describe Inferx::Complementary::Category, '#untrain' do
|
74
|
-
it 'calls Redis#zincrby, Redis#zremrangebyscore and Redis#hincrby for other categories' do
|
75
|
-
redis = redis_stub do |s|
|
76
|
-
s.stub!(:hkeys => %w(red green blue))
|
77
|
-
|
78
|
-
s.stub!(:pipelined).and_return do |&block|
|
79
|
-
block.call
|
80
|
-
%w(1 1 0 2 -1 1)
|
81
|
-
end
|
82
|
-
|
83
|
-
s.should_receive(:zincrby).with('inferx:categories:green', -2, 'apple')
|
84
|
-
s.should_receive(:zincrby).with('inferx:categories:green', -3, 'strawberry')
|
85
|
-
s.should_receive(:zremrangebyscore).with('inferx:categories:green', '-inf', 0)
|
86
|
-
s.should_receive(:zincrby).with('inferx:categories:blue', -2, 'apple')
|
87
|
-
s.should_receive(:zincrby).with('inferx:categories:blue', -3, 'strawberry')
|
88
|
-
s.should_receive(:zremrangebyscore).with('inferx:categories:blue', '-inf', 0)
|
89
|
-
s.should_receive(:hincrby).with('inferx:categories', 'green', -5)
|
90
|
-
s.should_receive(:hincrby).with('inferx:categories', 'blue', -4)
|
91
|
-
s.should_receive(:save)
|
92
|
-
end
|
93
|
-
|
94
|
-
category = described_class.new(redis, 'red', 2)
|
95
|
-
category.untrain(%w(apple strawberry apple strawberry strawberry))
|
96
|
-
end
|
97
|
-
|
98
|
-
context 'with no update' do
|
99
|
-
it 'does not call Redis#zremrangebyscore and Redis#hincrby' do
|
100
|
-
redis = redis_stub do |s|
|
101
|
-
s.stub!(:hkeys => %w(red green blue))
|
102
|
-
|
103
|
-
s.stub!(:pipelined).and_return do |&block|
|
104
|
-
block.call
|
105
|
-
%w(-3 -2 2 -3 -2 2)
|
106
|
-
end
|
107
|
-
|
108
|
-
s.stub!(:zincrby)
|
109
|
-
s.stub!(:zremrangebyscore)
|
110
|
-
s.should_not_receive(:hincrby)
|
111
|
-
s.should_not_receive(:save)
|
112
|
-
end
|
113
|
-
|
114
|
-
category = described_class.new(redis, 'red', 2)
|
115
|
-
category.untrain([])
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
|
-
context 'with manual save' do
|
120
|
-
it 'does not call Redis#save' do
|
121
|
-
redis = redis_stub do |s|
|
122
|
-
s.stub!(:hkeys => %w(red green blue))
|
123
|
-
|
124
|
-
s.stub!(:pipelined).and_return do |&block|
|
125
|
-
block.call
|
126
|
-
%w(1 1 0 2 -1 1)
|
127
|
-
end
|
128
|
-
|
129
|
-
s.stub!(:zincrby)
|
130
|
-
s.stub!(:zremrangebyscore)
|
131
|
-
s.stub!(:hincrby)
|
132
|
-
s.should_not_receive(:save)
|
133
|
-
end
|
134
|
-
|
135
|
-
category = described_class.new(redis, 'red', 2, :manual => true)
|
136
|
-
category.untrain(%w(apple strawberry apple strawberry strawberry))
|
137
|
-
end
|
138
|
-
end
|
139
|
-
end
|