picky 3.6.11 → 3.6.12
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.
- data/lib/picky/query/allocation.rb +6 -1
- data/lib/picky/query/allocations.rb +15 -6
- data/lib/picky/results.rb +4 -4
- data/lib/picky/search.rb +32 -1
- data/lib/picky/wrappers/category/exact_first.rb +2 -0
- data/spec/functional/max_allocations_spec.rb +4 -4
- data/spec/functional/regression_spec.rb +28 -0
- data/spec/functional/terminate_early_spec.rb +80 -0
- data/spec/lib/query/allocations_spec.rb +28 -0
- data/spec/lib/query/combination_spec.rb +12 -0
- metadata +23 -21
@@ -8,7 +8,6 @@ module Picky
|
|
8
8
|
class Allocation # :nodoc:all
|
9
9
|
|
10
10
|
attr_reader :count,
|
11
|
-
:ids,
|
12
11
|
:score,
|
13
12
|
:combinations,
|
14
13
|
:result_identifier
|
@@ -42,6 +41,12 @@ module Picky
|
|
42
41
|
@backend.ids combinations, amount, offset
|
43
42
|
end
|
44
43
|
|
44
|
+
# Ids return by default [].
|
45
|
+
#
|
46
|
+
def ids
|
47
|
+
@ids ||= []
|
48
|
+
end
|
49
|
+
|
45
50
|
# This starts the searching process.
|
46
51
|
#
|
47
52
|
def process! amount, offset
|
@@ -6,8 +6,6 @@ module Picky
|
|
6
6
|
#
|
7
7
|
class Allocations # :nodoc:all
|
8
8
|
|
9
|
-
attr_reader :total
|
10
|
-
|
11
9
|
delegate :each,
|
12
10
|
:empty?,
|
13
11
|
:first,
|
@@ -63,6 +61,7 @@ module Picky
|
|
63
61
|
# Parameters:
|
64
62
|
# * amount: the amount of ids to calculate
|
65
63
|
# * offset: the offset from where in the result set to take the ids
|
64
|
+
# * terminate_early: Whether to calculate all allocations.
|
66
65
|
#
|
67
66
|
# Note: With an amount of 0, an offset > 0 doesn't make much
|
68
67
|
# sense, as seen in the live search.
|
@@ -72,18 +71,28 @@ module Picky
|
|
72
71
|
#
|
73
72
|
# Note: It's possible that no ids are returned by an allocation, but a count. (In case of an offset)
|
74
73
|
#
|
75
|
-
def process! amount, offset = 0
|
76
|
-
@total = 0
|
74
|
+
def process! amount, offset = 0, terminate_early = nil
|
77
75
|
current_offset = 0
|
78
|
-
|
76
|
+
each do |allocation|
|
79
77
|
ids = allocation.process! amount, offset
|
80
|
-
@total = @total + allocation.count # the total mixed in
|
81
78
|
if ids.empty?
|
82
79
|
offset = offset - allocation.count unless offset.zero?
|
83
80
|
else
|
84
81
|
amount = amount - ids.size # we need less results from the following allocation
|
85
82
|
offset = 0 # we have already passed the offset
|
86
83
|
end
|
84
|
+
if terminate_early
|
85
|
+
break if terminate_early < 0 && offset <= 0
|
86
|
+
terminate_early -= 1
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
# The total is simply the sum of the counts of all allocations.
|
92
|
+
#
|
93
|
+
def total
|
94
|
+
@total ||= inject(0) do |total, allocation|
|
95
|
+
total + (allocation.count || break)
|
87
96
|
end
|
88
97
|
end
|
89
98
|
|
data/lib/picky/results.rb
CHANGED
@@ -24,9 +24,9 @@ module Picky
|
|
24
24
|
|
25
25
|
# Create new results and calculate the ids.
|
26
26
|
#
|
27
|
-
def self.from query, amount, offset, allocations
|
27
|
+
def self.from query, amount, offset, allocations, extra_allocations = nil
|
28
28
|
results = new query, amount, offset, allocations
|
29
|
-
results.prepare!
|
29
|
+
results.prepare! extra_allocations
|
30
30
|
results
|
31
31
|
end
|
32
32
|
|
@@ -53,8 +53,8 @@ module Picky
|
|
53
53
|
# Without this, the allocations are not processed,
|
54
54
|
# and no ids are calculated.
|
55
55
|
#
|
56
|
-
def prepare!
|
57
|
-
allocations.process! amount, offset
|
56
|
+
def prepare! extra_allocations = nil
|
57
|
+
allocations.process! amount, offset, extra_allocations
|
58
58
|
end
|
59
59
|
|
60
60
|
# Returns a hash with the allocations, offset, duration and total.
|
data/lib/picky/search.rb
CHANGED
@@ -80,6 +80,37 @@ module Picky
|
|
80
80
|
amount ? @max_allocations = amount : @max_allocations
|
81
81
|
end
|
82
82
|
|
83
|
+
# Tells Picky to terminate calculating ids if it has enough ids.
|
84
|
+
# (So, early)
|
85
|
+
#
|
86
|
+
# Important note: Do not use this for the live search!
|
87
|
+
# (As Picky needs to calculate the total)
|
88
|
+
#
|
89
|
+
# Note: When using the Picky interface, do not terminate too
|
90
|
+
# early as this will kill off the allocation selections.
|
91
|
+
# A value of
|
92
|
+
# early_terminate 5
|
93
|
+
# is probably a good idea to show the user 5 extra
|
94
|
+
# beyond the needed ones.
|
95
|
+
#
|
96
|
+
# Examples:
|
97
|
+
# # Terminate if you have enough ids.
|
98
|
+
# #
|
99
|
+
# search = Search.new(index1, index2, index3) do
|
100
|
+
# terminate_early
|
101
|
+
# end
|
102
|
+
#
|
103
|
+
# # After calculating enough ids,
|
104
|
+
# # calculate 5 extra allocations for the interface.
|
105
|
+
# #
|
106
|
+
# search = Search.new(index1, index2, index3) do
|
107
|
+
# terminate_early 5
|
108
|
+
# end
|
109
|
+
#
|
110
|
+
def terminate_early extra_allocations = 0
|
111
|
+
@extra_allocations = extra_allocations.respond_to?(:to_hash) ? extra_allocations[:with_extra_allocations] : extra_allocations
|
112
|
+
end
|
113
|
+
|
83
114
|
# Examples:
|
84
115
|
# search = Search.new(books_index, dvd_index, mp3_index) do
|
85
116
|
# boost [:author, :title] => +3,
|
@@ -174,7 +205,7 @@ module Picky
|
|
174
205
|
# Note: Internal method, use #search to search.
|
175
206
|
#
|
176
207
|
def execute tokens, ids, offset, original_text = nil
|
177
|
-
Results.from original_text, ids, offset, sorted_allocations(tokens, @max_allocations)
|
208
|
+
Results.from original_text, ids, offset, sorted_allocations(tokens, @max_allocations), @extra_allocations
|
178
209
|
end
|
179
210
|
|
180
211
|
# Delegates the tokenizing to the query tokenizer.
|
@@ -38,7 +38,7 @@ describe 'Search#max_allocations' do
|
|
38
38
|
category :text4
|
39
39
|
end
|
40
40
|
|
41
|
-
thing = Struct.new
|
41
|
+
thing = Struct.new :id, :text1, :text2, :text3, :text4
|
42
42
|
index.add thing.new(1, 'hello world', 'hello world', 'hello world', 'hello world')
|
43
43
|
index.add thing.new(2, 'hello world', 'hello world', 'hello world', 'hello world')
|
44
44
|
index.add thing.new(3, 'hello world', 'hello world', 'hello world', 'hello world')
|
@@ -49,7 +49,7 @@ describe 'Search#max_allocations' do
|
|
49
49
|
try = Picky::Search.new index
|
50
50
|
|
51
51
|
threshold = performance_of do
|
52
|
-
try.search
|
52
|
+
try.search 'hello world'
|
53
53
|
end
|
54
54
|
|
55
55
|
try_again = Picky::Search.new index do
|
@@ -57,8 +57,8 @@ describe 'Search#max_allocations' do
|
|
57
57
|
end
|
58
58
|
|
59
59
|
performance_of do
|
60
|
-
try_again.search
|
61
|
-
end.should < (threshold*
|
60
|
+
try_again.search 'hello world'
|
61
|
+
end.should < (threshold*2/3)
|
62
62
|
end
|
63
63
|
|
64
64
|
end
|
@@ -4,6 +4,34 @@ require 'spec_helper'
|
|
4
4
|
|
5
5
|
describe "Regression" do
|
6
6
|
|
7
|
+
it 'does not get confused' do
|
8
|
+
index = Picky::Index.new :dynamic_weights do
|
9
|
+
category :text1
|
10
|
+
category :text2
|
11
|
+
category :text3
|
12
|
+
category :text4
|
13
|
+
end
|
14
|
+
try = Picky::Search.new index
|
15
|
+
|
16
|
+
try.search('hello hello hello').allocations.size.should == 0
|
17
|
+
|
18
|
+
thing = Struct.new(:id, :text1, :text2, :text3, :text4)
|
19
|
+
index.add thing.new(1, 'hello', 'hello', 'hello', 'world')
|
20
|
+
|
21
|
+
try.search('hello hello hello').allocations.size.should == 27
|
22
|
+
|
23
|
+
index.add thing.new(2, 'hello', 'hello', 'hello', 'world')
|
24
|
+
index.add thing.new(3, 'hello', 'hello', 'hello', 'world')
|
25
|
+
index.add thing.new(4, 'hello', 'hello', 'hello', 'world')
|
26
|
+
index.add thing.new(5, 'hello', 'hello', 'hello', 'world')
|
27
|
+
|
28
|
+
try.search('hello hello hello').allocations.size.should == 27
|
29
|
+
|
30
|
+
index.add thing.new(6, 'world', 'world', 'world', 'hello')
|
31
|
+
|
32
|
+
try.search('hello hello world').allocations.size.should == 64
|
33
|
+
end
|
34
|
+
|
7
35
|
# # This was described by Niko
|
8
36
|
# # and references a case where
|
9
37
|
# # an attribute and the id referenced
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe 'Search#terminate_early' do
|
6
|
+
|
7
|
+
it 'terminates early' do
|
8
|
+
index = Picky::Index.new :terminate_early do
|
9
|
+
category :text1
|
10
|
+
category :text2
|
11
|
+
category :text3
|
12
|
+
category :text4
|
13
|
+
end
|
14
|
+
|
15
|
+
thing = Struct.new :id, :text1, :text2, :text3, :text4
|
16
|
+
index.add thing.new(1, 'hello', 'hello', 'hello', 'hello')
|
17
|
+
index.add thing.new(2, 'hello', 'hello', 'hello', 'hello')
|
18
|
+
index.add thing.new(3, 'hello', 'hello', 'hello', 'hello')
|
19
|
+
index.add thing.new(4, 'hello', 'hello', 'hello', 'hello')
|
20
|
+
index.add thing.new(5, 'hello', 'hello', 'hello', 'hello')
|
21
|
+
index.add thing.new(6, 'hello', 'hello', 'hello', 'hello')
|
22
|
+
|
23
|
+
try = Picky::Search.new index
|
24
|
+
try.search('hello').ids.should == [6, 5, 4, 3, 2, 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, 3, 2, 1, 6, 5]
|
25
|
+
|
26
|
+
try = Picky::Search.new index do
|
27
|
+
terminate_early
|
28
|
+
end
|
29
|
+
try.search('hello', 3).ids.should == [6, 5, 4]
|
30
|
+
|
31
|
+
try = Picky::Search.new index do
|
32
|
+
terminate_early
|
33
|
+
end
|
34
|
+
try.search('hello', 9).ids.should == [6, 5, 4, 3, 2, 1, 6, 5, 4]
|
35
|
+
|
36
|
+
try = Picky::Search.new index do
|
37
|
+
terminate_early with_extra_allocations: 0
|
38
|
+
end
|
39
|
+
try.search('hello', 9).ids.should == [6, 5, 4, 3, 2, 1, 6, 5, 4]
|
40
|
+
|
41
|
+
try = Picky::Search.new index do
|
42
|
+
terminate_early 0
|
43
|
+
end
|
44
|
+
try.search('hello').ids.should == [6, 5, 4, 3, 2, 1, 6, 5, 4, 3, 2, 1]
|
45
|
+
|
46
|
+
try = Picky::Search.new index do
|
47
|
+
terminate_early with_extra_allocations: 0
|
48
|
+
end
|
49
|
+
try.search('hello').ids.should == [6, 5, 4, 3, 2, 1, 6, 5, 4, 3, 2, 1]
|
50
|
+
|
51
|
+
try = Picky::Search.new index do
|
52
|
+
terminate_early 2
|
53
|
+
end
|
54
|
+
try.search('hello', 13).ids.should == [6, 5, 4, 3, 2, 1, 6, 5, 4, 3, 2, 1, 6]
|
55
|
+
|
56
|
+
try = Picky::Search.new index do
|
57
|
+
terminate_early with_extra_allocations: 2
|
58
|
+
end
|
59
|
+
try.search('hello').ids.should == [6, 5, 4, 3, 2, 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, 3, 2, 1, 6, 5]
|
60
|
+
|
61
|
+
try = Picky::Search.new index do
|
62
|
+
terminate_early with_extra_allocations: 1234
|
63
|
+
end
|
64
|
+
try.search('hello').ids.should == [6, 5, 4, 3, 2, 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, 3, 2, 1, 6, 5]
|
65
|
+
|
66
|
+
slow = performance_of do
|
67
|
+
try.search 'hello'
|
68
|
+
end
|
69
|
+
|
70
|
+
try = Picky::Search.new index do
|
71
|
+
terminate_early
|
72
|
+
end
|
73
|
+
fast = performance_of do
|
74
|
+
try.search 'hello'
|
75
|
+
end
|
76
|
+
|
77
|
+
(slow/fast).should
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
@@ -86,6 +86,34 @@ describe Picky::Query::Allocations do
|
|
86
86
|
@allocation3 = stub :allocation3, :process! => [], :count => 2 #, ids: [8, 9]
|
87
87
|
@allocations = described_class.new [@allocation1, @allocation2, @allocation3]
|
88
88
|
end
|
89
|
+
describe 'lazy evaluation' do
|
90
|
+
context 'small amount' do
|
91
|
+
before(:each) do
|
92
|
+
@amount = 3
|
93
|
+
@offset = 1
|
94
|
+
end
|
95
|
+
it 'should call the process! method right' do
|
96
|
+
@allocation1.should_receive(:process!).once.with(3,1).and_return [1, 2, 3]
|
97
|
+
@allocation2.should_receive(:process!).once.with(0,0).and_return [] # TODO Actually ok?
|
98
|
+
@allocation3.should_receive(:process!).never
|
99
|
+
|
100
|
+
@allocations.process! @amount, @offset, 0
|
101
|
+
end
|
102
|
+
end
|
103
|
+
context 'larger amount' do
|
104
|
+
before(:each) do
|
105
|
+
@amount = 1
|
106
|
+
@offset = 0
|
107
|
+
end
|
108
|
+
it 'should call the process! method right' do
|
109
|
+
@allocation1.should_receive(:process!).once.with(1,0).and_return [1]
|
110
|
+
@allocation2.should_receive(:process!).once.with(0,0).and_return [] # TODO Actually ok?
|
111
|
+
@allocation3.should_receive(:process!).never
|
112
|
+
|
113
|
+
@allocations.process! @amount, @offset, 0
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
89
117
|
describe 'amount spanning 3 allocations' do
|
90
118
|
before(:each) do
|
91
119
|
@amount = 6
|
@@ -27,6 +27,18 @@ describe Picky::Query::Combination do
|
|
27
27
|
it 'should hash the token and the bundle' do
|
28
28
|
@combination.hash.should == [@token, @category].hash
|
29
29
|
end
|
30
|
+
it 'should distinguish two combinations sufficiently' do
|
31
|
+
category1 = stub :category,
|
32
|
+
:identifier => 'some_category_identifier1'
|
33
|
+
|
34
|
+
category2 = stub :category,
|
35
|
+
:identifier => 'some_category_identifier2'
|
36
|
+
|
37
|
+
combination1 = described_class.new @token, category1
|
38
|
+
combination2 = described_class.new @token, category2
|
39
|
+
|
40
|
+
combination1.hash.should_not == combination2.hash
|
41
|
+
end
|
30
42
|
end
|
31
43
|
|
32
44
|
describe 'to_result' do
|
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: 3.6.
|
4
|
+
version: 3.6.12
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-
|
12
|
+
date: 2011-12-01 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
16
|
-
requirement: &
|
16
|
+
requirement: &70344058312240 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,21 +21,21 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70344058312240
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: picky-client
|
27
|
-
requirement: &
|
27
|
+
requirement: &70344058311560 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ~>
|
31
31
|
- !ruby/object:Gem::Version
|
32
|
-
version: 3.6.
|
32
|
+
version: 3.6.12
|
33
33
|
type: :development
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70344058311560
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: rack
|
38
|
-
requirement: &
|
38
|
+
requirement: &70344058310640 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: '0'
|
44
44
|
type: :runtime
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *70344058310640
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: rack_fast_escape
|
49
|
-
requirement: &
|
49
|
+
requirement: &70344058309960 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ! '>='
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: '0'
|
55
55
|
type: :runtime
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *70344058309960
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: text
|
60
|
-
requirement: &
|
60
|
+
requirement: &70344058309020 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ! '>='
|
@@ -65,10 +65,10 @@ dependencies:
|
|
65
65
|
version: '0'
|
66
66
|
type: :runtime
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *70344058309020
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: yajl-ruby
|
71
|
-
requirement: &
|
71
|
+
requirement: &70344058308480 !ruby/object:Gem::Requirement
|
72
72
|
none: false
|
73
73
|
requirements:
|
74
74
|
- - ! '>='
|
@@ -76,10 +76,10 @@ dependencies:
|
|
76
76
|
version: '0'
|
77
77
|
type: :runtime
|
78
78
|
prerelease: false
|
79
|
-
version_requirements: *
|
79
|
+
version_requirements: *70344058308480
|
80
80
|
- !ruby/object:Gem::Dependency
|
81
81
|
name: activesupport
|
82
|
-
requirement: &
|
82
|
+
requirement: &70344058307980 !ruby/object:Gem::Requirement
|
83
83
|
none: false
|
84
84
|
requirements:
|
85
85
|
- - ~>
|
@@ -87,10 +87,10 @@ dependencies:
|
|
87
87
|
version: '3.0'
|
88
88
|
type: :runtime
|
89
89
|
prerelease: false
|
90
|
-
version_requirements: *
|
90
|
+
version_requirements: *70344058307980
|
91
91
|
- !ruby/object:Gem::Dependency
|
92
92
|
name: unicorn
|
93
|
-
requirement: &
|
93
|
+
requirement: &70344058323920 !ruby/object:Gem::Requirement
|
94
94
|
none: false
|
95
95
|
requirements:
|
96
96
|
- - ! '>='
|
@@ -98,10 +98,10 @@ dependencies:
|
|
98
98
|
version: '0'
|
99
99
|
type: :runtime
|
100
100
|
prerelease: false
|
101
|
-
version_requirements: *
|
101
|
+
version_requirements: *70344058323920
|
102
102
|
- !ruby/object:Gem::Dependency
|
103
103
|
name: sinatra
|
104
|
-
requirement: &
|
104
|
+
requirement: &70344058323380 !ruby/object:Gem::Requirement
|
105
105
|
none: false
|
106
106
|
requirements:
|
107
107
|
- - ! '>='
|
@@ -109,7 +109,7 @@ dependencies:
|
|
109
109
|
version: '0'
|
110
110
|
type: :runtime
|
111
111
|
prerelease: false
|
112
|
-
version_requirements: *
|
112
|
+
version_requirements: *70344058323380
|
113
113
|
description: Fast Ruby semantic text search engine with comfortable single field interface.
|
114
114
|
email: florian.hanke+picky@gmail.com
|
115
115
|
executables:
|
@@ -276,6 +276,7 @@ files:
|
|
276
276
|
- spec/functional/realtime_spec.rb
|
277
277
|
- spec/functional/regression_spec.rb
|
278
278
|
- spec/functional/speed_spec.rb
|
279
|
+
- spec/functional/terminate_early_spec.rb
|
279
280
|
- spec/lib/adapters/rack/base_spec.rb
|
280
281
|
- spec/lib/adapters/rack/live_parameters_spec.rb
|
281
282
|
- spec/lib/adapters/rack/query_spec.rb
|
@@ -419,6 +420,7 @@ test_files:
|
|
419
420
|
- spec/functional/realtime_spec.rb
|
420
421
|
- spec/functional/regression_spec.rb
|
421
422
|
- spec/functional/speed_spec.rb
|
423
|
+
- spec/functional/terminate_early_spec.rb
|
422
424
|
- spec/lib/adapters/rack/base_spec.rb
|
423
425
|
- spec/lib/adapters/rack/live_parameters_spec.rb
|
424
426
|
- spec/lib/adapters/rack/query_spec.rb
|