picky 1.1.6 → 1.1.7
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/picky/application.rb +1 -1
- data/lib/picky/index_api.rb +56 -25
- data/lib/picky/indexed/index.rb +2 -2
- data/lib/picky/query/allocation.rb +5 -5
- data/lib/picky/query/combinations.rb +3 -3
- data/lib/picky/query/weigher.rb +2 -2
- data/spec/lib/query/allocation_spec.rb +14 -14
- data/spec/lib/query/combinations_spec.rb +3 -3
- metadata +2 -2
data/lib/picky/application.rb
CHANGED
@@ -179,7 +179,7 @@ class Application
|
|
179
179
|
# * source: The source the data comes from. See Sources::Base. # TODO Sources (all).
|
180
180
|
#
|
181
181
|
# Options:
|
182
|
-
# *
|
182
|
+
# * result_identifier: # TODO Rename.
|
183
183
|
#
|
184
184
|
def index name, source, options = {}
|
185
185
|
IndexAPI.new name, source, options
|
data/lib/picky/index_api.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# This class defines the indexing and index API that is exposed to the user
|
2
2
|
# as the #index method inside the Application class.
|
3
3
|
#
|
4
|
-
# It provides a single front for both indexing and index options.
|
4
|
+
# It provides a single front for both indexing and index options. We suggest to always use the index API.
|
5
5
|
#
|
6
6
|
# Note: An Index holds both an *Indexed*::*Index* and an *Indexing*::*Type*.
|
7
7
|
#
|
@@ -11,12 +11,13 @@ class IndexAPI
|
|
11
11
|
|
12
12
|
# Create a new index with a given source.
|
13
13
|
#
|
14
|
-
# Parameters
|
14
|
+
# === Parameters
|
15
15
|
# * name: A name that will be used for the index directory and in the Picky front end.
|
16
16
|
# * source: Where the data comes from, e.g. Sources::CSV.new(...)
|
17
17
|
#
|
18
|
-
# Options
|
19
|
-
# *
|
18
|
+
# === Options
|
19
|
+
# * result_identifier: Use if you'd like a different identifier/name in the results than the name of the index.
|
20
|
+
# * after_indexing: As of this writing only used in the db source. Executes the given after_indexing as SQL after the indexing process.
|
20
21
|
#
|
21
22
|
def initialize name, source, options = {}
|
22
23
|
@name = name
|
@@ -30,10 +31,10 @@ class IndexAPI
|
|
30
31
|
|
31
32
|
# Defines a searchable category on the index.
|
32
33
|
#
|
33
|
-
# Parameters
|
34
|
-
# 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.
|
34
|
+
# === Parameters
|
35
|
+
# * 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.
|
35
36
|
#
|
36
|
-
# Options
|
37
|
+
# === Options
|
37
38
|
# * partial: Partial::None.new or Partial::Substring.new(from: starting_char, to: ending_char). Default is Partial::Substring.new(from: -3, to: -1).
|
38
39
|
# * similarity: Similarity::None.new or Similarity::Phonetic.new(similar_words_searched). Default is Similarity::None.new.
|
39
40
|
# * 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.
|
@@ -53,9 +54,9 @@ class IndexAPI
|
|
53
54
|
end
|
54
55
|
alias category define_category
|
55
56
|
|
56
|
-
# HIGHLY EXPERIMENTAL
|
57
|
+
# HIGHLY EXPERIMENTAL Try if you feel "beta" ;)
|
57
58
|
#
|
58
|
-
# Make this category range searchable.
|
59
|
+
# Make this category range searchable with a fixed range. If you need other ranges, define another category with a different range value.
|
59
60
|
#
|
60
61
|
# Example:
|
61
62
|
# You have data values inside 1..100, and you want to have Picky return
|
@@ -63,33 +64,61 @@ class IndexAPI
|
|
63
64
|
# 45, 46, or 47.2, 48.9, in a range of 2 around 47, so (45..49).
|
64
65
|
#
|
65
66
|
# Then you use:
|
66
|
-
# my_index.
|
67
|
+
# my_index.define_ranged_category :values_inside_1_100, 2
|
67
68
|
#
|
68
69
|
# Optionally, you give it a precision value to reduce the error margin
|
69
70
|
# around 47 (Picky is a bit liberal).
|
70
|
-
# my_index.
|
71
|
+
# my_index.define_ranged_category :values_inside_1_100, 2, precision: 5
|
71
72
|
#
|
72
73
|
# This will force Picky to maximally be wrong 5% of the given range value
|
73
|
-
# (5% of 2 = 0.1).
|
74
|
+
# (5% of 2 = 0.1) instead of the default 20% (20% of 2 = 0.4).
|
74
75
|
#
|
75
|
-
# We suggest not to use more than 5 as a higher precision is more performance intensive.
|
76
|
+
# We suggest not to use much more than 5 as a higher precision is more performance intensive for less and less precision gain.
|
76
77
|
#
|
77
|
-
#
|
78
|
-
#
|
79
|
-
#
|
78
|
+
# == Protip 1
|
79
|
+
#
|
80
|
+
# Create two ranged categories to make an area search:
|
81
|
+
# index.define_ranged_category :x, 1
|
82
|
+
# index.define_ranged_category :y, 1
|
83
|
+
#
|
84
|
+
# Search for it using for example:
|
85
|
+
# x:133, y:120
|
86
|
+
#
|
87
|
+
# This will search this square area (* = 133, 120: The "search" point entered):
|
88
|
+
#
|
89
|
+
# 132 134
|
90
|
+
# | |
|
91
|
+
# --|---------|-- 121
|
92
|
+
# | |
|
93
|
+
# | * |
|
94
|
+
# | |
|
95
|
+
# --|---------|-- 119
|
96
|
+
# | |
|
97
|
+
#
|
98
|
+
# Note: The area does not need to be square, but can be rectangular.
|
99
|
+
#
|
100
|
+
# == Protip 2
|
101
|
+
#
|
102
|
+
# Create three ranged categories to make a volume search.
|
103
|
+
#
|
104
|
+
# Or go crazy and use 4 ranged categories for a space/time search! ;)
|
105
|
+
#
|
106
|
+
# === Parameters
|
107
|
+
# * category_name: The category_name as used in #define_category.
|
108
|
+
# * range: The range (in the units of your data values) around the query point where we search for results.
|
80
109
|
#
|
81
110
|
# -----|<- range ->*------------|-----
|
82
111
|
#
|
83
|
-
# Options
|
84
|
-
# * precision
|
85
|
-
# *
|
112
|
+
# === Options
|
113
|
+
# * precision: Default is 1 (20% error margin, very fast), up to 5 (5% error margin, slower) makes sense.
|
114
|
+
# * ... all options of #define_category.
|
86
115
|
#
|
87
|
-
def
|
116
|
+
def define_ranged_category category_name, range, options = {}
|
88
117
|
precision = options[:precision]
|
89
118
|
|
90
119
|
options = { partial: Partial::None.new }.merge options
|
91
120
|
|
92
|
-
define_category
|
121
|
+
define_category category_name, options do |indexing, indexed|
|
93
122
|
indexing.source = Sources::Wrappers::Location.new indexing, grid: range, precision: precision
|
94
123
|
indexing.tokenizer = Tokenizers::Index.new
|
95
124
|
|
@@ -98,11 +127,11 @@ class IndexAPI
|
|
98
127
|
indexed.partial = exact_bundle # A partial token also uses the exact index.
|
99
128
|
end
|
100
129
|
end
|
101
|
-
alias
|
130
|
+
alias ranged_category define_ranged_category
|
102
131
|
|
103
132
|
# HIGHLY EXPERIMENTAL Not correctly working yet. Try it if you feel "beta".
|
104
133
|
#
|
105
|
-
# Also a range search see #
|
134
|
+
# Also a range search see #define_ranged_category, but on the earth's surface.
|
106
135
|
#
|
107
136
|
# Parameters:
|
108
137
|
# * name: The name as used in #define_category.
|
@@ -128,7 +157,9 @@ class IndexAPI
|
|
128
157
|
# * precision: Default 1 (20% error margin, very fast), up to 5 (5% error margin, slower) makes sense.
|
129
158
|
# * from: The data category to take the data for this category from.
|
130
159
|
#
|
131
|
-
|
160
|
+
# TODO Redo. Probably extract into define_latitude_category, define_longitude_category.
|
161
|
+
#
|
162
|
+
def define_map_location name, radius, options = {} # :nodoc:
|
132
163
|
# The radius is given as if all the locations were on the equator.
|
133
164
|
#
|
134
165
|
# TODO Need to recalculate since not many locations are on the equator ;) This is just a prototype.
|
@@ -138,7 +169,7 @@ class IndexAPI
|
|
138
169
|
# A degree on the equator is equal to ~111,319.9 meters.
|
139
170
|
# So a km on the equator is equal to 0.00898312 degrees.
|
140
171
|
#
|
141
|
-
|
172
|
+
define_ranged_category name, radius * 0.00898312, options
|
142
173
|
end
|
143
174
|
alias map_location define_map_location
|
144
175
|
end
|
data/lib/picky/indexed/index.rb
CHANGED
@@ -4,7 +4,7 @@ module Indexed
|
|
4
4
|
#
|
5
5
|
class Index
|
6
6
|
|
7
|
-
attr_reader :name, :
|
7
|
+
attr_reader :name, :result_identifier, :combinator, :categories
|
8
8
|
|
9
9
|
delegate :load_from_cache,
|
10
10
|
:to => :categories
|
@@ -12,7 +12,7 @@ module Indexed
|
|
12
12
|
def initialize name, options = {}
|
13
13
|
@name = name
|
14
14
|
|
15
|
-
@
|
15
|
+
@result_identifier = options[:result_identifier] || name
|
16
16
|
ignore_unassigned_tokens = options[:ignore_unassigned_tokens] || false # TODO Move to query, somehow.
|
17
17
|
|
18
18
|
@categories = Categories.new ignore_unassigned_tokens: ignore_unassigned_tokens
|
@@ -4,13 +4,13 @@ module Query
|
|
4
4
|
#
|
5
5
|
class Allocation # :nodoc:all
|
6
6
|
|
7
|
-
attr_reader :count, :ids, :score, :combinations, :
|
7
|
+
attr_reader :count, :ids, :score, :combinations, :result_identifier
|
8
8
|
|
9
9
|
#
|
10
10
|
#
|
11
|
-
def initialize combinations,
|
12
|
-
@combinations
|
13
|
-
@
|
11
|
+
def initialize combinations, result_identifier
|
12
|
+
@combinations = combinations
|
13
|
+
@result_identifier = result_identifier
|
14
14
|
end
|
15
15
|
|
16
16
|
def hash
|
@@ -61,7 +61,7 @@ module Query
|
|
61
61
|
# Transform the allocation into result form.
|
62
62
|
#
|
63
63
|
def to_result
|
64
|
-
[self.
|
64
|
+
[self.result_identifier, self.score, self.count, @combinations.to_result, self.ids] if self.count > 0
|
65
65
|
end
|
66
66
|
|
67
67
|
# Json representation of this allocation.
|
@@ -62,10 +62,10 @@ module Query
|
|
62
62
|
Performant::Array.memory_efficient_intersect id_arrays
|
63
63
|
end
|
64
64
|
|
65
|
-
# Wrap the combinations into an allocation with the
|
65
|
+
# Wrap the combinations into an allocation with the result_identifier.
|
66
66
|
#
|
67
|
-
def pack_into_allocation
|
68
|
-
Allocation.new self,
|
67
|
+
def pack_into_allocation result_identifier
|
68
|
+
Allocation.new self, result_identifier
|
69
69
|
end
|
70
70
|
|
71
71
|
# Filters the tokens and identifiers such that only identifiers
|
data/lib/picky/query/weigher.rb
CHANGED
@@ -53,7 +53,7 @@ module Query
|
|
53
53
|
|
54
54
|
# Wrap into a real combination.
|
55
55
|
#
|
56
|
-
# expanded_combinations.map! { |expanded_combination| Combinations.new(expanded_combination).pack_into_allocation(index.
|
56
|
+
# expanded_combinations.map! { |expanded_combination| Combinations.new(expanded_combination).pack_into_allocation(index.result_identifier) }
|
57
57
|
|
58
58
|
# Add the possible allocations to the ones we already have.
|
59
59
|
#
|
@@ -63,7 +63,7 @@ module Query
|
|
63
63
|
# Add the wrapped possible allocations to the ones we already have.
|
64
64
|
#
|
65
65
|
previous_allocations + expanded_combinations.map! do |expanded_combination|
|
66
|
-
Combinations.new(expanded_combination).pack_into_allocation(index.
|
66
|
+
Combinations.new(expanded_combination).pack_into_allocation(index.result_identifier) # TODO Do not extract result_identifier. Remove pack_into_allocation.
|
67
67
|
end
|
68
68
|
end)
|
69
69
|
end
|
@@ -4,7 +4,7 @@ describe Query::Allocation do
|
|
4
4
|
|
5
5
|
before(:each) do
|
6
6
|
@combinations = stub :combinations
|
7
|
-
@allocation = Query::Allocation.new @combinations, :
|
7
|
+
@allocation = Query::Allocation.new @combinations, :some_result_identifier
|
8
8
|
end
|
9
9
|
|
10
10
|
describe "eql?" do
|
@@ -34,7 +34,7 @@ describe Query::Allocation do
|
|
34
34
|
@allocation.stub! :ids => :ids
|
35
35
|
end
|
36
36
|
it "represents correctly" do
|
37
|
-
@allocation.to_s.should == "Allocation:
|
37
|
+
@allocation.to_s.should == "Allocation: some_result_identifier, score, 10, combinations_result, ids"
|
38
38
|
end
|
39
39
|
end
|
40
40
|
end
|
@@ -104,34 +104,34 @@ describe Query::Allocation do
|
|
104
104
|
describe 'to_result' do
|
105
105
|
context 'with few combinations' do
|
106
106
|
before(:each) do
|
107
|
-
@allocation = Query::Allocation.new stub(:combinations, :ids => [1,2,3], :to_result => [:some_result]), :
|
107
|
+
@allocation = Query::Allocation.new stub(:combinations, :ids => [1,2,3], :to_result => [:some_result]), :some_result_identifier
|
108
108
|
@allocation.instance_variable_set :@score, :some_score
|
109
109
|
end
|
110
110
|
context 'with ids' do
|
111
111
|
it 'should output an array of information' do
|
112
112
|
@allocation.process! 20, 0
|
113
113
|
|
114
|
-
@allocation.to_result.should == [:
|
114
|
+
@allocation.to_result.should == [:some_result_identifier, :some_score, 3, [:some_result], [1, 2, 3]]
|
115
115
|
end
|
116
116
|
end
|
117
117
|
end
|
118
118
|
context 'with results' do
|
119
119
|
before(:each) do
|
120
120
|
combinations = stub :combinations, :ids => [1,2,3], :to_result => [:some_result1, :some_result2]
|
121
|
-
@allocation = Query::Allocation.new combinations, :
|
121
|
+
@allocation = Query::Allocation.new combinations, :some_result_identifier
|
122
122
|
@allocation.instance_variable_set :@score, :some_score
|
123
123
|
end
|
124
124
|
context 'with ids' do
|
125
125
|
it 'should output an array of information' do
|
126
126
|
@allocation.process! 20, 0
|
127
127
|
|
128
|
-
@allocation.to_result.should == [:
|
128
|
+
@allocation.to_result.should == [:some_result_identifier, :some_score, 3, [:some_result1, :some_result2], [1, 2, 3]]
|
129
129
|
end
|
130
130
|
end
|
131
131
|
end
|
132
132
|
context 'without results' do
|
133
133
|
before(:each) do
|
134
|
-
@allocation = Query::Allocation.new stub(:combinations, :ids => [], :to_result => []), :
|
134
|
+
@allocation = Query::Allocation.new stub(:combinations, :ids => [], :to_result => []), :some_result_identifier
|
135
135
|
@allocation.instance_variable_set :@score, :some_score
|
136
136
|
end
|
137
137
|
it 'should return nil' do
|
@@ -144,13 +144,13 @@ describe Query::Allocation do
|
|
144
144
|
|
145
145
|
describe 'to_json' do
|
146
146
|
before(:each) do
|
147
|
-
@allocation = Query::Allocation.new stub(:combination, :ids => [1,2,3,4,5,6,7], :to_result => [:some_result1, :some_result2]), :
|
147
|
+
@allocation = Query::Allocation.new stub(:combination, :ids => [1,2,3,4,5,6,7], :to_result => [:some_result1, :some_result2]), :some_result_identifier
|
148
148
|
@allocation.instance_variable_set :@score, :some_score
|
149
149
|
end
|
150
150
|
it 'should output the correct json string' do
|
151
151
|
@allocation.process! 20, 0
|
152
152
|
|
153
|
-
@allocation.to_json.should == '["
|
153
|
+
@allocation.to_json.should == '["some_result_identifier","some_score",7,["some_result1","some_result2"],[1,2,3,4,5,6,7]]'
|
154
154
|
end
|
155
155
|
end
|
156
156
|
|
@@ -164,9 +164,9 @@ describe Query::Allocation do
|
|
164
164
|
|
165
165
|
describe "<=>" do
|
166
166
|
it "should sort higher first" do
|
167
|
-
first = Query::Allocation.new [], :
|
167
|
+
first = Query::Allocation.new [], :some_result_identifier
|
168
168
|
first.instance_variable_set :@score, 20
|
169
|
-
second = Query::Allocation.new [], :
|
169
|
+
second = Query::Allocation.new [], :some_result_identifier
|
170
170
|
second.instance_variable_set :@score, 10
|
171
171
|
|
172
172
|
first.<=>(second).should == -1
|
@@ -175,11 +175,11 @@ describe Query::Allocation do
|
|
175
175
|
|
176
176
|
describe "sort!" do
|
177
177
|
it "should sort correctly" do
|
178
|
-
first = Query::Allocation.new :whatever, :
|
178
|
+
first = Query::Allocation.new :whatever, :some_result_identifier
|
179
179
|
first.instance_variable_set :@score, 20
|
180
|
-
second = Query::Allocation.new :whatever, :
|
180
|
+
second = Query::Allocation.new :whatever, :some_result_identifier
|
181
181
|
second.instance_variable_set :@score, 10
|
182
|
-
third = Query::Allocation.new :whatever, :
|
182
|
+
third = Query::Allocation.new :whatever, :some_result_identifier
|
183
183
|
third.instance_variable_set :@score, 5
|
184
184
|
|
185
185
|
allocations = [second, third, first]
|
@@ -12,10 +12,10 @@ describe 'Query::Combinations' do
|
|
12
12
|
|
13
13
|
describe "pack_into_allocation" do
|
14
14
|
it "return an Allocation" do
|
15
|
-
@combinations.pack_into_allocation(:
|
15
|
+
@combinations.pack_into_allocation(:some_result_identifier).should be_kind_of(Query::Allocation)
|
16
16
|
end
|
17
|
-
it "returns an Allocation with specific
|
18
|
-
@combinations.pack_into_allocation(:
|
17
|
+
it "returns an Allocation with specific result_identifier" do
|
18
|
+
@combinations.pack_into_allocation(:some_result_identifier).result_identifier.should == :some_result_identifier
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|