picky 4.0.0pre1 → 4.0.0pre2

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 (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