searchkick 0.7.7 → 0.7.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -1
- data/README.md +39 -14
- data/lib/searchkick/query.rb +37 -18
- data/lib/searchkick/results.rb +6 -1
- data/lib/searchkick/version.rb +1 -1
- data/test/boost_test.rb +37 -0
- data/test/sql_test.rb +7 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bb8ada9111159102b2327b5344afe0876aac137d
|
4
|
+
data.tar.gz: 3e3e655a723d06f6b741b0938d3fde6d02d5c7ab
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fdb99efc9149d644dd126456c9ab2e753a6f67a77feb90e07ad20dcbea75dd7152705136a2e30cfd0fd9e1a38a0ba35b1f05d0b8dd6c986ba248aa90a82126b2
|
7
|
+
data.tar.gz: 04a2c3229e5f40a866fa8cc2aed8832d361d680ef9a88fe75d1e3b8dc72875524961056f2f00bf2edd7bcd07989864118367547006198588b5f3af3e0e81ee96
|
data/CHANGELOG.md
CHANGED
@@ -1,7 +1,13 @@
|
|
1
|
+
## 0.7.8
|
2
|
+
|
3
|
+
- Added `boost_by` and `boost_where` options
|
4
|
+
- Added ability to boost fields - `name^10`
|
5
|
+
- Added `select` option for `load: false`
|
6
|
+
|
1
7
|
## 0.7.7
|
2
8
|
|
3
9
|
- Added support for automatic failover
|
4
|
-
- Fixed default
|
10
|
+
- Fixed `operator` option (and default) for partial matches
|
5
11
|
|
6
12
|
## 0.7.6
|
7
13
|
|
data/README.md
CHANGED
@@ -116,10 +116,26 @@ Limit / offset
|
|
116
116
|
limit: 20, offset: 40
|
117
117
|
```
|
118
118
|
|
119
|
-
|
119
|
+
### Boosting
|
120
|
+
|
121
|
+
Boost important fields
|
122
|
+
|
123
|
+
```ruby
|
124
|
+
fields: ["title^10", "description"]
|
125
|
+
```
|
126
|
+
|
127
|
+
Boost by the value of a field
|
120
128
|
|
121
129
|
```ruby
|
122
|
-
|
130
|
+
boost_by: [:orders_count] # give popular documents a little boost
|
131
|
+
boost_by: {orders_count: {factor: 10}}
|
132
|
+
```
|
133
|
+
|
134
|
+
Boost matching documents
|
135
|
+
|
136
|
+
```ruby
|
137
|
+
boost_where: {user_id: 1}
|
138
|
+
boost_where: {user_id: {value: 1, factor: 100}}
|
123
139
|
```
|
124
140
|
|
125
141
|
### Get Everything
|
@@ -164,7 +180,7 @@ class Product < ActiveRecord::Base
|
|
164
180
|
end
|
165
181
|
```
|
166
182
|
|
167
|
-
And to search:
|
183
|
+
And to search (after you reindex):
|
168
184
|
|
169
185
|
```ruby
|
170
186
|
Product.search "back", fields: [{name: :word_start}]
|
@@ -182,6 +198,12 @@ Available options are:
|
|
182
198
|
:text_end
|
183
199
|
```
|
184
200
|
|
201
|
+
To boost fields, use:
|
202
|
+
|
203
|
+
```ruby
|
204
|
+
fields: [{"name^2" => :word_start}] # better interface on the way
|
205
|
+
```
|
206
|
+
|
185
207
|
### Language
|
186
208
|
|
187
209
|
Searchkick defaults to English for stemming. To change this, use:
|
@@ -281,7 +303,7 @@ end
|
|
281
303
|
|
282
304
|
You do **not** need to clean up the search queries. Searchkick automatically treats `apple` and `APPLES` the same.
|
283
305
|
|
284
|
-
Next, add conversions to the index.
|
306
|
+
Next, add conversions to the index.
|
285
307
|
|
286
308
|
```ruby
|
287
309
|
class Product < ActiveRecord::Base
|
@@ -311,22 +333,21 @@ Order results differently for each user. For example, show a user’s previousl
|
|
311
333
|
|
312
334
|
```ruby
|
313
335
|
class Product < ActiveRecord::Base
|
314
|
-
searchkick personalize: "user_ids"
|
315
336
|
|
316
337
|
def search_data
|
317
338
|
{
|
318
339
|
name: name,
|
319
340
|
user_ids: orders.pluck(:user_id) # boost this product for these users
|
320
|
-
# [4, 8, 15, 16, 23, 42]
|
321
341
|
}
|
322
342
|
end
|
343
|
+
|
323
344
|
end
|
324
345
|
```
|
325
346
|
|
326
347
|
Reindex and search with:
|
327
348
|
|
328
349
|
```ruby
|
329
|
-
Product.search "milk", user_id: 8
|
350
|
+
Product.search "milk", boost_where: {user_id: 8}
|
330
351
|
```
|
331
352
|
|
332
353
|
### Autocomplete
|
@@ -484,8 +505,6 @@ product.similar(fields: ["name"])
|
|
484
505
|
|
485
506
|
### Geospatial Searches
|
486
507
|
|
487
|
-
**Note:** Before `0.3.0`, locations were indexed incorrectly. When upgrading, be sure to reindex immediately.
|
488
|
-
|
489
508
|
```ruby
|
490
509
|
class City < ActiveRecord::Base
|
491
510
|
searchkick locations: ["location"]
|
@@ -785,10 +804,20 @@ rake searchkick:reindex:all
|
|
785
804
|
|
786
805
|
4. Once it finishes, replace search calls w/ searchkick calls
|
787
806
|
|
788
|
-
##
|
807
|
+
## Upgrading
|
808
|
+
|
809
|
+
View the [changelog](https://github.com/ankane/searchkick/blob/master/CHANGELOG.md).
|
810
|
+
|
811
|
+
Important notes are listed below.
|
812
|
+
|
813
|
+
### 0.6.0 and 0.7.0
|
789
814
|
|
790
815
|
If running Searchkick `0.6.0` or `0.7.0` and Elasticsearch `0.90`, we recommend upgrading to Searchkick `0.6.1` or `0.7.1` to fix an issue that causes downtime when reindexing.
|
791
816
|
|
817
|
+
### 0.3.0
|
818
|
+
|
819
|
+
Before `0.3.0`, locations were indexed incorrectly. When upgrading, be sure to reindex immediately.
|
820
|
+
|
792
821
|
## Elasticsearch Gotchas
|
793
822
|
|
794
823
|
### Inconsistent Scores
|
@@ -816,10 +845,6 @@ Thanks to Karel Minarik for [Elasticsearch Ruby](https://github.com/elasticsearc
|
|
816
845
|
- Much finer customization
|
817
846
|
- More transparency into generated queries (for advanced use)
|
818
847
|
|
819
|
-
## History
|
820
|
-
|
821
|
-
View the [changelog](https://github.com/ankane/searchkick/blob/master/CHANGELOG.md)
|
822
|
-
|
823
848
|
## Contributing
|
824
849
|
|
825
850
|
Everyone is encouraged to help improve this project. Here are a few ways you can help:
|
data/lib/searchkick/query.rb
CHANGED
@@ -15,6 +15,7 @@ module Searchkick
|
|
15
15
|
@term = term
|
16
16
|
@options = options
|
17
17
|
|
18
|
+
boost_fields = {}
|
18
19
|
fields =
|
19
20
|
if options[:fields]
|
20
21
|
if options[:autocomplete]
|
@@ -22,7 +23,10 @@ module Searchkick
|
|
22
23
|
else
|
23
24
|
options[:fields].map do |value|
|
24
25
|
k, v = value.is_a?(Hash) ? value.to_a.first : [value, :word]
|
25
|
-
|
26
|
+
k2, boost = k.to_s.split("^", 2)
|
27
|
+
field = "#{k2}.#{v == :word ? "analyzed" : v}"
|
28
|
+
boost_fields[field] = boost.to_i if boost
|
29
|
+
field
|
26
30
|
end
|
27
31
|
end
|
28
32
|
else
|
@@ -74,17 +78,19 @@ module Searchkick
|
|
74
78
|
else
|
75
79
|
queries = []
|
76
80
|
fields.each do |field|
|
81
|
+
factor = boost_fields[field] || 1
|
77
82
|
shared_options = {
|
78
83
|
fields: [field],
|
79
84
|
query: term,
|
80
85
|
use_dis_max: false,
|
81
|
-
operator: operator
|
86
|
+
operator: operator,
|
87
|
+
boost: factor
|
82
88
|
}
|
83
89
|
if field == "_all" or field.end_with?(".analyzed")
|
84
90
|
shared_options[:cutoff_frequency] = 0.001 unless operator == "and"
|
85
91
|
queries.concat [
|
86
|
-
{multi_match: shared_options.merge(boost: 10, analyzer: "searchkick_search")},
|
87
|
-
{multi_match: shared_options.merge(boost: 10, analyzer: "searchkick_search2")}
|
92
|
+
{multi_match: shared_options.merge(boost: 10 * factor, analyzer: "searchkick_search")},
|
93
|
+
{multi_match: shared_options.merge(boost: 10 * factor, analyzer: "searchkick_search2")}
|
88
94
|
]
|
89
95
|
if options[:misspellings] != false
|
90
96
|
distance = (options[:misspellings].is_a?(Hash) && options[:misspellings][:distance]) || 1
|
@@ -137,36 +143,45 @@ module Searchkick
|
|
137
143
|
|
138
144
|
custom_filters = []
|
139
145
|
|
146
|
+
boost_by = options[:boost_by] || {}
|
147
|
+
if boost_by.is_a?(Array)
|
148
|
+
boost_by = Hash[ boost_by.map{|f| [f, {factor: 1}] } ]
|
149
|
+
end
|
140
150
|
if options[:boost]
|
151
|
+
boost_by[options[:boost]] = {factor: 1}
|
152
|
+
end
|
153
|
+
|
154
|
+
boost_by.each do |field, value|
|
141
155
|
custom_filters << {
|
142
156
|
filter: {
|
143
157
|
exists: {
|
144
|
-
field:
|
158
|
+
field: field
|
145
159
|
}
|
146
160
|
},
|
147
161
|
script_score: {
|
148
|
-
script: "log(doc['#{
|
162
|
+
script: "#{value[:factor].to_f} * log(doc['#{field}'].value + 2.718281828)"
|
149
163
|
}
|
150
164
|
}
|
151
165
|
end
|
152
166
|
|
167
|
+
boost_where = options[:boost_where] || {}
|
153
168
|
if options[:user_id] and personalize_field
|
154
|
-
|
155
|
-
filter: {
|
156
|
-
term: {
|
157
|
-
personalize_field => options[:user_id]
|
158
|
-
}
|
159
|
-
},
|
160
|
-
boost_factor: 100
|
161
|
-
}
|
169
|
+
boost_where[personalize_field] = options[:user_id]
|
162
170
|
end
|
163
|
-
|
164
171
|
if options[:personalize]
|
172
|
+
boost_where.merge!(options[:personalize])
|
173
|
+
end
|
174
|
+
boost_where.each do |field, value|
|
175
|
+
if value.is_a?(Hash)
|
176
|
+
value, factor = value[:value], value[:factor]
|
177
|
+
else
|
178
|
+
factor = 1000
|
179
|
+
end
|
165
180
|
custom_filters << {
|
166
181
|
filter: {
|
167
|
-
term:
|
182
|
+
term: {field => value}
|
168
183
|
},
|
169
|
-
boost_factor:
|
184
|
+
boost_factor: factor
|
170
185
|
}
|
171
186
|
end
|
172
187
|
|
@@ -292,7 +307,11 @@ module Searchkick
|
|
292
307
|
|
293
308
|
# An empty array will cause only the _id and _type for each hit to be returned
|
294
309
|
# http://www.elasticsearch.org/guide/reference/api/search/fields/
|
295
|
-
|
310
|
+
if load
|
311
|
+
payload[:fields] = []
|
312
|
+
elsif options[:select]
|
313
|
+
payload[:fields] = options[:select]
|
314
|
+
end
|
296
315
|
|
297
316
|
if options[:type] or klass != searchkick_klass
|
298
317
|
@type = [options[:type] || klass].flatten.map{|v| searchkick_index.klass_document_type(v) }
|
data/lib/searchkick/results.rb
CHANGED
@@ -38,7 +38,12 @@ module Searchkick
|
|
38
38
|
end.compact
|
39
39
|
else
|
40
40
|
hits.map do |hit|
|
41
|
-
result =
|
41
|
+
result =
|
42
|
+
if hit["_source"]
|
43
|
+
hit.except("_source").merge(hit["_source"])
|
44
|
+
else
|
45
|
+
hit.except("fields").merge(hit["fields"])
|
46
|
+
end
|
42
47
|
result["id"] ||= result["_id"] # needed for legacy reasons
|
43
48
|
Hashie::Mash.new(result)
|
44
49
|
end
|
data/lib/searchkick/version.rb
CHANGED
data/test/boost_test.rb
CHANGED
@@ -67,4 +67,41 @@ class TestBoost < Minitest::Unit::TestCase
|
|
67
67
|
assert_first "tomato", "Tomato B", personalize: {user_ids: 2}
|
68
68
|
end
|
69
69
|
|
70
|
+
def test_boost_fields
|
71
|
+
store [
|
72
|
+
{name: "Red", color: "White"},
|
73
|
+
{name: "White", color: "Red Red Red"}
|
74
|
+
]
|
75
|
+
assert_order "red", ["Red", "White"], fields: ["name^10", "color"]
|
76
|
+
end
|
77
|
+
|
78
|
+
def test_boost_fields_word_start
|
79
|
+
store [
|
80
|
+
{name: "Red", color: "White"},
|
81
|
+
{name: "White", color: "Red Red Red"}
|
82
|
+
]
|
83
|
+
assert_order "red", ["Red", "White"], fields: [{"name^10" => :word_start}, "color"]
|
84
|
+
end
|
85
|
+
|
86
|
+
def test_boost_by
|
87
|
+
store [
|
88
|
+
{name: "Tomato A"},
|
89
|
+
{name: "Tomato B", orders_count: 10},
|
90
|
+
{name: "Tomato C", orders_count: 100}
|
91
|
+
]
|
92
|
+
assert_order "tomato", ["Tomato C", "Tomato B", "Tomato A"], boost_by: [:orders_count]
|
93
|
+
assert_order "tomato", ["Tomato C", "Tomato B", "Tomato A"], boost_by: {orders_count: {factor: 10}}
|
94
|
+
end
|
95
|
+
|
96
|
+
def test_boost_where
|
97
|
+
store [
|
98
|
+
{name: "Tomato A"},
|
99
|
+
{name: "Tomato B", user_ids: [1, 2, 3]},
|
100
|
+
{name: "Tomato C"},
|
101
|
+
{name: "Tomato D"}
|
102
|
+
]
|
103
|
+
assert_first "tomato", "Tomato B", boost_where: {user_ids: 2}
|
104
|
+
assert_first "tomato", "Tomato B", boost_where: {user_ids: {value: 2, factor: 10}}
|
105
|
+
end
|
106
|
+
|
70
107
|
end
|
data/test/sql_test.rb
CHANGED
@@ -274,6 +274,13 @@ class TestSql < Minitest::Unit::TestCase
|
|
274
274
|
assert_kind_of Hash, Product.search("product", load: false, include: [:store]).first
|
275
275
|
end
|
276
276
|
|
277
|
+
# select
|
278
|
+
|
279
|
+
def test_select
|
280
|
+
store [{name: "Product A", store_id: 1}]
|
281
|
+
assert_equal %w[id name store_id], Product.search("product", load: false, select: [:name, :store_id]).first.keys.reject{|k| k.start_with?("_") }.sort
|
282
|
+
end
|
283
|
+
|
277
284
|
# TODO see if Mongoid is loaded
|
278
285
|
if !defined?(Mongoid)
|
279
286
|
def test_include
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: searchkick
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.7.
|
4
|
+
version: 0.7.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Kane
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-06-
|
11
|
+
date: 2014-06-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activemodel
|