picky 4.11.1 → 4.11.2
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.
|
@@ -16,13 +16,40 @@ module Picky
|
|
|
16
16
|
# Gets the weight for this token's text.
|
|
17
17
|
#
|
|
18
18
|
def weight token
|
|
19
|
-
bundle_for
|
|
19
|
+
bundle = bundle_for token
|
|
20
|
+
if range = token.range
|
|
21
|
+
# The math is not perfectly correct, but you
|
|
22
|
+
# get my idea. Also, we could return early.
|
|
23
|
+
#
|
|
24
|
+
# TODO Possible to speed up more?
|
|
25
|
+
#
|
|
26
|
+
range.inject(nil) do |sum, text|
|
|
27
|
+
weight = bundle.weight(text)
|
|
28
|
+
weight && (weight + (sum || 0)) || sum
|
|
29
|
+
end
|
|
30
|
+
else
|
|
31
|
+
bundle.weight token.text
|
|
32
|
+
end
|
|
20
33
|
end
|
|
21
34
|
|
|
22
35
|
# Gets the ids for this token's text.
|
|
23
36
|
#
|
|
24
37
|
def ids token
|
|
25
|
-
bundle_for
|
|
38
|
+
bundle = bundle_for token
|
|
39
|
+
if range = token.range
|
|
40
|
+
# Adding all to an array, then flattening
|
|
41
|
+
# is faster than using ary + ary.
|
|
42
|
+
#
|
|
43
|
+
range.inject([]) do |result, text|
|
|
44
|
+
# It is 30% faster using the empty check
|
|
45
|
+
# than just << [].
|
|
46
|
+
#
|
|
47
|
+
ids = bundle.ids text
|
|
48
|
+
ids.empty? ? result : result << ids
|
|
49
|
+
end.flatten
|
|
50
|
+
else
|
|
51
|
+
bundle.ids token.text
|
|
52
|
+
end
|
|
26
53
|
end
|
|
27
54
|
|
|
28
55
|
# Returns the right index bundle for this token.
|
|
@@ -34,6 +61,8 @@ module Picky
|
|
|
34
61
|
# Returns a combination for the token,
|
|
35
62
|
# or nil, if there is none.
|
|
36
63
|
#
|
|
64
|
+
# TODO Don't throw away the weight, instead store it in the combination?
|
|
65
|
+
#
|
|
37
66
|
def combination_for token
|
|
38
67
|
weight(token) && Query::Combination.new(token, self)
|
|
39
68
|
end
|
data/lib/picky/query/token.rb
CHANGED
|
@@ -43,6 +43,7 @@ module Picky
|
|
|
43
43
|
qualify
|
|
44
44
|
partialize
|
|
45
45
|
similarize
|
|
46
|
+
rangify
|
|
46
47
|
remove_illegals
|
|
47
48
|
self
|
|
48
49
|
end
|
|
@@ -186,6 +187,27 @@ module Picky
|
|
|
186
187
|
redefine_illegals
|
|
187
188
|
end
|
|
188
189
|
|
|
190
|
+
# Define a character which makes a token a range token.
|
|
191
|
+
#
|
|
192
|
+
# Default is '-'.
|
|
193
|
+
#
|
|
194
|
+
# Example:
|
|
195
|
+
# Picky::Query::Token.range_character = "…"
|
|
196
|
+
# try.search("year:2000…2008") # Will find results in a range.
|
|
197
|
+
#
|
|
198
|
+
@@range_character = '-'
|
|
199
|
+
def self.range_character= character
|
|
200
|
+
@@range_character = character
|
|
201
|
+
end
|
|
202
|
+
def rangify
|
|
203
|
+
if @text.include? @@range_character
|
|
204
|
+
@range = Range.new *@text.split(@@range_character, 2)
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
def range
|
|
208
|
+
@range
|
|
209
|
+
end
|
|
210
|
+
|
|
189
211
|
# Is this a "similar" character?
|
|
190
212
|
#
|
|
191
213
|
def similar?
|
|
@@ -4,11 +4,14 @@ require 'spec_helper'
|
|
|
4
4
|
|
|
5
5
|
describe 'custom delimiters' do
|
|
6
6
|
|
|
7
|
+
# TODO Add range query delimiter.
|
|
8
|
+
#
|
|
7
9
|
after(:each) do
|
|
8
10
|
Picky::Query::Token.partial_character = '\*'
|
|
9
11
|
Picky::Query::Token.no_partial_character = '"'
|
|
10
12
|
Picky::Query::Token.similar_character = '~'
|
|
11
13
|
Picky::Query::Token.no_similar_character = '"'
|
|
14
|
+
Picky::Query::Token.range_character = '-'
|
|
12
15
|
Picky::Query::Token.qualifier_text_delimiter = ':'
|
|
13
16
|
Picky::Query::Token.qualifiers_delimiter = ','
|
|
14
17
|
end
|
|
@@ -76,4 +79,25 @@ describe 'custom delimiters' do
|
|
|
76
79
|
Picky::Query::Token.qualifiers_delimiter = '|'
|
|
77
80
|
try.search("text1|text2?hello text2?world").ids.should == [1]
|
|
78
81
|
end
|
|
82
|
+
|
|
83
|
+
it 'offers custom range characters to be set' do
|
|
84
|
+
index = Picky::Index.new :custom_range_character do
|
|
85
|
+
category :year
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
rangy = Struct.new :id, :year
|
|
89
|
+
|
|
90
|
+
index.add rangy.new(1, 1977)
|
|
91
|
+
index.add rangy.new(2, 1989)
|
|
92
|
+
index.add rangy.new(3, 2001)
|
|
93
|
+
index.add rangy.new(4, 2012)
|
|
94
|
+
index.add rangy.new(4, 3000)
|
|
95
|
+
|
|
96
|
+
try = Picky::Search.new index
|
|
97
|
+
try.search("1980-2015").ids.should == [2,3,4]
|
|
98
|
+
|
|
99
|
+
try.search("1980…2015").ids.should == []
|
|
100
|
+
Picky::Query::Token.range_character = "…"
|
|
101
|
+
try.search("1980…2015").ids.should == [2,3,4]
|
|
102
|
+
end
|
|
79
103
|
end
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
#
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
|
|
5
|
+
describe 'range queries' do
|
|
6
|
+
|
|
7
|
+
let(:index) do
|
|
8
|
+
index = Picky::Index.new :range_queries do
|
|
9
|
+
category :year
|
|
10
|
+
category :alphabet
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
rangy = Struct.new :id, :year, :alphabet
|
|
14
|
+
|
|
15
|
+
index.add rangy.new(1, 2000, 'g')
|
|
16
|
+
index.add rangy.new(2, 1977, 'f')
|
|
17
|
+
index.add rangy.new(3, 1989, 'a')
|
|
18
|
+
index.add rangy.new(4, 2011, 'u')
|
|
19
|
+
index.add rangy.new(5, 3000, 'v')
|
|
20
|
+
index.add rangy.new(6, 1291, 'z')
|
|
21
|
+
index.add rangy.new(7, 881, 'm')
|
|
22
|
+
index.add rangy.new(8, 1984, 'l')
|
|
23
|
+
|
|
24
|
+
index
|
|
25
|
+
end
|
|
26
|
+
let(:try) { Picky::Search.new index }
|
|
27
|
+
|
|
28
|
+
it 'still works with exact queries' do
|
|
29
|
+
try.search('1980').ids.should == []
|
|
30
|
+
try.search('1989').ids.should == [3]
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it 'works with misses' do
|
|
34
|
+
try.search('900-1200').ids.should == []
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it 'survives huge ranges' do
|
|
38
|
+
try.search('0-10000 a').ids.should == [3]
|
|
39
|
+
|
|
40
|
+
# Quote to make it non-partial.
|
|
41
|
+
#
|
|
42
|
+
try.search('0-3000"').ids.should == [7,6,2,8,3,1,4,5]
|
|
43
|
+
end
|
|
44
|
+
it 'is semi-reasonably fast with huge ranges' do
|
|
45
|
+
# Quote to make it non-partial.
|
|
46
|
+
#
|
|
47
|
+
performance_of { try.search('0-3000"') }.should < 0.21
|
|
48
|
+
|
|
49
|
+
# Note it is much much faster with an additional token.
|
|
50
|
+
#
|
|
51
|
+
performance_of { try.search('0-3000 a') }.should < 0.0085
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it 'handles basic range queries' do
|
|
55
|
+
try.search('1980-2001').ids.should == [8,3,1]
|
|
56
|
+
try.search('f-u').ids.should == [2,1,8,7,4]
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it 'can handle qualifiers' do
|
|
60
|
+
try.search('year:1980-2001').ids.should == [8,3,1]
|
|
61
|
+
try.search('alphabet:f-u').ids.should == [2,1,8,7,4]
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
it 'can be combined with other search words' do
|
|
65
|
+
try.search('1980-2001 a').ids.should == [3]
|
|
66
|
+
try.search('f-u 881').ids.should == [7]
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
it 'can handle multiple range queries' do
|
|
70
|
+
try.search('1980-2001 a-h').ids.should == [3,1]
|
|
71
|
+
try.search('f-u 881-1977').ids.should == [2,7]
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
it 'can be combined with partial queries' do
|
|
75
|
+
try.search('198* a-h').ids.should == [3]
|
|
76
|
+
try.search('a-h 198').ids.should == [3]
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
it 'works with nonsensical ranges' do
|
|
80
|
+
try.search('h-a').ids.should == []
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# it 'handles combined range/partial queries' do
|
|
84
|
+
# # TODO This still needs to be refined. It is madness.
|
|
85
|
+
# #
|
|
86
|
+
# try.search('198-200*').ids.should == [8,3,1,4,5,7,6,2]
|
|
87
|
+
# end
|
|
88
|
+
|
|
89
|
+
end
|
|
@@ -64,53 +64,120 @@ describe Picky::Category do
|
|
|
64
64
|
end
|
|
65
65
|
|
|
66
66
|
describe 'weight' do
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
67
|
+
let(:token) { stub :token, :text => :some_text }
|
|
68
|
+
context 'without range' do
|
|
69
|
+
before :each do
|
|
70
|
+
token.stub! :range => nil
|
|
71
|
+
end
|
|
72
|
+
context 'partial bundle' do
|
|
73
|
+
before(:each) do
|
|
74
|
+
@category.stub! :bundle_for => @partial
|
|
75
|
+
end
|
|
76
|
+
it 'should receive weight with the token text' do
|
|
77
|
+
@partial.should_receive(:weight).once.with :some_text
|
|
78
|
+
|
|
79
|
+
@category.weight token
|
|
80
|
+
end
|
|
73
81
|
end
|
|
74
|
-
|
|
75
|
-
|
|
82
|
+
context 'exact bundle' do
|
|
83
|
+
before(:each) do
|
|
84
|
+
@category.stub! :bundle_for => @exact
|
|
85
|
+
end
|
|
86
|
+
it 'should receive weight with the token text' do
|
|
87
|
+
@exact.should_receive(:weight).once.with :some_text
|
|
76
88
|
|
|
77
|
-
|
|
89
|
+
@category.weight token
|
|
90
|
+
end
|
|
78
91
|
end
|
|
79
92
|
end
|
|
80
|
-
context '
|
|
81
|
-
before
|
|
82
|
-
|
|
93
|
+
context 'with range' do
|
|
94
|
+
before :each do
|
|
95
|
+
token.stub! :range => (1..3)
|
|
96
|
+
end
|
|
97
|
+
context 'partial bundle' do
|
|
98
|
+
before(:each) do
|
|
99
|
+
@category.stub! :bundle_for => @partial
|
|
100
|
+
end
|
|
101
|
+
it 'should receive weight with the token text' do
|
|
102
|
+
@partial.should_receive(:weight).once.times.with(1).and_return(1)
|
|
103
|
+
@partial.should_receive(:weight).once.times.with(2).and_return(2)
|
|
104
|
+
@partial.should_receive(:weight).once.times.with(3).and_return(3)
|
|
105
|
+
|
|
106
|
+
@category.weight(token).should == 6
|
|
107
|
+
end
|
|
108
|
+
it 'returns nil if none hit' do
|
|
109
|
+
@partial.should_receive(:weight).once.times.with(1).and_return(nil)
|
|
110
|
+
@partial.should_receive(:weight).once.times.with(2).and_return(nil)
|
|
111
|
+
@partial.should_receive(:weight).once.times.with(3).and_return(nil)
|
|
112
|
+
|
|
113
|
+
@category.weight(token).should == nil
|
|
114
|
+
end
|
|
83
115
|
end
|
|
84
|
-
|
|
85
|
-
|
|
116
|
+
context 'exact bundle' do
|
|
117
|
+
before(:each) do
|
|
118
|
+
@category.stub! :bundle_for => @exact
|
|
119
|
+
end
|
|
120
|
+
it 'should receive weight with the token text' do
|
|
121
|
+
@exact.should_receive(:weight).once.times.with(1).and_return(1)
|
|
122
|
+
@exact.should_receive(:weight).once.times.with(2).and_return(2)
|
|
123
|
+
@exact.should_receive(:weight).once.times.with(3).and_return(3)
|
|
86
124
|
|
|
87
|
-
|
|
125
|
+
@category.weight(token).should == 6
|
|
126
|
+
end
|
|
88
127
|
end
|
|
89
128
|
end
|
|
90
129
|
end
|
|
91
130
|
|
|
92
131
|
describe 'ids' do
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
132
|
+
let(:token) { stub :token, :text => :some_text }
|
|
133
|
+
context 'without range' do
|
|
134
|
+
before(:each) { token.stub! :range => nil }
|
|
135
|
+
context 'partial bundle' do
|
|
136
|
+
before(:each) do
|
|
137
|
+
@category.stub! :bundle_for => @partial
|
|
138
|
+
end
|
|
139
|
+
it 'should receive ids with the token text' do
|
|
140
|
+
@partial.should_receive(:ids).once.with :some_text
|
|
141
|
+
|
|
142
|
+
@category.ids token
|
|
143
|
+
end
|
|
99
144
|
end
|
|
100
|
-
|
|
101
|
-
|
|
145
|
+
context 'exact bundle' do
|
|
146
|
+
before(:each) do
|
|
147
|
+
@category.stub! :bundle_for => @exact
|
|
148
|
+
end
|
|
149
|
+
it 'should receive ids with the token text' do
|
|
150
|
+
@exact.should_receive(:ids).once.with :some_text
|
|
102
151
|
|
|
103
|
-
|
|
152
|
+
@category.ids token
|
|
153
|
+
end
|
|
104
154
|
end
|
|
105
155
|
end
|
|
106
|
-
context '
|
|
107
|
-
before(:each)
|
|
108
|
-
|
|
156
|
+
context 'with range' do
|
|
157
|
+
before(:each) { token.stub! :range => (1..3) }
|
|
158
|
+
context 'partial bundle' do
|
|
159
|
+
before(:each) do
|
|
160
|
+
@category.stub! :bundle_for => @partial
|
|
161
|
+
end
|
|
162
|
+
it 'should receive ids with the token text' do
|
|
163
|
+
@partial.should_receive(:ids).once.with(1).and_return [1]
|
|
164
|
+
@partial.should_receive(:ids).once.with(2).and_return [2]
|
|
165
|
+
@partial.should_receive(:ids).once.with(3).and_return [3]
|
|
166
|
+
|
|
167
|
+
@category.ids(token).should == [1,2,3]
|
|
168
|
+
end
|
|
109
169
|
end
|
|
110
|
-
|
|
111
|
-
|
|
170
|
+
context 'exact bundle' do
|
|
171
|
+
before(:each) do
|
|
172
|
+
@category.stub! :bundle_for => @exact
|
|
173
|
+
end
|
|
174
|
+
it 'should receive ids with the token text' do
|
|
175
|
+
@exact.should_receive(:ids).once.with(1).and_return [1]
|
|
176
|
+
@exact.should_receive(:ids).once.with(2).and_return [2]
|
|
177
|
+
@exact.should_receive(:ids).once.with(3).and_return [3]
|
|
112
178
|
|
|
113
|
-
|
|
179
|
+
@category.ids(token).should == [1,2,3]
|
|
180
|
+
end
|
|
114
181
|
end
|
|
115
182
|
end
|
|
116
183
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: picky
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 4.11.
|
|
4
|
+
version: 4.11.2
|
|
5
5
|
prerelease:
|
|
6
6
|
platform: ruby
|
|
7
7
|
authors:
|
|
@@ -9,7 +9,7 @@ authors:
|
|
|
9
9
|
autorequire:
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date: 2012-11-
|
|
12
|
+
date: 2012-11-06 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: rspec
|
|
@@ -34,7 +34,7 @@ dependencies:
|
|
|
34
34
|
requirements:
|
|
35
35
|
- - ~>
|
|
36
36
|
- !ruby/object:Gem::Version
|
|
37
|
-
version: 4.11.
|
|
37
|
+
version: 4.11.2
|
|
38
38
|
type: :development
|
|
39
39
|
prerelease: false
|
|
40
40
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -42,7 +42,7 @@ dependencies:
|
|
|
42
42
|
requirements:
|
|
43
43
|
- - ~>
|
|
44
44
|
- !ruby/object:Gem::Version
|
|
45
|
-
version: 4.11.
|
|
45
|
+
version: 4.11.2
|
|
46
46
|
- !ruby/object:Gem::Dependency
|
|
47
47
|
name: text
|
|
48
48
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -282,6 +282,7 @@ files:
|
|
|
282
282
|
- spec/functional/non_specific_ids_larger_than_20_spec.rb
|
|
283
283
|
- spec/functional/only_spec.rb
|
|
284
284
|
- spec/functional/pool_spec.rb
|
|
285
|
+
- spec/functional/range_queries_spec.rb
|
|
285
286
|
- spec/functional/realtime_spec.rb
|
|
286
287
|
- spec/functional/regression_spec.rb
|
|
287
288
|
- spec/functional/reloading_spec.rb
|
|
@@ -445,6 +446,7 @@ test_files:
|
|
|
445
446
|
- spec/functional/non_specific_ids_larger_than_20_spec.rb
|
|
446
447
|
- spec/functional/only_spec.rb
|
|
447
448
|
- spec/functional/pool_spec.rb
|
|
449
|
+
- spec/functional/range_queries_spec.rb
|
|
448
450
|
- spec/functional/realtime_spec.rb
|
|
449
451
|
- spec/functional/regression_spec.rb
|
|
450
452
|
- spec/functional/reloading_spec.rb
|