searchkick 4.1.1 → 4.2.0
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 -0
- data/README.md +8 -8
- data/lib/searchkick/index.rb +24 -1
- data/lib/searchkick/index_options.rb +7 -0
- data/lib/searchkick/logging.rb +11 -10
- data/lib/searchkick/model.rb +1 -1
- data/lib/searchkick/query.rb +28 -14
- data/lib/searchkick/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '0529381ceedcb4630640d4ae37b02ac2e950c3088a757946b930e56e0a8d4591'
|
4
|
+
data.tar.gz: 539ee2b8da1632f5b86ff3da063e5b815fac2ba3edb5efc2b3d2d508cdb9c002
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cfb0aa73064ee937db83d948086bf5f9f1a81bc597f871288786f18ddaff1f39edf202c3a877d4147c3e963c1a736130f4250e10238444924347dbf8854b15c0
|
7
|
+
data.tar.gz: d4733742e12185d5f6296361948a20a2cc11ad14cf0f2c254cbcb80b5f5c64ba6754eb46161b22e33d786363a94b7e79db8b55d567e77ee8dc46ed3a9d7ab246
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
## 4.2.0 (2019-12-18)
|
2
|
+
|
3
|
+
- Added safety check for multiple `Model.reindex`
|
4
|
+
- Added `deep_paging` option
|
5
|
+
- Added request parameters to search notifications and curl representation
|
6
|
+
- Removed curl from search notifications to prevent confusion
|
7
|
+
|
1
8
|
## 4.1.1 (2019-11-19)
|
2
9
|
|
3
10
|
- Added `chinese2` and `korean2` languages
|
data/README.md
CHANGED
@@ -137,8 +137,6 @@ Limit / offset
|
|
137
137
|
limit: 20, offset: 40
|
138
138
|
```
|
139
139
|
|
140
|
-
**Note:** By default, Elasticsearch [limits pagination](#deep-pagination) to the first 10,000 results for performance
|
141
|
-
|
142
140
|
Select
|
143
141
|
|
144
142
|
```ruby
|
@@ -182,6 +180,8 @@ Get the full response from Elasticsearch
|
|
182
180
|
results.response
|
183
181
|
```
|
184
182
|
|
183
|
+
**Note:** By default, Elasticsearch [limits paging](#deep-paging-master) to the first 10,000 results for performance. With Elasticsearch 7, this applies to the total count as well.
|
184
|
+
|
185
185
|
### Boosting
|
186
186
|
|
187
187
|
Boost important fields
|
@@ -554,7 +554,7 @@ Searchkick.callbacks(false) do
|
|
554
554
|
end
|
555
555
|
```
|
556
556
|
|
557
|
-
|
557
|
+
### Associations
|
558
558
|
|
559
559
|
Data is **not** automatically synced when an association is updated. If this is desired, add a callback to reindex:
|
560
560
|
|
@@ -1518,20 +1518,20 @@ end
|
|
1518
1518
|
products.clear_scroll
|
1519
1519
|
```
|
1520
1520
|
|
1521
|
-
## Deep
|
1521
|
+
## Deep Paging
|
1522
1522
|
|
1523
|
-
By default, Elasticsearch limits
|
1523
|
+
By default, Elasticsearch limits paging to the first 10,000 results. [Here’s why](https://www.elastic.co/guide/en/elasticsearch/guide/current/pagination.html). We don’t recommend changing this, but if you really need all results, you can use:
|
1524
1524
|
|
1525
1525
|
```ruby
|
1526
1526
|
class Product < ApplicationRecord
|
1527
|
-
searchkick
|
1527
|
+
searchkick deep_paging: true
|
1528
1528
|
end
|
1529
1529
|
```
|
1530
1530
|
|
1531
|
-
|
1531
|
+
If you just need an accurate total count with Elasticsearch 7, you can instead use:
|
1532
1532
|
|
1533
1533
|
```ruby
|
1534
|
-
Product.search("pears",
|
1534
|
+
Product.search("pears", body_options: {track_total_hits: true})
|
1535
1535
|
```
|
1536
1536
|
|
1537
1537
|
## Nested Data
|
data/lib/searchkick/index.rb
CHANGED
@@ -47,7 +47,7 @@ module Searchkick
|
|
47
47
|
end
|
48
48
|
|
49
49
|
def refresh_interval
|
50
|
-
|
50
|
+
index_settings["refresh_interval"]
|
51
51
|
end
|
52
52
|
|
53
53
|
def update_settings(settings)
|
@@ -249,6 +249,11 @@ module Searchkick
|
|
249
249
|
end
|
250
250
|
end
|
251
251
|
|
252
|
+
# private
|
253
|
+
def uuid
|
254
|
+
index_settings["uuid"]
|
255
|
+
end
|
256
|
+
|
252
257
|
protected
|
253
258
|
|
254
259
|
def client
|
@@ -259,6 +264,10 @@ module Searchkick
|
|
259
264
|
@bulk_indexer ||= BulkIndexer.new(self)
|
260
265
|
end
|
261
266
|
|
267
|
+
def index_settings
|
268
|
+
settings.values.first["settings"]["index"]
|
269
|
+
end
|
270
|
+
|
262
271
|
def import_before_promotion(index, relation, **import_options)
|
263
272
|
index.import_scope(relation, **import_options)
|
264
273
|
end
|
@@ -285,6 +294,8 @@ module Searchkick
|
|
285
294
|
scope: scope
|
286
295
|
}
|
287
296
|
|
297
|
+
uuid = index.uuid
|
298
|
+
|
288
299
|
# check if alias exists
|
289
300
|
alias_exists = alias_exists?
|
290
301
|
if alias_exists
|
@@ -292,6 +303,7 @@ module Searchkick
|
|
292
303
|
|
293
304
|
# get existing indices to remove
|
294
305
|
unless async
|
306
|
+
check_uuid(uuid, index.uuid)
|
295
307
|
promote(index.name, update_refresh_interval: !refresh_interval.nil?)
|
296
308
|
clean_indices unless retain
|
297
309
|
end
|
@@ -316,6 +328,7 @@ module Searchkick
|
|
316
328
|
# already promoted if alias didn't exist
|
317
329
|
if alias_exists
|
318
330
|
puts "Jobs complete. Promoting..."
|
331
|
+
check_uuid(uuid, index.uuid)
|
319
332
|
promote(index.name, update_refresh_interval: !refresh_interval.nil?)
|
320
333
|
end
|
321
334
|
clean_indices unless retain
|
@@ -334,5 +347,15 @@ module Searchkick
|
|
334
347
|
|
335
348
|
raise e
|
336
349
|
end
|
350
|
+
|
351
|
+
# safety check
|
352
|
+
# still a chance for race condition since its called before promotion
|
353
|
+
# ideal is for user to disable automatic index creation
|
354
|
+
# https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-index_.html#index-creation
|
355
|
+
def check_uuid(old_uuid, new_uuid)
|
356
|
+
if old_uuid != new_uuid
|
357
|
+
raise Searchkick::Error, "Safety check failed - only run one Model.reindex per model at a time"
|
358
|
+
end
|
359
|
+
end
|
337
360
|
end
|
338
361
|
end
|
@@ -456,6 +456,13 @@ module Searchkick
|
|
456
456
|
mappings = mappings.symbolize_keys.deep_merge(custom_mapping.symbolize_keys)
|
457
457
|
end
|
458
458
|
|
459
|
+
if options[:deep_paging]
|
460
|
+
if !settings.dig(:index, :max_result_window) && !settings[:"index.max_result_window"]
|
461
|
+
settings[:index] ||= {}
|
462
|
+
settings[:index][:max_result_window] = 1_000_000_000
|
463
|
+
end
|
464
|
+
end
|
465
|
+
|
459
466
|
{
|
460
467
|
settings: settings,
|
461
468
|
mappings: mappings
|
data/lib/searchkick/logging.rb
CHANGED
@@ -132,7 +132,7 @@ module Searchkick
|
|
132
132
|
def multi_search(searches)
|
133
133
|
event = {
|
134
134
|
name: "Multi Search",
|
135
|
-
body: searches.flat_map { |q| [q.params.except(:body).to_json, q.body.to_json] }.map { |v| "#{v}\n" }.join
|
135
|
+
body: searches.flat_map { |q| [q.params.except(:body).to_json, q.body.to_json] }.map { |v| "#{v}\n" }.join,
|
136
136
|
}
|
137
137
|
ActiveSupport::Notifications.instrument("multi_search.searchkick", event) do
|
138
138
|
super
|
@@ -162,14 +162,17 @@ module Searchkick
|
|
162
162
|
|
163
163
|
payload = event.payload
|
164
164
|
name = "#{payload[:name]} (#{event.duration.round(1)}ms)"
|
165
|
-
|
165
|
+
|
166
166
|
index = payload[:query][:index].is_a?(Array) ? payload[:query][:index].join(",") : payload[:query][:index]
|
167
|
+
type = payload[:query][:type]
|
168
|
+
request_params = payload[:query].except(:index, :type, :body)
|
169
|
+
|
170
|
+
params = []
|
171
|
+
request_params.each do |k, v|
|
172
|
+
params << "#{CGI.escape(k.to_s)}=#{CGI.escape(v.to_s)}"
|
173
|
+
end
|
167
174
|
|
168
|
-
#
|
169
|
-
host = Searchkick.client.transport.hosts.first
|
170
|
-
params = ["pretty"]
|
171
|
-
params << "scroll=#{payload[:query][:scroll]}" if payload[:query][:scroll]
|
172
|
-
debug " #{color(name, YELLOW, true)} curl #{host[:protocol]}://#{host[:host]}:#{host[:port]}/#{CGI.escape(index)}#{type ? "/#{type.map { |t| CGI.escape(t) }.join(',')}" : ''}/_search?#{params.join('&')} -H 'Content-Type: application/json' -d '#{payload[:query][:body].to_json}'"
|
175
|
+
debug " #{color(name, YELLOW, true)} #{index}#{type ? "/#{type.join(',')}" : ''}/_search#{params.any? ? '?' + params.join('&') : nil} #{payload[:query][:body].to_json}"
|
173
176
|
end
|
174
177
|
|
175
178
|
def request(event)
|
@@ -189,9 +192,7 @@ module Searchkick
|
|
189
192
|
payload = event.payload
|
190
193
|
name = "#{payload[:name]} (#{event.duration.round(1)}ms)"
|
191
194
|
|
192
|
-
#
|
193
|
-
host = Searchkick.client.transport.hosts.first
|
194
|
-
debug " #{color(name, YELLOW, true)} curl #{host[:protocol]}://#{host[:host]}:#{host[:port]}/_msearch?pretty -H 'Content-Type: application/json' -d '#{payload[:body]}'"
|
195
|
+
debug " #{color(name, YELLOW, true)} _msearch #{payload[:body]}"
|
195
196
|
end
|
196
197
|
end
|
197
198
|
|
data/lib/searchkick/model.rb
CHANGED
@@ -3,7 +3,7 @@ module Searchkick
|
|
3
3
|
def searchkick(**options)
|
4
4
|
options = Searchkick.model_options.merge(options)
|
5
5
|
|
6
|
-
unknown_keywords = options.keys - [:_all, :_type, :batch_size, :callbacks, :case_sensitive, :conversions, :default_fields,
|
6
|
+
unknown_keywords = options.keys - [:_all, :_type, :batch_size, :callbacks, :case_sensitive, :conversions, :deep_paging, :default_fields,
|
7
7
|
:filterable, :geo_shape, :highlight, :ignore_above, :index_name, :index_prefix, :inheritance, :language,
|
8
8
|
:locations, :mappings, :match, :merge_mappings, :routing, :searchable, :settings, :similarity,
|
9
9
|
:special_characters, :stem, :stem_conversions, :suggest, :synonyms, :text_end,
|
data/lib/searchkick/query.rb
CHANGED
@@ -106,12 +106,15 @@ module Searchkick
|
|
106
106
|
query = params
|
107
107
|
type = query[:type]
|
108
108
|
index = query[:index].is_a?(Array) ? query[:index].join(",") : query[:index]
|
109
|
+
request_params = query.except(:index, :type, :body)
|
109
110
|
|
110
111
|
# no easy way to tell which host the client will use
|
111
112
|
host = Searchkick.client.transport.hosts.first
|
112
113
|
credentials = host[:user] || host[:password] ? "#{host[:user]}:#{host[:password]}@" : nil
|
113
114
|
params = ["pretty"]
|
114
|
-
|
115
|
+
request_params.each do |k, v|
|
116
|
+
params << "#{CGI.escape(k.to_s)}=#{CGI.escape(v.to_s)}"
|
117
|
+
end
|
115
118
|
"curl #{host[:protocol]}://#{credentials}#{host[:host]}:#{host[:port]}/#{CGI.escape(index)}#{type ? "/#{type.map { |t| CGI.escape(t) }.join(',')}" : ''}/_search?#{params.join('&')} -H 'Content-Type: application/json' -d '#{query[:body].to_json}'"
|
116
119
|
end
|
117
120
|
|
@@ -232,7 +235,9 @@ module Searchkick
|
|
232
235
|
|
233
236
|
# pagination
|
234
237
|
page = [options[:page].to_i, 1].max
|
235
|
-
|
238
|
+
# maybe use index.max_result_window in the future
|
239
|
+
default_limit = searchkick_options[:deep_paging] ? 1_000_000_000 : 10_000
|
240
|
+
per_page = (options[:limit] || options[:per_page] || default_limit).to_i
|
236
241
|
padding = [options[:padding].to_i, 0].max
|
237
242
|
offset = options[:offset] || (page - 1) * per_page + padding
|
238
243
|
scroll = options[:scroll]
|
@@ -433,19 +438,20 @@ module Searchkick
|
|
433
438
|
|
434
439
|
models = Array(options[:models])
|
435
440
|
if models.any? { |m| m != m.searchkick_klass }
|
436
|
-
|
437
|
-
|
438
|
-
# TODO uncomment once aliases are supported with _index
|
439
|
-
# should be ES 7.5
|
441
|
+
# aliases are not supported with _index in ES below 7.5
|
440
442
|
# see https://github.com/elastic/elasticsearch/pull/46640
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
443
|
+
if below75?
|
444
|
+
Searchkick.warn("Passing child models to models option throws off hits and pagination - use type option instead")
|
445
|
+
else
|
446
|
+
index_type_or =
|
447
|
+
models.map do |m|
|
448
|
+
v = {_index: m.searchkick_index.name}
|
449
|
+
v[:type] = m.searchkick_index.klass_document_type(m, true) if m != m.searchkick_klass
|
450
|
+
v
|
451
|
+
end
|
452
|
+
|
453
|
+
where[:or] = Array(where[:or]) + [index_type_or]
|
454
|
+
end
|
449
455
|
end
|
450
456
|
|
451
457
|
# start everything as efficient filters
|
@@ -516,6 +522,10 @@ module Searchkick
|
|
516
522
|
# routing
|
517
523
|
@routing = options[:routing] if options[:routing]
|
518
524
|
|
525
|
+
if searchkick_options[:deep_paging] && !below70?
|
526
|
+
payload[:track_total_hits] = true
|
527
|
+
end
|
528
|
+
|
519
529
|
# merge more body options
|
520
530
|
payload = payload.deep_merge(options[:body_options]) if options[:body_options]
|
521
531
|
|
@@ -1097,5 +1107,9 @@ module Searchkick
|
|
1097
1107
|
def below70?
|
1098
1108
|
Searchkick.server_below?("7.0.0")
|
1099
1109
|
end
|
1110
|
+
|
1111
|
+
def below75?
|
1112
|
+
Searchkick.server_below?("7.5.0")
|
1113
|
+
end
|
1100
1114
|
end
|
1101
1115
|
end
|
data/lib/searchkick/version.rb
CHANGED
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: 4.
|
4
|
+
version: 4.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Kane
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-12-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activemodel
|
@@ -145,7 +145,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
145
145
|
- !ruby/object:Gem::Version
|
146
146
|
version: '0'
|
147
147
|
requirements: []
|
148
|
-
rubygems_version: 3.0.
|
148
|
+
rubygems_version: 3.0.3
|
149
149
|
signing_key:
|
150
150
|
specification_version: 4
|
151
151
|
summary: Intelligent search made easy with Rails and Elasticsearch
|