lunar 0.4.1 → 0.5.0

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.
Files changed (69) hide show
  1. data/.gitignore +2 -1
  2. data/LICENSE +1 -1
  3. data/README.markdown +116 -0
  4. data/Rakefile +6 -5
  5. data/VERSION +1 -1
  6. data/lib/lunar.rb +112 -24
  7. data/lib/lunar/connection.rb +51 -0
  8. data/lib/lunar/fuzzy_matches.rb +24 -0
  9. data/lib/lunar/fuzzy_word.rb +2 -2
  10. data/lib/lunar/index.rb +200 -94
  11. data/lib/lunar/keyword_matches.rb +32 -0
  12. data/lib/lunar/lunar_nest.rb +19 -0
  13. data/lib/lunar/range_matches.rb +28 -0
  14. data/lib/lunar/result_set.rb +85 -28
  15. data/lib/lunar/scoring.rb +4 -2
  16. data/lib/lunar/stopwords.rb +15 -0
  17. data/lib/lunar/words.rb +6 -3
  18. data/lunar.gemspec +31 -60
  19. data/test/helper.rb +4 -5
  20. data/test/test_fuzzy_indexing.rb +105 -0
  21. data/test/test_index.rb +150 -0
  22. data/test/test_lunar.rb +178 -1
  23. data/test/test_lunar_fuzzy_word.rb +4 -4
  24. data/test/test_lunar_nest.rb +46 -0
  25. data/test/{test_lunar_scoring.rb → test_scoring.rb} +5 -5
  26. metadata +72 -68
  27. data/.document +0 -5
  28. data/DATA +0 -41
  29. data/README.md +0 -80
  30. data/examples/ohm.rb +0 -40
  31. data/lib/lunar/search.rb +0 -68
  32. data/lib/lunar/sets.rb +0 -86
  33. data/test/test_lunar_fuzzy.rb +0 -118
  34. data/test/test_lunar_index.rb +0 -191
  35. data/test/test_lunar_search.rb +0 -261
  36. data/test/test_sets.rb +0 -48
  37. data/vendor/nest/nest.rb +0 -7
  38. data/vendor/redis/.gitignore +0 -9
  39. data/vendor/redis/LICENSE +0 -20
  40. data/vendor/redis/README.markdown +0 -120
  41. data/vendor/redis/Rakefile +0 -75
  42. data/vendor/redis/benchmarking/logging.rb +0 -62
  43. data/vendor/redis/benchmarking/pipeline.rb +0 -44
  44. data/vendor/redis/benchmarking/speed.rb +0 -21
  45. data/vendor/redis/benchmarking/suite.rb +0 -24
  46. data/vendor/redis/benchmarking/worker.rb +0 -71
  47. data/vendor/redis/bin/distredis +0 -33
  48. data/vendor/redis/examples/basic.rb +0 -15
  49. data/vendor/redis/examples/dist_redis.rb +0 -43
  50. data/vendor/redis/examples/incr-decr.rb +0 -17
  51. data/vendor/redis/examples/list.rb +0 -26
  52. data/vendor/redis/examples/pubsub.rb +0 -25
  53. data/vendor/redis/examples/sets.rb +0 -36
  54. data/vendor/redis/lib/edis.rb +0 -3
  55. data/vendor/redis/lib/redis.rb +0 -496
  56. data/vendor/redis/lib/redis/client.rb +0 -265
  57. data/vendor/redis/lib/redis/dist_redis.rb +0 -118
  58. data/vendor/redis/lib/redis/distributed.rb +0 -460
  59. data/vendor/redis/lib/redis/hash_ring.rb +0 -131
  60. data/vendor/redis/lib/redis/pipeline.rb +0 -13
  61. data/vendor/redis/lib/redis/raketasks.rb +0 -1
  62. data/vendor/redis/lib/redis/subscribe.rb +0 -79
  63. data/vendor/redis/profile.rb +0 -22
  64. data/vendor/redis/tasks/redis.tasks.rb +0 -140
  65. data/vendor/redis/test/db/.gitignore +0 -1
  66. data/vendor/redis/test/distributed_test.rb +0 -1131
  67. data/vendor/redis/test/redis_test.rb +0 -1134
  68. data/vendor/redis/test/test.conf +0 -8
  69. data/vendor/redis/test/test_helper.rb +0 -113
@@ -1,191 +0,0 @@
1
- require "helper"
2
-
3
- class LunarIndexTest < Test::Unit::TestCase
4
- setup do
5
- Lunar.redis(Redis.new(:host => '127.0.0.1', :port => '6380'))
6
- Lunar.redis.flushdb
7
- end
8
-
9
- context "given Item" do
10
- setup do
11
- @index = Lunar::Index.new('Item')
12
- end
13
-
14
- should "have a Lunar:Item ns" do
15
- assert_equal 'Lunar:Item', @index.ns
16
- end
17
-
18
- context "when setting attr :name, 'iphone'" do
19
- should "have attr(:name) iphone" do
20
- @index.attr :name, 'iphone'
21
-
22
- assert_equal 'iphone', @index.attr(:name)
23
- end
24
- end
25
-
26
- context "when setting attrs name iphone desc cellular mobile" do
27
- setup do
28
- @index.attrs = { :name => 'iphone', :desc => 'cellular mobile' }
29
- end
30
-
31
- should "be able to retrieve them via symbol or string" do
32
- assert_equal 'iphone', @index.attr(:name)
33
- assert_equal 'cellular mobile', @index.attr('desc')
34
- end
35
- end
36
- end
37
-
38
- context "on create" do
39
- setup do
40
- @index = Lunar::Index.create 'Item' do |i|
41
- i.key 1001
42
- i.attr :name, 'iphone 3G'
43
- i.attr :description, 'the cellular mobile is the shiznit'
44
- end
45
- end
46
-
47
- should "store Lunar:Item:name:iphone 1001 1" do
48
- assert_equal "1",
49
- zscore("Lunar:Item:name:#{ encode('iphone') }", 1001)
50
- end
51
-
52
- should "store Lunar:Item:name:3g 1001 1" do
53
- assert_equal "1",
54
- zscore("Lunar:Item:name:#{ encode('3g') }", 1001)
55
- end
56
-
57
- should "store Lunar:Item:description:cellular 1001 1" do
58
- assert_equal "1",
59
- zscore("Lunar:Item:description:#{ encode('cellular') }", 1001)
60
- end
61
-
62
- should "store Lunar:Item:description:the 1001 2" do
63
- assert_equal "2",
64
- zscore("Lunar:Item:description:#{ encode('the') }", 1001)
65
- end
66
-
67
- should "store Lunar:Item:1001:name <iphone 3g> set" do
68
- set = Lunar.redis.smembers("Lunar:Item:1001:name")
69
-
70
- assert set.include?('iphone')
71
- assert set.include?('3g')
72
- end
73
-
74
- should "store Lunar:Item:1001:description of all words" do
75
- set = Lunar.redis.smembers("Lunar:Item:1001:description")
76
-
77
- assert set.include?('the')
78
- assert set.include?('cellular')
79
- assert set.include?('mobile')
80
- assert set.include?('is')
81
- assert set.include?('shiznit')
82
- end
83
- end
84
-
85
- context "when creating an index that already exists" do
86
- setup do
87
- @index = Lunar::Index.create 'Item' do |i|
88
- i.key 1001
89
- i.attr :name, 'iphone 3G'
90
- i.attr :description, 'the cellular mobile is the shiznit'
91
- end
92
-
93
- @index = Lunar::Index.create 'Item' do |i|
94
- i.key 1001
95
- i.attr :name, 'iphone 3GS'
96
- i.attr :description, 'kickass'
97
- end
98
- end
99
-
100
- should "update the references for Item:name" do
101
- set = Lunar.redis.smembers("Lunar:Item:1001:name")
102
-
103
- assert ! set.include?('3g'), "should not include 3G"
104
- assert set.include?('3gs'), "should include 3GS"
105
- end
106
-
107
- should "also remove the scores for the non-existent references for name" do
108
- assert_nil zscore("Lunar:Item:name:#{ encode('3g') }", 1001)
109
- end
110
-
111
- should "update the references for Item:description" do
112
- set = Lunar.redis.smembers("Lunar:Item:1001:description")
113
-
114
- assert ! set.include?('the')
115
- assert ! set.include?('cellular')
116
- assert ! set.include?('mobile')
117
- assert ! set.include?('is')
118
- assert ! set.include?('shiznit')
119
-
120
- assert set.include?('kickass')
121
- end
122
-
123
- should "also remove the scores for the non-existent references for desc" do
124
- assert_nil zscore("Lunar:Item:description:#{ encode('the') }", 1001)
125
- assert_nil zscore("Lunar:Item:description:#{ encode('cellular') }", 1001)
126
- assert_nil zscore("Lunar:Item:description:#{ encode('mobile') }", 1001)
127
- assert_nil zscore("Lunar:Item:description:#{ encode('is') }", 1001)
128
- assert_nil zscore("Lunar:Item:description:#{ encode('shiznit') }", 1001)
129
-
130
- assert_equal "1",
131
- zscore("Lunar:Item:description:#{ encode('kickass') }", 1001)
132
- end
133
- end
134
-
135
- context "on delete" do
136
- setup do
137
- @index = Lunar::Index.create 'Item' do |i|
138
- i.key 1001
139
- i.attr :name, 'iphone 3G'
140
- i.attr :description, 'the cellular mobile is the shiznit'
141
- end
142
-
143
- Lunar::Index.delete('Item', 1001)
144
- end
145
-
146
- should "remove all references of the document words from the scores" do
147
- assert_nil zscore("Lunar:Item:name:#{ encode('iphone') }", 1001)
148
- assert_nil zscore("Lunar:Item:name:#{ encode('3g') }", 1001)
149
-
150
- assert_nil zscore("Lunar:Item:description:#{ encode('the') }", 1001)
151
- assert_nil zscore("Lunar:Item:description:#{ encode('cellular') }", 1001)
152
- assert_nil zscore("Lunar:Item:description:#{ encode('mobile') }", 1001)
153
- assert_nil zscore("Lunar:Item:description:#{ encode('is') }", 1001)
154
- assert_nil zscore("Lunar:Item:description:#{ encode('shiznit') }", 1001)
155
- end
156
-
157
- should "remove all Lunar:Item:* references" do
158
- assert ! Lunar.redis.exists("Lunar:Item:1001:name")
159
- assert ! Lunar.redis.exists("Lunar:Item:1001:description")
160
- end
161
- end
162
-
163
- context "on create of an index with numeric scores" do
164
- setup do
165
- @index = Lunar::Index.create 'Item' do |i|
166
- i.key 1001
167
- i.integer :cost, 2700
168
- i.float :voting_quotient, 35.5
169
- end
170
- end
171
-
172
- should "store Lunar:Item:cost 1001 2700" do
173
- assert_equal "2700", zscore("Lunar:Item:cost", 1001)
174
- end
175
-
176
- should "store Lunar:Item:voting_quotient 1001 35.5" do
177
- assert_equal "35.5", zscore("Lunar:Item:voting_quotient", 1001)
178
- end
179
-
180
-
181
- end
182
-
183
- protected
184
- def encode(str)
185
- Lunar.encode(str)
186
- end
187
-
188
- def zscore(key, value)
189
- Lunar.redis.zscore(key, value)
190
- end
191
- end
@@ -1,261 +0,0 @@
1
- require "helper"
2
-
3
- class Item < Struct.new(:id)
4
- def self.[](id)
5
- new(id)
6
- end
7
- end
8
-
9
- class Person < Struct.new(:id)
10
- def self.[](id)
11
- new(id)
12
- end
13
- end
14
-
15
-
16
-
17
- class LunarSearchTest < Test::Unit::TestCase
18
- setup do
19
- Lunar.redis(Redis.new(:host => "127.0.0.1", :port => 6380))
20
- Lunar.redis.flushdb
21
- end
22
-
23
- context "searching when there exists no index yet" do
24
- should "return an empty set" do
25
- items = Lunar.search(Item, "foobar")
26
-
27
- assert_equal 0, items.size
28
- end
29
- end
30
-
31
- context "when searching a non existent term, with an index existing" do
32
- setup do
33
- Lunar::Index.create "Item" do |i|
34
- i.key 1001
35
- i.attr :name, 'iphone 3GS'
36
- end
37
- end
38
-
39
- should "still return an empty set" do
40
- items = Lunar.search(Item, "foobar")
41
-
42
- assert_equal 0, items.size
43
-
44
- end
45
- end
46
-
47
- # This is how the scheme appears
48
- # Item:name:iphone => 1004 1001
49
- # Item:name:3gs => 1001
50
- # Item:name:apple => 1004 1003 1002
51
- # Item:name:macbook => 1003 1002
52
- # Item:name:pro => 1003 1002
53
- # Item:name:17 => 1003 1002
54
- # Item:desc:iphone => 1004 1003 1002
55
- # Item:desc:4g => 1004 1003
56
- #
57
- context "given the schema appearing above" do
58
- setup do
59
- Lunar::Index.create "Item" do |i|
60
- i.key 1001
61
- i.attr :name, 'iphone 3GS'
62
- end
63
-
64
- Lunar::Index.create "Item" do |i|
65
- i.key 1002
66
- i.attr :name, 'apple macbook pro 17"'
67
- i.attr :desc, 'iphone'
68
- end
69
-
70
- Lunar::Index.create "Item" do |i|
71
- i.key 1003
72
- i.attr :name, 'apple macbook pro 17"'
73
- i.attr :desc, 'iphone 4G'
74
- i.integer :cost, '2300'
75
- i.float :voting_quotient, '35.5'
76
- end
77
-
78
- Lunar::Index.create "Item" do |i|
79
- i.key 1004
80
- i.attr :name, 'iphone apple'
81
- i.attr :desc, 'iphone 4G'
82
- end
83
- end
84
-
85
- should "return all 4 when searching iphone" do
86
- items = Lunar.search(Item, "iphone")
87
-
88
- assert_equal %w(1001 1002 1003 1004), items.map(&:id).sort
89
- end
90
-
91
- should "return only 1001 when searching 3gs" do
92
- items = Lunar.search(Item, '3gs')
93
-
94
- assert_equal %w(1001), items.map(&:id)
95
- end
96
-
97
- should "return only 1002 1003 1004 when searching apple" do
98
- items = Lunar.search(Item, 'APPle')
99
-
100
- assert_equal %w(1002 1003 1004), items.map(&:id).sort
101
- end
102
-
103
- should "return only 1002 1003 when searching macbook, pro, or 17" do
104
- macbook = Lunar.search(Item, 'macbook')
105
- pro = Lunar.search(Item, 'pro')
106
- _17 = Lunar.search(Item, '17')
107
- all = Lunar.search(Item, 'macbook pro 17')
108
-
109
- assert_equal %w(1002 1003), macbook.map(&:id).sort
110
- assert_equal %w(1002 1003), pro.map(&:id).sort
111
- assert_equal %w(1002 1003), _17.map(&:id).sort
112
- assert_equal %w(1002 1003), all.map(&:id).sort
113
- end
114
-
115
- should "return only 1003 1004 when searching 4g" do
116
- items = Lunar.search(Item, '4g')
117
-
118
- assert_equal %w(1003 1004), items.map(&:id).sort
119
- end
120
-
121
- should "return 1001 1004 given name: iphone" do
122
- items = Lunar.search(Item, :name => 'iphone')
123
- assert_equal %w(1001 1004), items.map(&:id).sort
124
- end
125
-
126
- should "return 1004 given name: iphone, desc: iphone" do
127
- items = Lunar.search(Item, :name => 'iphone', :desc => 'iphone')
128
- assert_equal %w(1004), items.map(&:id).sort
129
- end
130
-
131
- should "return 1004 given name: iphone, desc: 4g" do
132
- items = Lunar.search(Item, :name => 'iphone', :desc => '4g')
133
- assert_equal %w(1004), items.map(&:id).sort
134
- end
135
-
136
- should "return 1002 1003 1004 given name: apple, desc: iphone" do
137
- items = Lunar.search(Item, :name => 'apple', :desc => 'iphone')
138
- assert_equal %w(1002 1003 1004), items.map(&:id).sort
139
- end
140
-
141
- should "return 1002 1003 given name: apple macbook pro, desc: iphone" do
142
- items = Lunar.search(Item, :name => 'apple macbook pro', :desc => 'iphone')
143
- assert_equal %w(1002 1003), items.map(&:id).sort
144
- end
145
-
146
- should "return 1003 given name: apple macbook pro 17, desc: 4g" do
147
- items = Lunar.search(Item, :name => 'apple macbook pro 17', :desc => '4g')
148
- assert_equal %w(1003), items.map(&:id).sort
149
- end
150
-
151
- should "be able to search by cost range: 2000..2700" do
152
- items = Lunar.search(Item, :cost => 2000..2700)
153
- assert items.map(&:id).include?('1003')
154
- end
155
-
156
- should "be able to exclude by cost range: 2000..2200" do
157
- items = Lunar.search(Item, :cost => 2000..2200)
158
- assert ! items.map(&:id).include?('1003')
159
- end
160
-
161
- should "be able to search by range of cost and name" do
162
- items = Lunar.search(Item, :cost => 2000..2300, :name => 'apple')
163
- assert items.map(&:id).include?('1003')
164
- end
165
-
166
- should "be able to search by range of cost and exclude by name" do
167
- items = Lunar.search(Item, :cost => 2000..2200, :name => 'foobar')
168
- assert ! items.map(&:id).include?('1003')
169
- end
170
-
171
- should "be able to search by voting_quotient" do
172
- items = Lunar.search(Item, :voting_quotient => 35..40)
173
- assert items.map(&:id).include?('1003')
174
- end
175
- end
176
-
177
- context "given Martin Fowler, Chad Fowler, and Frank Macallen" do
178
- setup do
179
- Lunar::Index.create "Person" do |i|
180
- i.key 1001
181
- i.fuzzy :name, 'Martin Fowler'
182
- end
183
-
184
- Lunar::Index.create "Person" do |i|
185
- i.key 1002
186
- i.fuzzy :name, 'Chad Fowler'
187
- end
188
-
189
- Lunar::Index.create "Person" do |i|
190
- i.key 1003
191
- i.fuzzy :name, 'Frank Macallen'
192
- end
193
- end
194
-
195
- should "return Martin and Frank when searching M, and Ma" do
196
- res1 = Lunar.search(Person, :fuzzy => { :name => 'M' })
197
- res2 = Lunar.search(Person, :fuzzy => { :name => 'Ma' })
198
-
199
- assert_equal %w{1001 1003}, res1.map(&:id)
200
- assert_equal %w{1001 1003}, res2.map(&:id)
201
- end
202
-
203
- should "return only Martin when searching Mar up to Martin" do
204
- res1 = Lunar.search(Person, :fuzzy => { :name => 'Mar' })
205
- res2 = Lunar.search(Person, :fuzzy => { :name => 'Mart' })
206
- res3 = Lunar.search(Person, :fuzzy => { :name => 'Marti' })
207
- res4 = Lunar.search(Person, :fuzzy => { :name => 'Martin' })
208
-
209
- assert_equal %w{1001}, res1.map(&:id)
210
- assert_equal %w{1001}, res2.map(&:id)
211
- assert_equal %w{1001}, res3.map(&:id)
212
- assert_equal %w{1001}, res4.map(&:id)
213
- end
214
-
215
- should "return only Frank when searching Mac up to Macallen" do
216
- res1 = Lunar.search(Person, :fuzzy => { :name => 'Mac' })
217
- res2 = Lunar.search(Person, :fuzzy => { :name => 'Maca' })
218
- res3 = Lunar.search(Person, :fuzzy => { :name => 'Macal' })
219
- res4 = Lunar.search(Person, :fuzzy => { :name => 'Macall' })
220
- res5 = Lunar.search(Person, :fuzzy => { :name => 'Macalle' })
221
- res6 = Lunar.search(Person, :fuzzy => { :name => 'Macallen' })
222
-
223
- assert_equal %w{1003}, res1.map(&:id)
224
- assert_equal %w{1003}, res2.map(&:id)
225
- assert_equal %w{1003}, res3.map(&:id)
226
- assert_equal %w{1003}, res4.map(&:id)
227
- assert_equal %w{1003}, res5.map(&:id)
228
- assert_equal %w{1003}, res6.map(&:id)
229
- end
230
-
231
- should "return the three of them when searching F" do
232
- res1 = Lunar.search(Person, :fuzzy => { :name => 'F' })
233
-
234
- assert_equal %w{1001 1002 1003}, res1.map(&:id)
235
- end
236
-
237
- should "return the 2 fowlers when searching fo up to fowler" do
238
- res1 = Lunar.search(Person, :fuzzy => { :name => 'Fo' })
239
- res2 = Lunar.search(Person, :fuzzy => { :name => 'Fow' })
240
- res3 = Lunar.search(Person, :fuzzy => { :name => 'Fowl' })
241
- res4 = Lunar.search(Person, :fuzzy => { :name => 'Fowle' })
242
- res5 = Lunar.search(Person, :fuzzy => { :name => 'Fowler' })
243
-
244
- assert_equal %w{1001 1002}, res1.map(&:id)
245
- assert_equal %w{1001 1002}, res2.map(&:id)
246
- assert_equal %w{1001 1002}, res3.map(&:id)
247
- assert_equal %w{1001 1002}, res4.map(&:id)
248
- assert_equal %w{1001 1002}, res5.map(&:id)
249
- end
250
-
251
- should "return be able to expire the stored union" do
252
- Lunar.stubs(:ttl).returns(1)
253
- search = Lunar::Search.new(Person, :fuzzy => { :name => 'Fo' })
254
- search.results
255
-
256
- assert Lunar.redis.exists search.send(:dist_key)
257
- sleep 2
258
- assert ! Lunar.redis.exists(search.send(:dist_key))
259
- end
260
- end
261
- end