picky 4.11.1 → 4.11.2
Sign up to get free protection for your applications and to get access to all the features.
@@ -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
|