picky 4.5.11 → 4.5.12

Sign up to get free protection for your applications and to get access to all the features.
@@ -3,14 +3,27 @@ module Picky
3
3
  class Index
4
4
 
5
5
  # Return facets for a category in the form:
6
- # { text => weight } # or ids.size?
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
- weights = self[category_identifier].exact.weights
10
- if minimal_weight = options[:more_than]
11
- weights.select { |_, weight| weight > minimal_weight }
12
- else
13
- weights
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
 
@@ -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
- # more_than: A minimum weight a facet needs to have (exclusive).
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 weights.
22
+ # Get index-specific facet counts.
22
23
  #
23
- weights = index.facets category_identifier, options
24
+ counts = index.facets category_identifier, options
24
25
 
25
26
  # We're done if there is no filter.
26
27
  #
27
- return weights unless filter_query = options[:filter]
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
- # Filter out impossible facets.
34
+ # Extract options.
34
35
  #
35
- weights.select do |key, weight|
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 > 0
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 weights for surname.
27
+ # Picky has 2 facets with different counts for surname.
28
28
  #
29
29
  index.facets(:surname).should == {
30
- 'hanke' => 0.693,
31
- 'schiess' => 0
30
+ 'hanke' => 2,
31
+ 'schiess' => 1
32
32
  }
33
33
 
34
- # It has 3 facets with the same weight for name.
34
+ # It has 3 facets with the same count for name.
35
35
  #
36
36
  index.facets(:name).should == {
37
- 'fritz' => 0,
38
- 'kaspar' => 0,
39
- 'florian' => 0
37
+ 'fritz' => 1,
38
+ 'kaspar' => 1,
39
+ 'florian' => 1
40
40
  }
41
41
 
42
- # Picky only selects facets with a weight >= the given one.
42
+ # Picky only selects facets with a count >= the given one.
43
43
  #
44
- index.facets(:surname, more_than: 0.5).should == {
45
- 'hanke' => 0.693
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' => 0.693,
56
- 'schiess' => 0.0
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' => 0,
65
- 'florian' => 0
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 'is correct' do
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' => 0.693,
97
- 'kunz' => 0.0,
98
- 'meier' => 1.099
94
+ 'hanke' => 2,
95
+ 'kunz' => 1,
96
+ 'meier' => 3
99
97
  }
100
-
101
- # It has 3 facets with the same weight for name.
102
- #
98
+ end
99
+ it 'has 4 facets for the name' do
103
100
  index.facets(:name).should == {
104
- 'annabelle' => 0.0,
105
- 'hans' => 0.0,
106
- 'peter' => 1.099,
107
- 'ursula' => 0.0
101
+ 'annabelle' => 1,
102
+ 'hans' => 1,
103
+ 'peter' => 3,
104
+ 'ursula' => 1
108
105
  }
109
-
110
- # It has 1 facet with weight > 0.
111
- #
112
- index.facets(:name, more_than: 0).should == {
113
- 'peter' => 1.099
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 'filters them correctly' do
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' => 0
132
+ '45' => 1
131
133
  }
132
-
133
- # It has two facets.
134
- #
134
+ end
135
+ it 'has two filtered facets' do
135
136
  finder.facets(:surname, filter: 'age_category:40 name:peter').should == {
136
- 'kunz' => 0.0,
137
- 'hanke' => 0.693
137
+ 'kunz' => 1,
138
+ 'hanke' => 1 # Not 2 since it is filtered.
138
139
  }
139
-
140
- # It has 1 facet > weight 0.
141
- #
142
- finder.facets(:surname, filter: 'age_category:40 name:peter', more_than: 0).should == {
143
- 'hanke' => 0.693
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.11
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: &70359044149180 !ruby/object:Gem::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: *70359044149180
24
+ version_requirements: *70303139130820
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: picky-client
27
- requirement: &70359044148680 !ruby/object:Gem::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.11
32
+ version: 4.5.12
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *70359044148680
35
+ version_requirements: *70303139130320
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: text
38
- requirement: &70359044148260 !ruby/object:Gem::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: *70359044148260
46
+ version_requirements: *70303139129900
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: multi_json
49
- requirement: &70359044147800 !ruby/object:Gem::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: *70359044147800
57
+ version_requirements: *70303139129440
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: activesupport
60
- requirement: &70359044147300 !ruby/object:Gem::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: *70359044147300
68
+ version_requirements: *70303139128940
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: procrastinate
71
- requirement: &70359044146800 !ruby/object:Gem::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: *70359044146800
79
+ version_requirements: *70303139128440
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: rack_fast_escape
82
- requirement: &70359044146420 !ruby/object:Gem::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: *70359044146420
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: