picky 4.0.0pre1 → 4.0.0pre2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (112) hide show
  1. data/aux/picky/cli.rb +6 -2
  2. data/lib/picky.rb +10 -8
  3. data/lib/picky/backends/backend.rb +37 -0
  4. data/lib/picky/backends/file.rb +0 -20
  5. data/lib/picky/backends/memory.rb +0 -29
  6. data/lib/picky/backends/redis.rb +74 -15
  7. data/lib/picky/backends/redis/list.rb +1 -1
  8. data/lib/picky/backends/sqlite.rb +0 -27
  9. data/lib/picky/bundle.rb +2 -2
  10. data/lib/picky/bundle_indexed.rb +1 -1
  11. data/lib/picky/bundle_indexing.rb +1 -1
  12. data/lib/picky/categories_indexed.rb +1 -11
  13. data/lib/picky/category.rb +4 -4
  14. data/lib/picky/category/location.rb +25 -0
  15. data/lib/picky/category_realtime.rb +4 -3
  16. data/lib/picky/console.rb +1 -1
  17. data/lib/picky/constants.rb +1 -1
  18. data/lib/picky/ext/maybe_compile.rb +2 -2
  19. data/lib/picky/extensions/object.rb +3 -2
  20. data/lib/picky/generators/aliases.rb +7 -2
  21. data/lib/picky/generators/partial/default.rb +1 -0
  22. data/lib/picky/generators/similarity/default.rb +1 -0
  23. data/lib/picky/generators/similarity/phonetic.rb +13 -2
  24. data/lib/picky/generators/strategy.rb +0 -2
  25. data/lib/picky/generators/weights/constant.rb +1 -2
  26. data/lib/picky/generators/weights/default.rb +1 -0
  27. data/lib/picky/generators/weights/dynamic.rb +1 -1
  28. data/lib/picky/generators/weights/logarithmic.rb +1 -1
  29. data/lib/picky/generators/weights/{runtime.rb → stub.rb} +1 -3
  30. data/lib/picky/index.rb +3 -3
  31. data/lib/picky/index_indexing.rb +0 -2
  32. data/lib/picky/index_realtime.rb +1 -1
  33. data/lib/picky/indexers/base.rb +7 -0
  34. data/lib/picky/indexers/parallel.rb +2 -4
  35. data/lib/picky/indexers/serial.rb +2 -0
  36. data/lib/picky/indexes_indexing.rb +1 -1
  37. data/lib/picky/interfaces/live_parameters/master_child.rb +175 -0
  38. data/lib/picky/interfaces/live_parameters/unicorn.rb +37 -0
  39. data/lib/picky/loader.rb +238 -259
  40. data/lib/picky/query/allocation.rb +19 -10
  41. data/lib/picky/query/combination.rb +7 -1
  42. data/lib/picky/query/combinations.rb +1 -6
  43. data/lib/picky/query/token.rb +26 -36
  44. data/lib/picky/results.rb +18 -17
  45. data/lib/picky/scheduler.rb +2 -1
  46. data/lib/picky/search.rb +1 -1
  47. data/lib/picky/sinatra.rb +6 -6
  48. data/lib/picky/statistics.rb +2 -0
  49. data/lib/picky/tokenizer.rb +8 -8
  50. data/lib/picky/wrappers/bundle/calculation.rb +4 -4
  51. data/lib/picky/wrappers/bundle/location.rb +1 -2
  52. data/lib/tasks/framework.rake +1 -1
  53. data/lib/tasks/statistics.rake +1 -1
  54. data/lib/tasks/try.rake +1 -1
  55. data/lib/tasks/try.rb +1 -1
  56. data/spec/aux/picky/cli_spec.rb +12 -12
  57. data/spec/ext/performant_spec.rb +16 -16
  58. data/spec/functional/backends/file_spec.rb +78 -7
  59. data/spec/functional/backends/memory_spec.rb +78 -7
  60. data/spec/functional/backends/redis_spec.rb +73 -13
  61. data/spec/functional/dynamic_weights_spec.rb +3 -4
  62. data/spec/functional/realtime_spec.rb +2 -2
  63. data/spec/functional/speed_spec.rb +2 -2
  64. data/spec/functional/terminate_early_spec.rb +3 -3
  65. data/spec/lib/analytics_spec.rb +1 -1
  66. data/spec/lib/analyzer_spec.rb +5 -3
  67. data/spec/lib/categories_indexed_spec.rb +38 -20
  68. data/spec/lib/category/location_spec.rb +30 -0
  69. data/spec/lib/character_substituters/west_european_spec.rb +1 -0
  70. data/spec/lib/extensions/hash_spec.rb +6 -5
  71. data/spec/lib/extensions/module_spec.rb +6 -6
  72. data/spec/lib/extensions/object_spec.rb +9 -8
  73. data/spec/lib/extensions/string_spec.rb +1 -1
  74. data/spec/lib/generators/similarity/phonetic_spec.rb +11 -0
  75. data/spec/lib/index_realtime_spec.rb +5 -5
  76. data/spec/lib/interfaces/{live_parameters_spec.rb → live_parameters/master_child_spec.rb} +26 -26
  77. data/spec/lib/interfaces/live_parameters/unicorn_spec.rb +160 -0
  78. data/spec/lib/loader_spec.rb +65 -25
  79. data/spec/lib/query/allocation_spec.rb +25 -22
  80. data/spec/lib/query/combinations_spec.rb +13 -36
  81. data/spec/lib/query/token_spec.rb +144 -131
  82. data/spec/lib/query/tokens_spec.rb +14 -0
  83. data/spec/lib/results_spec.rb +14 -8
  84. data/spec/lib/search_spec.rb +1 -1
  85. data/spec/lib/sinatra_spec.rb +8 -8
  86. metadata +28 -91
  87. data/lib/picky/adapters/rack.rb +0 -34
  88. data/lib/picky/adapters/rack/base.rb +0 -27
  89. data/lib/picky/adapters/rack/live_parameters.rb +0 -37
  90. data/lib/picky/adapters/rack/search.rb +0 -67
  91. data/lib/picky/application.rb +0 -268
  92. data/lib/picky/frontend_adapters/rack.rb +0 -161
  93. data/lib/picky/interfaces/live_parameters.rb +0 -187
  94. data/lib/picky/sources/base.rb +0 -92
  95. data/lib/picky/sources/couch.rb +0 -76
  96. data/lib/picky/sources/csv.rb +0 -83
  97. data/lib/picky/sources/db.rb +0 -189
  98. data/lib/picky/sources/delicious.rb +0 -63
  99. data/lib/picky/sources/mongo.rb +0 -80
  100. data/lib/picky/wrappers/category/location.rb +0 -38
  101. data/lib/tasks/routes.rake +0 -8
  102. data/spec/lib/adapters/rack/base_spec.rb +0 -24
  103. data/spec/lib/adapters/rack/live_parameters_spec.rb +0 -26
  104. data/spec/lib/adapters/rack/query_spec.rb +0 -39
  105. data/spec/lib/application_spec.rb +0 -155
  106. data/spec/lib/frontend_adapters/rack_spec.rb +0 -294
  107. data/spec/lib/sources/base_spec.rb +0 -53
  108. data/spec/lib/sources/couch_spec.rb +0 -114
  109. data/spec/lib/sources/csv_spec.rb +0 -89
  110. data/spec/lib/sources/db_spec.rb +0 -125
  111. data/spec/lib/sources/delicious_spec.rb +0 -94
  112. data/spec/lib/sources/mongo_spec.rb +0 -50
@@ -1,21 +1,21 @@
1
- require File.dirname(__FILE__) + '/../spec_helper'
1
+ require 'spec_helper'
2
2
 
3
3
  describe Performant::Array do
4
-
4
+
5
5
  describe "memory_efficient_intersect" do
6
6
  it "should intersect empty arrays correctly" do
7
7
  arys = [[3,4], [1,2,3], []]
8
-
8
+
9
9
  Performant::Array.memory_efficient_intersect(arys).should == []
10
10
  end
11
11
  it "should handle intermediate empty results correctly" do
12
12
  arys = [[5,4], [1,2,3], [3,4,5,8,9]]
13
-
13
+
14
14
  Performant::Array.memory_efficient_intersect(arys).should == []
15
15
  end
16
16
  it "should intersect correctly" do
17
17
  arys = [[3,4], [1,2,3], [3,4,5,8,9]]
18
-
18
+
19
19
  Performant::Array.memory_efficient_intersect(arys).should == [3]
20
20
  end
21
21
  it "should intersect correctly again" do
@@ -24,24 +24,24 @@ describe Performant::Array do
24
24
  end
25
25
  it "should intersect many arrays" do
26
26
  arys = [[3,4,5,6,7], [1,2,3,5,6,7], [3,4,5,6,7,8,9], [1,2,3,4,5,6,7,8,9,10], [2,3,5,6,7,19], [1,2,3,4,5,6,7,8,9,10], [2,3,5,6,7,19]]
27
-
27
+
28
28
  Performant::Array.memory_efficient_intersect(arys).should == [3,5,6,7]
29
29
  end
30
30
  it "should handle random arrays" do
31
31
  proto = Array.new(100, 3_500_000)
32
32
  arys = [proto.map { |e| rand e }, proto.map { |e| rand e }, proto.map { |e| rand e }]
33
-
33
+
34
34
  Performant::Array.memory_efficient_intersect(arys).should == arys.inject(arys.shift.dup) { |total, ary| total & arys }
35
35
  end
36
36
  it "should be optimal for 2 small arrays of 50/10_000" do
37
37
  arys = [(1..50).to_a, (10_000..20_000).to_a << 7]
38
-
38
+
39
39
  # brute force
40
40
  performance_of { Performant::Array.memory_efficient_intersect(arys) }.should < 0.001
41
41
  end
42
42
  it "should be optimal for 2 small arrays of 50/10_000" do
43
43
  arys = [(1..50).to_a, (10_000..20_000).to_a << 7]
44
-
44
+
45
45
  # &
46
46
  performance_of do
47
47
  arys.inject(arys.shift.dup) do |total, ary|
@@ -50,37 +50,37 @@ describe Performant::Array do
50
50
  end.should < 0.0015
51
51
  end
52
52
  end
53
-
53
+
54
54
  describe "memory_efficient_intersect with symbols" do
55
55
  it "should intersect empty arrays correctly" do
56
56
  arys = [[:c,:d], [:a,:b,:c], []]
57
-
57
+
58
58
  Performant::Array.memory_efficient_intersect(arys).should == []
59
59
  end
60
60
  it "should handle intermediate empty results correctly" do
61
61
  arys = [[:e,:d], [:a,:b,:c], [:c,:d,:e,:h,:i]]
62
-
62
+
63
63
  Performant::Array.memory_efficient_intersect(arys).should == []
64
64
  end
65
65
  it "should intersect correctly" do
66
66
  arys = [[:c,:d], [:a,:b,:c], [:c,:d,:e,:h,:i]]
67
-
67
+
68
68
  Performant::Array.memory_efficient_intersect(arys).should == [:c]
69
69
  end
70
70
  it "should intersect many arrays" do
71
71
  arys = [[:c,:d,:e,:f,:g], [:a,:b,:c,:e,:f,:g], [:c,:d,:e,:f,:g,:h,:i], [:a,:b,:c,:d,:e,:f,:g,:h,:i,:j], [:b,:c,:e,:f,:g,:s], [:a,:b,:c,:d,:e,:f,:g,:h,:i,:j], [:b,:c,:e,:f,:g,:s]]
72
-
72
+
73
73
  Performant::Array.memory_efficient_intersect(arys).should == [:c,:e,:f,:g]
74
74
  end
75
75
  it "should be optimal for 2 small arrays of 50/10_000" do
76
76
  arys = [(:'1'..:'50').to_a, (:'10_000'..:'20_000').to_a]
77
-
77
+
78
78
  # brute force
79
79
  performance_of { Performant::Array.memory_efficient_intersect(arys) }.should < 0.001
80
80
  end
81
81
  it "should be optimal for 2 small arrays of 50/10_000" do
82
82
  arys = [(:'1'..:'50').to_a, (:'10_000'..:'20_000').to_a << 7]
83
-
83
+
84
84
  # &
85
85
  performance_of do
86
86
  arys.inject(arys.shift.dup) do |total, ary|
@@ -18,7 +18,6 @@ describe Picky::Backends::File do
18
18
 
19
19
  let(:data) do
20
20
  Picky::Index.new(:books) do
21
- key_format :to_s # TODO Also make to_i work.
22
21
  source []
23
22
  category :title, partial: Picky::Partial::Postfix.new(from: 1)
24
23
  category :author, similarity: Picky::Generators::Similarity::DoubleMetaphone.new(3)
@@ -26,7 +25,7 @@ describe Picky::Backends::File do
26
25
  end
27
26
  let(:books) { Picky::Search.new data }
28
27
 
29
- its = ->(*) do
28
+ its_to_s = ->(*) do
30
29
  it 'searching for it' do
31
30
  books.search('title').ids.should == ['1']
32
31
  end
@@ -82,15 +81,87 @@ describe Picky::Backends::File do
82
81
  end
83
82
  end
84
83
 
85
- context 'immediately indexing backend (no dump needed)' do
86
- before(:each) do
87
- data.backend described_class.new
84
+ its_to_i = ->(*) do
85
+ it 'searching for it' do
86
+ books.search('title').ids.should == [1]
87
+ end
88
+ it 'searching for it using multiple words' do
89
+ books.search('title author').ids.should == [1]
90
+ end
91
+ it 'searching for it using partial' do
92
+ books.search('tit').ids.should == [1]
93
+ end
94
+ it 'searching for it using similarity' do
95
+ books.search('aothor~').ids.should == [1]
96
+ end
97
+ it 'handles removing' do
98
+ data.remove 1
99
+
100
+ books.search('title').ids.should == []
101
+ end
102
+ it 'handles removing with more than one entry' do
103
+ data.add Book.new(2, 'title', 'author')
104
+
105
+ books.search('title').ids.should == [2, 1]
106
+
107
+ data.remove 1
108
+
109
+ books.search('title').ids.should == [2]
110
+ end
111
+ it 'handles removing with three entries' do
112
+ data.add Book.new(2, 'title', 'author')
113
+ data.add Book.new(3, 'title', 'author')
114
+
115
+ books.search('title').ids.should == [3, 2, 1]
116
+
117
+ data.remove 1
118
+
119
+ books.search('title').ids.should == [3, 2]
120
+ end
121
+ it 'handles replacing' do
122
+ data.replace Book.new(1, 'toitle', 'oithor')
123
+
124
+ books.search('title').ids.should == []
125
+ books.search('toitle').ids.should == [1]
126
+ end
127
+ it 'handles clearing' do
88
128
  data.clear
89
129
 
90
- data.add Book.new(1, 'title', 'author')
130
+ books.search('title').ids.should == []
131
+ end
132
+ it 'handles dumping and loading' do
133
+ data.dump
134
+ data.load
135
+
136
+ books.search('title').ids.should == [1]
137
+ end
138
+ end
139
+
140
+ context 'to_s key format' do
141
+ context 'immediately indexing backend (no dump needed)' do
142
+ before(:each) do
143
+ data.key_format :to_s
144
+ data.backend described_class.new
145
+ data.clear
146
+
147
+ data.add Book.new(1, 'title', 'author')
148
+ end
149
+
150
+ instance_eval &its_to_s
91
151
  end
152
+ end
153
+ context 'to_i key format' do
154
+ context 'immediately indexing backend (no dump needed)' do
155
+ before(:each) do
156
+ data.key_format :to_i
157
+ data.backend described_class.new
158
+ data.clear
159
+
160
+ data.add Book.new(1, 'title', 'author')
161
+ end
92
162
 
93
- instance_eval &its
163
+ instance_eval &its_to_i
164
+ end
94
165
  end
95
166
 
96
167
  end
@@ -18,7 +18,6 @@ describe Picky::Backends::Memory do
18
18
 
19
19
  let(:data) do
20
20
  Picky::Index.new(:books) do
21
- key_format :to_s # TODO Also make to_i work.
22
21
  source []
23
22
  category :title, partial: Picky::Partial::Postfix.new(from: 1)
24
23
  category :author, similarity: Picky::Generators::Similarity::DoubleMetaphone.new(3)
@@ -26,7 +25,7 @@ describe Picky::Backends::Memory do
26
25
  end
27
26
  let(:books) { Picky::Search.new data }
28
27
 
29
- its = ->(*) do
28
+ its_to_s = ->(*) do
30
29
  it 'searching for it' do
31
30
  books.search('title').ids.should == ['1']
32
31
  end
@@ -82,15 +81,87 @@ describe Picky::Backends::Memory do
82
81
  end
83
82
  end
84
83
 
85
- context 'immediately indexing backend (no dump needed)' do
86
- before(:each) do
87
- data.backend described_class.new
84
+ its_to_i = ->(*) do
85
+ it 'searching for it' do
86
+ books.search('title').ids.should == [1]
87
+ end
88
+ it 'searching for it using multiple words' do
89
+ books.search('title author').ids.should == [1]
90
+ end
91
+ it 'searching for it using partial' do
92
+ books.search('tit').ids.should == [1]
93
+ end
94
+ it 'searching for it using similarity' do
95
+ books.search('aothor~').ids.should == [1]
96
+ end
97
+ it 'handles removing' do
98
+ data.remove 1
99
+
100
+ books.search('title').ids.should == []
101
+ end
102
+ it 'handles removing with more than one entry' do
103
+ data.add Book.new(2, 'title', 'author')
104
+
105
+ books.search('title').ids.should == [2, 1]
106
+
107
+ data.remove 1
108
+
109
+ books.search('title').ids.should == [2]
110
+ end
111
+ it 'handles removing with three entries' do
112
+ data.add Book.new(2, 'title', 'author')
113
+ data.add Book.new(3, 'title', 'author')
114
+
115
+ books.search('title').ids.should == [3, 2, 1]
116
+
117
+ data.remove 1
118
+
119
+ books.search('title').ids.should == [3, 2]
120
+ end
121
+ it 'handles replacing' do
122
+ data.replace Book.new(1, 'toitle', 'oithor')
123
+
124
+ books.search('title').ids.should == []
125
+ books.search('toitle').ids.should == [1]
126
+ end
127
+ it 'handles clearing' do
88
128
  data.clear
89
129
 
90
- data.add Book.new(1, 'title', 'author')
130
+ books.search('title').ids.should == []
131
+ end
132
+ it 'handles dumping and loading' do
133
+ data.dump
134
+ data.load
135
+
136
+ books.search('title').ids.should == [1]
137
+ end
138
+ end
139
+
140
+ context 'to_s key format' do
141
+ context 'immediately indexing backend (no dump needed)' do
142
+ before(:each) do
143
+ data.key_format :to_s
144
+ data.backend described_class.new
145
+ data.clear
146
+
147
+ data.add Book.new(1, 'title', 'author')
148
+ end
149
+
150
+ instance_eval &its_to_s
91
151
  end
152
+ end
153
+ context 'to_i key format' do
154
+ context 'immediately indexing backend (no dump needed)' do
155
+ before(:each) do
156
+ data.key_format :to_i
157
+ data.backend described_class.new
158
+ data.clear
159
+
160
+ data.add Book.new(1, 'title', 'author')
161
+ end
92
162
 
93
- instance_eval &its
163
+ instance_eval &its_to_i
164
+ end
94
165
  end
95
166
 
96
167
  end
@@ -18,7 +18,6 @@ describe Picky::Backends::Redis do
18
18
 
19
19
  let(:data) do
20
20
  Picky::Index.new(:books) do
21
- key_format :to_s # TODO Also make to_i work.
22
21
  source []
23
22
  category :title, partial: Picky::Partial::Postfix.new(from: 1)
24
23
  category :author, similarity: Picky::Generators::Similarity::DoubleMetaphone.new(3)
@@ -26,7 +25,7 @@ describe Picky::Backends::Redis do
26
25
  end
27
26
  let(:books) { Picky::Search.new data }
28
27
 
29
- its = ->(*) do
28
+ its_to_s = ->(*) do
30
29
  it 'searching for it' do
31
30
  books.search('title').ids.should == ['1']
32
31
  end
@@ -82,26 +81,87 @@ describe Picky::Backends::Redis do
82
81
  end
83
82
  end
84
83
 
85
- context 'default backend (dump needed)' do
86
- before(:each) do
87
- data.backend Picky::Backends::Redis.new
84
+ its_to_i = ->(*) do
85
+ it 'searching for it' do
86
+ books.search('title').ids.should == [1]
87
+ end
88
+ it 'searching for it using multiple words' do
89
+ books.search('title author').ids.should == [1]
90
+ end
91
+ it 'searching for it using partial' do
92
+ books.search('tit').ids.should == [1]
93
+ end
94
+ it 'searching for it using similarity' do
95
+ books.search('aothor~').ids.should == [1]
96
+ end
97
+ it 'handles removing' do
98
+ data.remove 1
99
+
100
+ books.search('title').ids.should == []
101
+ end
102
+ it 'handles removing with more than one entry' do
103
+ data.add Book.new(2, 'title', 'author')
104
+
105
+ books.search('title').ids.should == [2, 1]
106
+
107
+ data.remove 1
108
+
109
+ books.search('title').ids.should == [2]
110
+ end
111
+ it 'handles removing with three entries' do
112
+ data.add Book.new(2, 'title', 'author')
113
+ data.add Book.new(3, 'title', 'author')
114
+
115
+ books.search('title').ids.should == [3, 2, 1]
116
+
117
+ data.remove 1
118
+
119
+ books.search('title').ids.should == [3, 2]
120
+ end
121
+ it 'handles replacing' do
122
+ data.replace Book.new(1, 'toitle', 'oithor')
123
+
124
+ books.search('title').ids.should == []
125
+ books.search('toitle').ids.should == [1]
126
+ end
127
+ it 'handles clearing' do
88
128
  data.clear
89
129
 
90
- data.add Book.new(1, 'title', 'author')
130
+ books.search('title').ids.should == []
91
131
  end
132
+ it 'handles dumping and loading' do
133
+ data.dump
134
+ data.load
92
135
 
93
- instance_eval &its
136
+ books.search('title').ids.should == [1]
137
+ end
94
138
  end
95
139
 
96
- context 'immediately indexing backend (no dump needed)' do
97
- before(:each) do
98
- data.backend Picky::Backends::Redis.new(immediate: true)
99
- data.clear
140
+ context 'to_s key format' do
141
+ context 'immediately indexing backend (no dump needed)' do
142
+ before(:each) do
143
+ data.key_format :to_s
144
+ data.backend described_class.new
145
+ data.clear
146
+
147
+ data.add Book.new(1, 'title', 'author')
148
+ end
100
149
 
101
- data.add Book.new(1, 'title', 'author')
150
+ instance_eval &its_to_s
102
151
  end
152
+ end
153
+ context 'to_i key format' do
154
+ context 'immediately indexing backend (no dump needed)' do
155
+ before(:each) do
156
+ data.key_format :to_i
157
+ data.backend described_class.new
158
+ data.clear
103
159
 
104
- instance_eval &its
160
+ data.add Book.new(1, 'title', 'author')
161
+ end
162
+
163
+ instance_eval &its_to_i
164
+ end
105
165
  end
106
166
 
107
167
  end
@@ -8,10 +8,9 @@ describe "Weights" do
8
8
  #
9
9
  it 'can handle dynamic weights' do
10
10
  index = Picky::Index.new :dynamic_weights do
11
- source { [] }
12
- category :text1, weights: Picky::Weights::Constant.new
13
- category :text2, weights: Picky::Weights::Constant.new(3.14)
14
- category :text3, weights: Picky::Weights::Dynamic.new { |str_or_sym| str_or_sym.size }
11
+ category :text1, weight: Picky::Weights::Constant.new
12
+ category :text2, weight: Picky::Weights::Constant.new(3.14)
13
+ category :text3, weight: Picky::Weights::Dynamic.new { |str_or_sym| str_or_sym.size }
15
14
  category :text4 # Default
16
15
  end
17
16