picky 4.5.7 → 4.5.8
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/maybe_compile.rb +3 -0
- data/lib/picky/generators/weights/logarithmic.rb +36 -23
- data/lib/picky/index.rb +1 -0
- data/lib/picky/index_facets.rb +19 -0
- data/lib/picky/loader.rb +2 -0
- data/lib/picky/query/indexes.rb +7 -1
- data/lib/picky/query/token.rb +5 -3
- data/lib/picky/search_facets.rb +29 -0
- data/spec/functional/facets_spec.rb +143 -0
- metadata +21 -17
data/lib/maybe_compile.rb
CHANGED
@@ -15,30 +15,43 @@ module Picky
|
|
15
15
|
class Logarithmic < Strategy
|
16
16
|
|
17
17
|
def initialize constant = 0.0
|
18
|
-
|
19
|
-
#
|
20
|
-
#
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
# Sets the weight value.
|
29
|
-
#
|
30
|
-
# If the size is 0 or one, we would get -Infinity or 0.0.
|
31
|
-
# Thus we do not set a value if there is just one. The default, dynamically, is 0.
|
32
|
-
#
|
33
|
-
# BUT: We need the value, even if 0. To designate that there IS a weight!
|
34
|
-
#
|
35
|
-
def weight_for amount
|
36
|
-
return @constant if amount < 1
|
37
|
-
@constant + Math.log(amount).round(3)
|
38
|
-
end
|
39
|
-
end
|
18
|
+
@constant = constant
|
19
|
+
# # Note: Optimisation since it is called
|
20
|
+
# # once per indexed object.
|
21
|
+
# #
|
22
|
+
# if constant == 0.0
|
23
|
+
# install_without_constant
|
24
|
+
# else
|
25
|
+
# @constant = constant
|
26
|
+
# install_with_constant
|
27
|
+
# end
|
40
28
|
end
|
41
|
-
|
29
|
+
|
30
|
+
def weight_for amount
|
31
|
+
return @constant if amount < 1
|
32
|
+
@constant + Math.log(amount).round(3)
|
33
|
+
end
|
34
|
+
|
35
|
+
# def install_with_constant
|
36
|
+
# # Sets the weight value.
|
37
|
+
# #
|
38
|
+
# # If the size is 0 or one, we would get -Infinity or 0.0.
|
39
|
+
# # Thus we do not set a value if there is just one. The default, dynamically, is 0.
|
40
|
+
# #
|
41
|
+
# # BUT: We need the value, even if 0. To designate that there IS a weight!
|
42
|
+
# #
|
43
|
+
# def weight_for amount
|
44
|
+
# return @constant if amount < 1
|
45
|
+
# @constant + Math.log(amount).round(3)
|
46
|
+
# end
|
47
|
+
# end
|
48
|
+
# def install_without_constant
|
49
|
+
# def weight_for amount
|
50
|
+
# return 0 if amount < 1
|
51
|
+
# Math.log(amount).round 3
|
52
|
+
# end
|
53
|
+
# end
|
54
|
+
|
42
55
|
end
|
43
56
|
|
44
57
|
end
|
data/lib/picky/index.rb
CHANGED
@@ -162,6 +162,7 @@ module Picky
|
|
162
162
|
# * category_name: This identifier is used in the front end, but also to categorize query text. For example, “title:hobbit” will narrow the hobbit query on categories with the identifier :title.
|
163
163
|
#
|
164
164
|
# === Options
|
165
|
+
# * indexing: Pass in either a tokenizer or tokenizer options.
|
165
166
|
# * partial: Partial::None.new or Partial::Substring.new(from: starting_char, to: ending_char). Default is Partial::Substring.new(from: -3, to: -1).
|
166
167
|
# * similarity: Similarity::None.new or Similarity::DoubleMetaphone.new(similar_words_searched). Default is Similarity::None.new.
|
167
168
|
# * qualifiers: An array of qualifiers with which you can define which category you’d like to search, for example “title:hobbit” will search for hobbit in just title categories. Example: qualifiers: [:t, :titre, :title] (use it for example with multiple languages). Default is the name of the category.
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Picky
|
2
|
+
|
3
|
+
class Index
|
4
|
+
|
5
|
+
# Return facets for a category in the form:
|
6
|
+
# { text => weight } # or ids.size?
|
7
|
+
#
|
8
|
+
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
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
data/lib/picky/loader.rb
CHANGED
@@ -243,6 +243,7 @@ module Picky
|
|
243
243
|
load_relative 'index_indexed'
|
244
244
|
load_relative 'index_indexing'
|
245
245
|
load_relative 'index_realtime'
|
246
|
+
load_relative 'index_facets'
|
246
247
|
load_relative 'index_convenience'
|
247
248
|
|
248
249
|
# Results.
|
@@ -253,6 +254,7 @@ module Picky
|
|
253
254
|
# Search.
|
254
255
|
#
|
255
256
|
load_relative 'search'
|
257
|
+
load_relative 'search_facets'
|
256
258
|
|
257
259
|
# Interfaces
|
258
260
|
#
|
data/lib/picky/query/indexes.rb
CHANGED
data/lib/picky/query/token.rb
CHANGED
@@ -25,10 +25,10 @@ module Picky
|
|
25
25
|
# Note:
|
26
26
|
# Use this if you do not want a normalized token.
|
27
27
|
#
|
28
|
-
def initialize text, original = nil,
|
28
|
+
def initialize text, original = nil, categories = nil
|
29
29
|
@text = text
|
30
30
|
@original = original
|
31
|
-
@user_defined_categories =
|
31
|
+
@user_defined_categories = categories
|
32
32
|
end
|
33
33
|
|
34
34
|
# Returns a qualified and normalized token.
|
@@ -214,7 +214,9 @@ module Picky
|
|
214
214
|
def similar_tokens_for category
|
215
215
|
similars = category.bundle_for(self).similar @text
|
216
216
|
similars.map do |similar|
|
217
|
-
|
217
|
+
# The array describes all possible categories. There is only one here.
|
218
|
+
#
|
219
|
+
self.class.new similar, similar, [category]
|
218
220
|
end
|
219
221
|
end
|
220
222
|
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Picky
|
2
|
+
|
3
|
+
class Search
|
4
|
+
|
5
|
+
# Returns a list of filtered facets.
|
6
|
+
#
|
7
|
+
# Params
|
8
|
+
# category: The category whose facets to return.
|
9
|
+
#
|
10
|
+
# Options
|
11
|
+
# more_than: A minimum weight a facet needs to have (exclusive).
|
12
|
+
# filter: A query to filter the facets with.
|
13
|
+
#
|
14
|
+
# Usage:
|
15
|
+
# search.facets :name, filter: 'surname:peter', more_than: 0
|
16
|
+
#
|
17
|
+
def facets category_identifier, options = {}
|
18
|
+
raise "#{__method__} cannot be used on searches with more than 1 index yet. Sorry!" if indexes.size > 1
|
19
|
+
index = indexes.first
|
20
|
+
weights = index.facets category_identifier, options
|
21
|
+
return weights unless filter_query = options[:filter]
|
22
|
+
weights.select do |key, weight|
|
23
|
+
search("#{filter_query} #{category_identifier}:#{key}", 0, 0).total > 0
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
@@ -0,0 +1,143 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
# This spec describes
|
6
|
+
#
|
7
|
+
describe 'facets' do
|
8
|
+
|
9
|
+
describe 'simple example' do
|
10
|
+
let(:index) {
|
11
|
+
index = Picky::Index.new :facets do
|
12
|
+
category :name
|
13
|
+
category :surname
|
14
|
+
end
|
15
|
+
|
16
|
+
thing = Struct.new :id, :name, :surname
|
17
|
+
index.add thing.new(1, 'fritz', 'hanke')
|
18
|
+
index.add thing.new(2, 'kaspar', 'schiess')
|
19
|
+
index.add thing.new(3, 'florian', 'hanke')
|
20
|
+
|
21
|
+
index
|
22
|
+
}
|
23
|
+
let(:finder) { Picky::Search.new index }
|
24
|
+
|
25
|
+
describe 'facets' do
|
26
|
+
it 'is correct' do
|
27
|
+
# Picky has 2 facets with different weights for surname.
|
28
|
+
#
|
29
|
+
index.facets(:surname).should == {
|
30
|
+
'hanke' => 0.693,
|
31
|
+
'schiess' => 0
|
32
|
+
}
|
33
|
+
|
34
|
+
# It has 3 facets with the same weight for name.
|
35
|
+
#
|
36
|
+
index.facets(:name).should == {
|
37
|
+
'fritz' => 0,
|
38
|
+
'kaspar' => 0,
|
39
|
+
'florian' => 0
|
40
|
+
}
|
41
|
+
|
42
|
+
# Picky only selects facets with a weight >= the given one.
|
43
|
+
#
|
44
|
+
index.facets(:surname, more_than: 0.5).should == {
|
45
|
+
'hanke' => 0.693
|
46
|
+
}
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe 'facets' do
|
51
|
+
it 'filters them correctly' do
|
52
|
+
# Passing in no filter query just returns the facets
|
53
|
+
#
|
54
|
+
finder.facets(:surname).should == {
|
55
|
+
'hanke' => 0.693,
|
56
|
+
'schiess' => 0.0
|
57
|
+
}
|
58
|
+
|
59
|
+
# It has two facets.
|
60
|
+
#
|
61
|
+
# TODO Rewrite API.
|
62
|
+
#
|
63
|
+
finder.facets(:name, filter: 'surname:hanke').should == {
|
64
|
+
'fritz' => 0,
|
65
|
+
'florian' => 0
|
66
|
+
}
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe 'complex example' do
|
72
|
+
let(:index) {
|
73
|
+
index = Picky::Index.new :facets do
|
74
|
+
category :name
|
75
|
+
category :surname
|
76
|
+
category :age_category
|
77
|
+
end
|
78
|
+
|
79
|
+
thing = Struct.new :id, :name, :surname, :age_category
|
80
|
+
index.add thing.new(1, 'ursula', 'meier', 40)
|
81
|
+
index.add thing.new(2, 'peter', 'meier', 45)
|
82
|
+
index.add thing.new(3, 'peter', 'kunz', 40)
|
83
|
+
index.add thing.new(4, 'peter', 'hanke', 40)
|
84
|
+
index.add thing.new(5, 'annabelle', 'hanke', 35)
|
85
|
+
index.add thing.new(5, 'hans', 'meier', 35)
|
86
|
+
|
87
|
+
index
|
88
|
+
}
|
89
|
+
let(:finder) { Picky::Search.new index }
|
90
|
+
|
91
|
+
describe 'facets' do
|
92
|
+
it 'is correct' do
|
93
|
+
# Picky has 2 facets with different weights for surname.
|
94
|
+
#
|
95
|
+
index.facets(:surname).should == {
|
96
|
+
'hanke' => 0.693,
|
97
|
+
'kunz' => 0.0,
|
98
|
+
'meier' => 1.099
|
99
|
+
}
|
100
|
+
|
101
|
+
# It has 3 facets with the same weight for name.
|
102
|
+
#
|
103
|
+
index.facets(:name).should == {
|
104
|
+
'annabelle' => 0.0,
|
105
|
+
'hans' => 0.0,
|
106
|
+
'peter' => 1.099,
|
107
|
+
'ursula' => 0.0
|
108
|
+
}
|
109
|
+
|
110
|
+
# It has 1 facet with weight > 0.
|
111
|
+
#
|
112
|
+
index.facets(:name, more_than: 0).should == {
|
113
|
+
'peter' => 1.099
|
114
|
+
}
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
describe 'facets' do
|
119
|
+
it 'filters them correctly' do
|
120
|
+
# It has one facet.
|
121
|
+
#
|
122
|
+
# TODO Fix problems with alternative qualifiers (like :age).
|
123
|
+
#
|
124
|
+
finder.facets(:age_category, filter: 'surname:meier name:peter').should == {
|
125
|
+
'45' => 0
|
126
|
+
}
|
127
|
+
|
128
|
+
# It has two facets.
|
129
|
+
#
|
130
|
+
finder.facets(:surname, filter: 'age_category:40 name:peter').should == {
|
131
|
+
'kunz' => 0.0,
|
132
|
+
'hanke' => 0.693
|
133
|
+
}
|
134
|
+
|
135
|
+
# It has 1 facet > weight 0.
|
136
|
+
#
|
137
|
+
finder.facets(:surname, filter: 'age_category:40 name:peter', more_than: 0).should == {
|
138
|
+
'hanke' => 0.693
|
139
|
+
}
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
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.8
|
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: 2012-07-
|
12
|
+
date: 2012-07-21 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
16
|
-
requirement: &
|
16
|
+
requirement: &70220459152600 !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: *70220459152600
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: picky-client
|
27
|
-
requirement: &
|
27
|
+
requirement: &70220459151560 !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.8
|
33
33
|
type: :development
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70220459151560
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: text
|
38
|
-
requirement: &
|
38
|
+
requirement: &70220450665880 !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: *70220450665880
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: multi_json
|
49
|
-
requirement: &
|
49
|
+
requirement: &70220450662740 !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: *70220450662740
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: activesupport
|
60
|
-
requirement: &
|
60
|
+
requirement: &70220450660780 !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: *70220450660780
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: procrastinate
|
71
|
-
requirement: &
|
71
|
+
requirement: &70220450680620 !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: *70220450680620
|
80
80
|
- !ruby/object:Gem::Dependency
|
81
81
|
name: rack_fast_escape
|
82
|
-
requirement: &
|
82
|
+
requirement: &70220450679340 !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: *70220450679340
|
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:
|
@@ -184,6 +184,7 @@ files:
|
|
184
184
|
- lib/picky/helpers/measuring.rb
|
185
185
|
- lib/picky/index.rb
|
186
186
|
- lib/picky/index_convenience.rb
|
187
|
+
- lib/picky/index_facets.rb
|
187
188
|
- lib/picky/index_indexed.rb
|
188
189
|
- lib/picky/index_indexing.rb
|
189
190
|
- lib/picky/index_realtime.rb
|
@@ -220,6 +221,7 @@ files:
|
|
220
221
|
- lib/picky/results.rb
|
221
222
|
- lib/picky/scheduler.rb
|
222
223
|
- lib/picky/search.rb
|
224
|
+
- lib/picky/search_facets.rb
|
223
225
|
- lib/picky/sinatra/index_actions.rb
|
224
226
|
- lib/picky/sinatra.rb
|
225
227
|
- lib/picky/statistics.rb
|
@@ -256,6 +258,7 @@ files:
|
|
256
258
|
- spec/functional/custom_delimiters_spec.rb
|
257
259
|
- spec/functional/dynamic_weights_spec.rb
|
258
260
|
- spec/functional/exact_first_spec.rb
|
261
|
+
- spec/functional/facets_spec.rb
|
259
262
|
- spec/functional/max_allocations_spec.rb
|
260
263
|
- spec/functional/non_specific_ids_larger_than_20_spec.rb
|
261
264
|
- spec/functional/only_spec.rb
|
@@ -412,6 +415,7 @@ test_files:
|
|
412
415
|
- spec/functional/custom_delimiters_spec.rb
|
413
416
|
- spec/functional/dynamic_weights_spec.rb
|
414
417
|
- spec/functional/exact_first_spec.rb
|
418
|
+
- spec/functional/facets_spec.rb
|
415
419
|
- spec/functional/max_allocations_spec.rb
|
416
420
|
- spec/functional/non_specific_ids_larger_than_20_spec.rb
|
417
421
|
- spec/functional/only_spec.rb
|