picky 4.5.11 → 4.5.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/index_facets.rb +19 -6
- data/lib/picky/search_facets.rb +24 -8
- data/spec/functional/facets_spec.rb +83 -50
- metadata +16 -16
data/lib/picky/index_facets.rb
CHANGED
@@ -3,14 +3,27 @@ module Picky
|
|
3
3
|
class Index
|
4
4
|
|
5
5
|
# Return facets for a category in the form:
|
6
|
-
# { text =>
|
6
|
+
# { text => count }
|
7
|
+
#
|
8
|
+
# Options
|
9
|
+
# counts: Whether you want counts or not.
|
10
|
+
# at_least: A minimum count a facet needs to have (inclusive).
|
11
|
+
#
|
12
|
+
# TODO Think about having a separate index for counts to reduce the complexity of this.
|
7
13
|
#
|
8
14
|
def facets category_identifier, options = {}
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
15
|
+
text_ids = self[category_identifier].exact.inverted
|
16
|
+
no_counts = options[:counts] == false
|
17
|
+
minimal_counts = options[:at_least]
|
18
|
+
text_ids.inject(no_counts ? [] : {}) do |result, text_ids|
|
19
|
+
text, ids = text_ids
|
20
|
+
size = ids.size
|
21
|
+
next result if minimal_counts && size < minimal_counts
|
22
|
+
if no_counts
|
23
|
+
result << text
|
24
|
+
else
|
25
|
+
result[text] = size; result
|
26
|
+
end
|
14
27
|
end
|
15
28
|
end
|
16
29
|
|
data/lib/picky/search_facets.rb
CHANGED
@@ -2,13 +2,14 @@ module Picky
|
|
2
2
|
|
3
3
|
class Search
|
4
4
|
|
5
|
-
# Returns a list of filtered facets.
|
5
|
+
# Returns a list/hash of filtered facets.
|
6
6
|
#
|
7
7
|
# Params
|
8
8
|
# category: The category whose facets to return.
|
9
9
|
#
|
10
10
|
# Options
|
11
|
-
#
|
11
|
+
# counts: Whether you want counts (returns a Hash) or not (returns an Array).
|
12
|
+
# at_least: A minimum count a facet needs to have (inclusive).
|
12
13
|
# filter: A query to filter the facets with.
|
13
14
|
#
|
14
15
|
# Usage:
|
@@ -18,23 +19,38 @@ module Picky
|
|
18
19
|
raise "#{__method__} cannot be used on searches with more than 1 index yet. Sorry!" if indexes.size > 1
|
19
20
|
index = indexes.first
|
20
21
|
|
21
|
-
# Get index-specific facet
|
22
|
+
# Get index-specific facet counts.
|
22
23
|
#
|
23
|
-
|
24
|
+
counts = index.facets category_identifier, options
|
24
25
|
|
25
26
|
# We're done if there is no filter.
|
26
27
|
#
|
27
|
-
return
|
28
|
+
return counts unless filter_query = options[:filter]
|
28
29
|
|
29
30
|
# Pre-tokenize filter for reuse.
|
30
31
|
#
|
31
32
|
tokenized_filter = tokenized filter_query, false
|
32
33
|
|
33
|
-
#
|
34
|
+
# Extract options.
|
34
35
|
#
|
35
|
-
|
36
|
+
no_counts = options[:counts] == false
|
37
|
+
minimal_counts = options[:at_least] || 1 # Default needs at least one.
|
38
|
+
|
39
|
+
# Get actual counts.
|
40
|
+
#
|
41
|
+
# TODO Rewrite.
|
42
|
+
#
|
43
|
+
counts.inject(no_counts ? [] : {}) do |result, key_count|
|
44
|
+
key, _ = key_count
|
36
45
|
tokenized_query = tokenized "#{category_identifier}:#{key}", false
|
37
|
-
search_with(tokenized_filter + tokenized_query, 0, 0).total
|
46
|
+
total = search_with(tokenized_filter + tokenized_query, 0, 0).total
|
47
|
+
next result unless total >= minimal_counts
|
48
|
+
if no_counts
|
49
|
+
result << key
|
50
|
+
else
|
51
|
+
result[key] = total; result
|
52
|
+
end
|
53
|
+
result
|
38
54
|
end
|
39
55
|
end
|
40
56
|
|
@@ -22,38 +22,38 @@ describe 'facets' do
|
|
22
22
|
}
|
23
23
|
let(:finder) { Picky::Search.new index }
|
24
24
|
|
25
|
-
describe 'facets' do
|
25
|
+
describe 'Index#facets' do
|
26
26
|
it 'is correct' do
|
27
|
-
# Picky has 2 facets with different
|
27
|
+
# Picky has 2 facets with different counts for surname.
|
28
28
|
#
|
29
29
|
index.facets(:surname).should == {
|
30
|
-
'hanke' =>
|
31
|
-
'schiess' =>
|
30
|
+
'hanke' => 2,
|
31
|
+
'schiess' => 1
|
32
32
|
}
|
33
33
|
|
34
|
-
# It has 3 facets with the same
|
34
|
+
# It has 3 facets with the same count for name.
|
35
35
|
#
|
36
36
|
index.facets(:name).should == {
|
37
|
-
'fritz' =>
|
38
|
-
'kaspar' =>
|
39
|
-
'florian' =>
|
37
|
+
'fritz' => 1,
|
38
|
+
'kaspar' => 1,
|
39
|
+
'florian' => 1
|
40
40
|
}
|
41
41
|
|
42
|
-
# Picky only selects facets with a
|
42
|
+
# Picky only selects facets with a count >= the given one.
|
43
43
|
#
|
44
|
-
index.facets(:surname,
|
45
|
-
'hanke' =>
|
44
|
+
index.facets(:surname, at_least: 2).should == {
|
45
|
+
'hanke' => 2
|
46
46
|
}
|
47
47
|
end
|
48
48
|
end
|
49
49
|
|
50
|
-
describe 'facets' do
|
50
|
+
describe 'Search#facets' do
|
51
51
|
it 'filters them correctly' do
|
52
52
|
# Passing in no filter query just returns the facets
|
53
53
|
#
|
54
54
|
finder.facets(:surname).should == {
|
55
|
-
'hanke' =>
|
56
|
-
'schiess' =>
|
55
|
+
'hanke' => 2,
|
56
|
+
'schiess' => 1
|
57
57
|
}
|
58
58
|
|
59
59
|
# It has two facets.
|
@@ -61,8 +61,8 @@ describe 'facets' do
|
|
61
61
|
# TODO Rewrite API.
|
62
62
|
#
|
63
63
|
finder.facets(:name, filter: 'surname:hanke').should == {
|
64
|
-
'fritz' =>
|
65
|
-
'florian' =>
|
64
|
+
'fritz' => 1,
|
65
|
+
'florian' => 1
|
66
66
|
}
|
67
67
|
end
|
68
68
|
end
|
@@ -88,61 +88,94 @@ describe 'facets' do
|
|
88
88
|
}
|
89
89
|
let(:finder) { Picky::Search.new index }
|
90
90
|
|
91
|
-
describe 'facets' do
|
92
|
-
it '
|
93
|
-
# Picky has 2 facets with different weights for surname.
|
94
|
-
#
|
91
|
+
describe 'Index#facets' do
|
92
|
+
it 'has 2 facets with different counts for surname' do
|
95
93
|
index.facets(:surname).should == {
|
96
|
-
'hanke' =>
|
97
|
-
'kunz' =>
|
98
|
-
'meier' =>
|
94
|
+
'hanke' => 2,
|
95
|
+
'kunz' => 1,
|
96
|
+
'meier' => 3
|
99
97
|
}
|
100
|
-
|
101
|
-
|
102
|
-
#
|
98
|
+
end
|
99
|
+
it 'has 4 facets for the name' do
|
103
100
|
index.facets(:name).should == {
|
104
|
-
'annabelle' =>
|
105
|
-
'hans' =>
|
106
|
-
'peter' =>
|
107
|
-
'ursula' =>
|
101
|
+
'annabelle' => 1,
|
102
|
+
'hans' => 1,
|
103
|
+
'peter' => 3,
|
104
|
+
'ursula' => 1
|
108
105
|
}
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
'
|
106
|
+
end
|
107
|
+
it 'has 3 facets with the same count for name' do
|
108
|
+
index.facets(:name).should == {
|
109
|
+
'annabelle' => 1,
|
110
|
+
'hans' => 1,
|
111
|
+
'peter' => 3,
|
112
|
+
'ursula' => 1
|
113
|
+
}
|
114
|
+
end
|
115
|
+
it 'has 1 facet with count >= 2' do
|
116
|
+
index.facets(:name, at_least: 2).should == {
|
117
|
+
'peter' => 3
|
114
118
|
}
|
115
119
|
end
|
116
120
|
end
|
117
121
|
|
118
|
-
describe 'facets' do
|
122
|
+
describe 'Search#facets' do
|
119
123
|
it 'is fast enough' do
|
120
124
|
performance_of {
|
121
125
|
10.times { finder.facets(:age_category, filter: 'surname:meier name:peter') }
|
122
126
|
}.should < 0.00275
|
123
127
|
end
|
124
|
-
it '
|
125
|
-
# It has one facet.
|
126
|
-
#
|
128
|
+
it 'has one filtered facet' do
|
127
129
|
# TODO Fix problems with alternative qualifiers (like :age).
|
128
130
|
#
|
129
131
|
finder.facets(:age_category, filter: 'surname:meier name:peter').should == {
|
130
|
-
'45' =>
|
132
|
+
'45' => 1
|
131
133
|
}
|
132
|
-
|
133
|
-
|
134
|
-
#
|
134
|
+
end
|
135
|
+
it 'has two filtered facets' do
|
135
136
|
finder.facets(:surname, filter: 'age_category:40 name:peter').should == {
|
136
|
-
'kunz' =>
|
137
|
-
'hanke' =>
|
137
|
+
'kunz' => 1,
|
138
|
+
'hanke' => 1 # Not 2 since it is filtered.
|
138
139
|
}
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
'hanke' =>
|
140
|
+
end
|
141
|
+
it 'has 2 facets >= count 0' do
|
142
|
+
finder.facets(:surname, filter: 'age_category:40 name:peter', at_least: 1).should == {
|
143
|
+
'kunz' => 1,
|
144
|
+
'hanke' => 1
|
144
145
|
}
|
145
146
|
end
|
147
|
+
it 'has 0 facets >= counts 2' do
|
148
|
+
finder.facets(:surname, filter: 'age_category:40 name:peter', at_least: 2).should == {}
|
149
|
+
end
|
146
150
|
end
|
151
|
+
|
152
|
+
describe 'Search#facets without counts' do
|
153
|
+
it 'is fast enough' do
|
154
|
+
performance_of {
|
155
|
+
10.times { finder.facets(:age_category, filter: 'surname:meier name:peter', counts: false) }
|
156
|
+
}.should < 0.00275
|
157
|
+
end
|
158
|
+
it 'has one filtered facet' do
|
159
|
+
# TODO Fix problems with alternative qualifiers (like :age).
|
160
|
+
#
|
161
|
+
finder.facets(:age_category, filter: 'surname:meier name:peter', counts: false).should == ['45']
|
162
|
+
end
|
163
|
+
it 'has two filtered facets' do
|
164
|
+
finder.facets(:surname, filter: 'age_category:40 name:peter', counts: false).should == [
|
165
|
+
'kunz',
|
166
|
+
'hanke'
|
167
|
+
]
|
168
|
+
end
|
169
|
+
it 'has 2 facets >= count 0' do
|
170
|
+
finder.facets(:surname, filter: 'age_category:40 name:peter', at_least: 1, counts: false).should == [
|
171
|
+
'kunz',
|
172
|
+
'hanke'
|
173
|
+
]
|
174
|
+
end
|
175
|
+
it 'has 0 facets >= counts 2' do
|
176
|
+
finder.facets(:surname, filter: 'age_category:40 name:peter', at_least: 2, counts: false).should == []
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
147
180
|
end
|
148
181
|
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.5.
|
4
|
+
version: 4.5.12
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -13,7 +13,7 @@ date: 2012-07-24 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
16
|
-
requirement: &
|
16
|
+
requirement: &70303139130820 !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: *70303139130820
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: picky-client
|
27
|
-
requirement: &
|
27
|
+
requirement: &70303139130320 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ~>
|
31
31
|
- !ruby/object:Gem::Version
|
32
|
-
version: 4.5.
|
32
|
+
version: 4.5.12
|
33
33
|
type: :development
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70303139130320
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: text
|
38
|
-
requirement: &
|
38
|
+
requirement: &70303139129900 !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: *70303139129900
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: multi_json
|
49
|
-
requirement: &
|
49
|
+
requirement: &70303139129440 !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: *70303139129440
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: activesupport
|
60
|
-
requirement: &
|
60
|
+
requirement: &70303139128940 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ~>
|
@@ -65,10 +65,10 @@ dependencies:
|
|
65
65
|
version: '3.0'
|
66
66
|
type: :runtime
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *70303139128940
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: procrastinate
|
71
|
-
requirement: &
|
71
|
+
requirement: &70303139128440 !ruby/object:Gem::Requirement
|
72
72
|
none: false
|
73
73
|
requirements:
|
74
74
|
- - ~>
|
@@ -76,10 +76,10 @@ dependencies:
|
|
76
76
|
version: '0.4'
|
77
77
|
type: :runtime
|
78
78
|
prerelease: false
|
79
|
-
version_requirements: *
|
79
|
+
version_requirements: *70303139128440
|
80
80
|
- !ruby/object:Gem::Dependency
|
81
81
|
name: rack_fast_escape
|
82
|
-
requirement: &
|
82
|
+
requirement: &70303139128060 !ruby/object:Gem::Requirement
|
83
83
|
none: false
|
84
84
|
requirements:
|
85
85
|
- - ! '>='
|
@@ -87,7 +87,7 @@ dependencies:
|
|
87
87
|
version: '0'
|
88
88
|
type: :runtime
|
89
89
|
prerelease: false
|
90
|
-
version_requirements: *
|
90
|
+
version_requirements: *70303139128060
|
91
91
|
description: Fast Ruby semantic text search engine with comfortable single field interface.
|
92
92
|
email: florian.hanke+picky@gmail.com
|
93
93
|
executables:
|