chewy 7.2.4 → 7.6.0
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.
- checksums.yaml +4 -4
- data/.github/CODEOWNERS +1 -0
- data/.github/dependabot.yml +42 -0
- data/.github/workflows/ruby.yml +26 -32
- data/.rubocop.yml +4 -1
- data/CHANGELOG.md +144 -0
- data/Gemfile +4 -4
- data/README.md +165 -10
- data/chewy.gemspec +4 -17
- data/gemfiles/base.gemfile +12 -0
- data/gemfiles/rails.6.1.activerecord.gemfile +2 -1
- data/gemfiles/rails.7.0.activerecord.gemfile +2 -1
- data/gemfiles/{rails.5.2.activerecord.gemfile → rails.7.1.activerecord.gemfile} +6 -3
- data/lib/chewy/config.rb +22 -14
- data/lib/chewy/elastic_client.rb +31 -0
- data/lib/chewy/errors.rb +5 -2
- data/lib/chewy/fields/base.rb +1 -1
- data/lib/chewy/fields/root.rb +1 -1
- data/lib/chewy/index/adapter/active_record.rb +13 -3
- data/lib/chewy/index/adapter/object.rb +3 -3
- data/lib/chewy/index/adapter/orm.rb +2 -2
- data/lib/chewy/index/crutch.rb +15 -7
- data/lib/chewy/index/import/bulk_builder.rb +6 -7
- data/lib/chewy/index/import/routine.rb +1 -1
- data/lib/chewy/index/import.rb +31 -4
- data/lib/chewy/index/observe/active_record_methods.rb +87 -0
- data/lib/chewy/index/observe/callback.rb +34 -0
- data/lib/chewy/index/observe.rb +3 -58
- data/lib/chewy/index/syncer.rb +1 -1
- data/lib/chewy/index.rb +25 -0
- data/lib/chewy/journal.rb +17 -6
- data/lib/chewy/log_subscriber.rb +5 -1
- data/lib/chewy/minitest/helpers.rb +1 -1
- data/lib/chewy/minitest/search_index_receiver.rb +3 -1
- data/lib/chewy/rake_helper.rb +74 -13
- data/lib/chewy/rspec/update_index.rb +13 -6
- data/lib/chewy/runtime/version.rb +1 -1
- data/lib/chewy/search/parameters/collapse.rb +16 -0
- data/lib/chewy/search/parameters/indices.rb +1 -1
- data/lib/chewy/search/parameters/knn.rb +16 -0
- data/lib/chewy/search/parameters/storage.rb +1 -1
- data/lib/chewy/search/parameters.rb +3 -3
- data/lib/chewy/search/request.rb +45 -11
- data/lib/chewy/search.rb +6 -3
- data/lib/chewy/stash.rb +3 -3
- data/lib/chewy/strategy/atomic_no_refresh.rb +18 -0
- data/lib/chewy/strategy/base.rb +10 -0
- data/lib/chewy/strategy/delayed_sidekiq/scheduler.rb +168 -0
- data/lib/chewy/strategy/delayed_sidekiq/worker.rb +76 -0
- data/lib/chewy/strategy/delayed_sidekiq.rb +30 -0
- data/lib/chewy/strategy/lazy_sidekiq.rb +64 -0
- data/lib/chewy/strategy.rb +3 -0
- data/lib/chewy/version.rb +1 -1
- data/lib/chewy.rb +5 -8
- data/lib/tasks/chewy.rake +17 -1
- data/migration_guide.md +1 -1
- data/spec/chewy/config_spec.rb +2 -2
- data/spec/chewy/elastic_client_spec.rb +26 -0
- data/spec/chewy/fields/base_spec.rb +1 -0
- data/spec/chewy/index/actions_spec.rb +4 -4
- data/spec/chewy/index/adapter/active_record_spec.rb +62 -0
- data/spec/chewy/index/import/bulk_builder_spec.rb +7 -3
- data/spec/chewy/index/import_spec.rb +16 -3
- data/spec/chewy/index/observe/active_record_methods_spec.rb +68 -0
- data/spec/chewy/index/observe/callback_spec.rb +139 -0
- data/spec/chewy/index/observe_spec.rb +27 -0
- data/spec/chewy/journal_spec.rb +13 -49
- data/spec/chewy/minitest/helpers_spec.rb +3 -3
- data/spec/chewy/minitest/search_index_receiver_spec.rb +6 -4
- data/spec/chewy/rake_helper_spec.rb +155 -4
- data/spec/chewy/rspec/helpers_spec.rb +1 -1
- data/spec/chewy/search/pagination/kaminari_examples.rb +1 -1
- data/spec/chewy/search/pagination/kaminari_spec.rb +1 -1
- data/spec/chewy/search/parameters/collapse_spec.rb +5 -0
- data/spec/chewy/search/parameters/knn_spec.rb +5 -0
- data/spec/chewy/search/request_spec.rb +37 -0
- data/spec/chewy/search_spec.rb +9 -0
- data/spec/chewy/strategy/active_job_spec.rb +8 -8
- data/spec/chewy/strategy/atomic_no_refresh_spec.rb +60 -0
- data/spec/chewy/strategy/delayed_sidekiq_spec.rb +208 -0
- data/spec/chewy/strategy/lazy_sidekiq_spec.rb +214 -0
- data/spec/chewy/strategy/sidekiq_spec.rb +4 -4
- data/spec/chewy_spec.rb +7 -4
- data/spec/spec_helper.rb +1 -1
- metadata +32 -253
- data/gemfiles/rails.6.0.activerecord.gemfile +0 -11
data/lib/chewy/journal.rb
CHANGED
|
@@ -16,14 +16,17 @@ module Chewy
|
|
|
16
16
|
# specified indexes.
|
|
17
17
|
#
|
|
18
18
|
# @param since_time [Time, DateTime] timestamp from which changes will be applied
|
|
19
|
-
# @param
|
|
19
|
+
# @param fetch_limit [Int] amount of entries to be fetched on each cycle
|
|
20
20
|
# @return [Integer] the amount of journal entries found
|
|
21
|
-
def apply(since_time,
|
|
21
|
+
def apply(since_time, fetch_limit: 10, **import_options)
|
|
22
22
|
stage = 1
|
|
23
23
|
since_time -= 1
|
|
24
24
|
count = 0
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
|
|
26
|
+
total_count = entries(since_time, fetch_limit).total_count
|
|
27
|
+
|
|
28
|
+
while count < total_count
|
|
29
|
+
entries = entries(since_time, fetch_limit).to_a.presence or break
|
|
27
30
|
count += entries.size
|
|
28
31
|
groups = reference_groups(entries)
|
|
29
32
|
ActiveSupport::Notifications.instrument 'apply_journal.chewy', stage: stage, groups: groups
|
|
@@ -40,12 +43,20 @@ module Chewy
|
|
|
40
43
|
#
|
|
41
44
|
# @param until_time [Time, DateTime] time to clean up until it
|
|
42
45
|
# @return [Hash] delete_by_query ES API call result
|
|
43
|
-
def clean(until_time = nil)
|
|
44
|
-
Chewy::Stash::Journal.clean(
|
|
46
|
+
def clean(until_time = nil, delete_by_query_options: {})
|
|
47
|
+
Chewy::Stash::Journal.clean(
|
|
48
|
+
until_time,
|
|
49
|
+
only: @only,
|
|
50
|
+
delete_by_query_options: delete_by_query_options.merge(refresh: false)
|
|
51
|
+
)
|
|
45
52
|
end
|
|
46
53
|
|
|
47
54
|
private
|
|
48
55
|
|
|
56
|
+
def entries(since_time, fetch_limit)
|
|
57
|
+
Chewy::Stash::Journal.entries(since_time, only: @only).order(:created_at).limit(fetch_limit)
|
|
58
|
+
end
|
|
59
|
+
|
|
49
60
|
def reference_groups(entries)
|
|
50
61
|
entries.group_by(&:index_name)
|
|
51
62
|
.transform_keys { |index_name| Chewy.derive_name(index_name) }
|
data/lib/chewy/log_subscriber.rb
CHANGED
|
@@ -24,7 +24,11 @@ module Chewy
|
|
|
24
24
|
|
|
25
25
|
subject = payload[:type].presence || payload[:index]
|
|
26
26
|
action = "#{subject} #{action} (#{event.duration.round(1)}ms)"
|
|
27
|
-
action =
|
|
27
|
+
action = if ActiveSupport.version >= Gem::Version.new('7.1')
|
|
28
|
+
color(action, GREEN, bold: true)
|
|
29
|
+
else
|
|
30
|
+
color(action, GREEN, true)
|
|
31
|
+
end
|
|
28
32
|
|
|
29
33
|
debug(" #{action} #{description}")
|
|
30
34
|
end
|
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
# The class will capture the data from the *param on the Chewy::Index.bulk method and
|
|
7
7
|
# aggregate the data for test analysis.
|
|
8
8
|
class SearchIndexReceiver
|
|
9
|
+
MUTATION_FOR_CLASS = Struct.new(:indexes, :deletes, keyword_init: true)
|
|
10
|
+
|
|
9
11
|
def initialize
|
|
10
12
|
@mutations = {}
|
|
11
13
|
end
|
|
@@ -71,6 +73,6 @@ private
|
|
|
71
73
|
# @param index [Chewy::Index] the index to fetch.
|
|
72
74
|
# @return [#indexes, #deletes] an object with a list of indexes and a list of deletes.
|
|
73
75
|
def mutation_for(index)
|
|
74
|
-
@mutations[index] ||=
|
|
76
|
+
@mutations[index] ||= MUTATION_FOR_CLASS.new(indexes: [], deletes: [])
|
|
75
77
|
end
|
|
76
78
|
end
|
data/lib/chewy/rake_helper.rb
CHANGED
|
@@ -19,6 +19,9 @@ module Chewy
|
|
|
19
19
|
output.puts " Applying journal to #{targets}, #{count} entries, stage #{payload[:stage]}"
|
|
20
20
|
end
|
|
21
21
|
|
|
22
|
+
DELETE_BY_QUERY_OPTIONS = %w[WAIT_FOR_COMPLETION REQUESTS_PER_SECOND SCROLL_SIZE].freeze
|
|
23
|
+
FALSE_VALUES = %w[0 f false off].freeze
|
|
24
|
+
|
|
22
25
|
class << self
|
|
23
26
|
# Performs zero-downtime reindexing of all documents for the specified indexes
|
|
24
27
|
#
|
|
@@ -162,7 +165,7 @@ module Chewy
|
|
|
162
165
|
|
|
163
166
|
subscribed_task_stats(output) do
|
|
164
167
|
output.puts "Applying journal entries created after #{time}"
|
|
165
|
-
count = Chewy::Journal.new(
|
|
168
|
+
count = Chewy::Journal.new(journal_indexes_from(only: only, except: except)).apply(time)
|
|
166
169
|
output.puts 'No journal entries were created after the specified time' if count.zero?
|
|
167
170
|
end
|
|
168
171
|
end
|
|
@@ -181,12 +184,29 @@ module Chewy
|
|
|
181
184
|
# @param except [Array<Chewy::Index, String>, Chewy::Index, String] indexes to exclude from processing
|
|
182
185
|
# @param output [IO] output io for logging
|
|
183
186
|
# @return [Array<Chewy::Index>] indexes that were actually updated
|
|
184
|
-
def journal_clean(time: nil, only: nil, except: nil, output: $stdout)
|
|
187
|
+
def journal_clean(time: nil, only: nil, except: nil, delete_by_query_options: {}, output: $stdout)
|
|
185
188
|
subscribed_task_stats(output) do
|
|
186
189
|
output.puts "Cleaning journal entries created before #{time}" if time
|
|
187
|
-
response = Chewy::Journal.new(
|
|
188
|
-
|
|
189
|
-
|
|
190
|
+
response = Chewy::Journal.new(journal_indexes_from(only: only, except: except)).clean(time, delete_by_query_options: delete_by_query_options)
|
|
191
|
+
if response.key?('task')
|
|
192
|
+
output.puts "Task to cleanup the journal has been created, #{response['task']}"
|
|
193
|
+
else
|
|
194
|
+
count = response['deleted'] || response['_indices']['_all']['deleted']
|
|
195
|
+
output.puts "Cleaned up #{count} journal entries"
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
# Creates journal index.
|
|
201
|
+
#
|
|
202
|
+
# @example
|
|
203
|
+
# Chewy::RakeHelper.journal_create # creates journal
|
|
204
|
+
#
|
|
205
|
+
# @param output [IO] output io for logging
|
|
206
|
+
# @return Chewy::Index Returns instance of chewy index
|
|
207
|
+
def journal_create(output: $stdout)
|
|
208
|
+
subscribed_task_stats(output) do
|
|
209
|
+
Chewy::Stash::Journal.create!
|
|
190
210
|
end
|
|
191
211
|
end
|
|
192
212
|
|
|
@@ -228,6 +248,44 @@ module Chewy
|
|
|
228
248
|
end
|
|
229
249
|
end
|
|
230
250
|
|
|
251
|
+
# Reads options that are required to run journal cleanup asynchronously from ENV hash
|
|
252
|
+
# @see https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-delete-by-query.html
|
|
253
|
+
#
|
|
254
|
+
# @example
|
|
255
|
+
# Chewy::RakeHelper.delete_by_query_options_from_env({'WAIT_FOR_COMPLETION' => 'false','REQUESTS_PER_SECOND' => '10','SCROLL_SIZE' => '5000'})
|
|
256
|
+
# # => { wait_for_completion: false, requests_per_second: 10.0, scroll_size: 5000 }
|
|
257
|
+
#
|
|
258
|
+
def delete_by_query_options_from_env(env)
|
|
259
|
+
env
|
|
260
|
+
.slice(*DELETE_BY_QUERY_OPTIONS)
|
|
261
|
+
.transform_keys { |k| k.downcase.to_sym }
|
|
262
|
+
.to_h do |key, value|
|
|
263
|
+
case key
|
|
264
|
+
when :wait_for_completion then [key, !FALSE_VALUES.include?(value.downcase)]
|
|
265
|
+
when :requests_per_second then [key, value.to_f]
|
|
266
|
+
when :scroll_size then [key, value.to_i]
|
|
267
|
+
end
|
|
268
|
+
end
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
def create_missing_indexes!(output: $stdout, env: ENV)
|
|
272
|
+
subscribed_task_stats(output) do
|
|
273
|
+
Chewy.eager_load!
|
|
274
|
+
all_indexes = Chewy::Index.descendants
|
|
275
|
+
all_indexes -= [Chewy::Stash::Journal] unless Chewy.configuration[:journal]
|
|
276
|
+
all_indexes.each do |index|
|
|
277
|
+
if index.exists?
|
|
278
|
+
output.puts "#{index.name} already exists, skipping" if env['VERBOSE']
|
|
279
|
+
next
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
index.create!
|
|
283
|
+
|
|
284
|
+
output.puts "#{index.name} index successfully created"
|
|
285
|
+
end
|
|
286
|
+
end
|
|
287
|
+
end
|
|
288
|
+
|
|
231
289
|
def normalize_indexes(*identifiers)
|
|
232
290
|
identifiers.flatten(1).map { |identifier| normalize_index(identifier) }
|
|
233
291
|
end
|
|
@@ -243,11 +301,18 @@ module Chewy
|
|
|
243
301
|
ActiveSupport::Notifications.subscribed(JOURNAL_CALLBACK.curry[output], 'apply_journal.chewy') do
|
|
244
302
|
ActiveSupport::Notifications.subscribed(IMPORT_CALLBACK.curry[output], 'import_objects.chewy', &block)
|
|
245
303
|
end
|
|
304
|
+
ensure
|
|
246
305
|
output.puts "Total: #{human_duration(Time.now - start)}"
|
|
247
306
|
end
|
|
248
307
|
|
|
249
308
|
private
|
|
250
309
|
|
|
310
|
+
def journal_indexes_from(only: nil, except: nil)
|
|
311
|
+
return if Array.wrap(only).empty? && Array.wrap(except).empty?
|
|
312
|
+
|
|
313
|
+
indexes_from(only: only, except: except)
|
|
314
|
+
end
|
|
315
|
+
|
|
251
316
|
def indexes_from(only: nil, except: nil)
|
|
252
317
|
indexes = if only.present?
|
|
253
318
|
normalize_indexes(Array.wrap(only))
|
|
@@ -255,11 +320,7 @@ module Chewy
|
|
|
255
320
|
all_indexes
|
|
256
321
|
end
|
|
257
322
|
|
|
258
|
-
indexes
|
|
259
|
-
indexes - normalize_indexes(Array.wrap(except))
|
|
260
|
-
else
|
|
261
|
-
indexes
|
|
262
|
-
end
|
|
323
|
+
indexes -= normalize_indexes(Array.wrap(except)) if except.present?
|
|
263
324
|
|
|
264
325
|
indexes.sort_by(&:derivable_name)
|
|
265
326
|
end
|
|
@@ -282,9 +343,9 @@ module Chewy
|
|
|
282
343
|
return if journal_exists?
|
|
283
344
|
|
|
284
345
|
output.puts "############################################################\n" \
|
|
285
|
-
"WARN: You are risking to lose some changes during the reset.\n" \
|
|
286
|
-
"
|
|
287
|
-
"
|
|
346
|
+
"WARN: You are risking to lose some changes during the reset.\n " \
|
|
347
|
+
"Please consider enabling journaling.\n " \
|
|
348
|
+
"See https://github.com/toptal/chewy#journaling\n" \
|
|
288
349
|
'############################################################'
|
|
289
350
|
end
|
|
290
351
|
|
|
@@ -88,6 +88,11 @@ RSpec::Matchers.define :update_index do |index_name, options = {}| # rubocop:dis
|
|
|
88
88
|
@only = true
|
|
89
89
|
end
|
|
90
90
|
|
|
91
|
+
# Expect import to be called with refresh=false parameter
|
|
92
|
+
chain(:no_refresh) do
|
|
93
|
+
@no_refresh = true
|
|
94
|
+
end
|
|
95
|
+
|
|
91
96
|
def supports_block_expectations?
|
|
92
97
|
true
|
|
93
98
|
end
|
|
@@ -100,11 +105,13 @@ RSpec::Matchers.define :update_index do |index_name, options = {}| # rubocop:dis
|
|
|
100
105
|
|
|
101
106
|
index = Chewy.derive_name(index_name)
|
|
102
107
|
if defined?(Mocha) && RSpec.configuration.mock_framework.to_s == 'RSpec::Core::MockingAdapters::Mocha'
|
|
103
|
-
|
|
108
|
+
params_matcher = @no_refresh ? has_entry(refresh: false) : any_parameters
|
|
109
|
+
Chewy::Index::Import::BulkRequest.stubs(:new).with(index, params_matcher).returns(mock_bulk_request)
|
|
104
110
|
else
|
|
105
|
-
mocked_already =
|
|
111
|
+
mocked_already = RSpec::Mocks.space.proxy_for(Chewy::Index::Import::BulkRequest).method_double_if_exists_for_message(:new)
|
|
106
112
|
allow(Chewy::Index::Import::BulkRequest).to receive(:new).and_call_original unless mocked_already
|
|
107
|
-
|
|
113
|
+
params_matcher = @no_refresh ? hash_including(refresh: false) : any_args
|
|
114
|
+
allow(Chewy::Index::Import::BulkRequest).to receive(:new).with(index, params_matcher).and_return(mock_bulk_request)
|
|
108
115
|
end
|
|
109
116
|
|
|
110
117
|
Chewy.strategy(options[:strategy] || :atomic) { block.call }
|
|
@@ -146,7 +153,7 @@ RSpec::Matchers.define :update_index do |index_name, options = {}| # rubocop:dis
|
|
|
146
153
|
output = ''
|
|
147
154
|
|
|
148
155
|
if mock_bulk_request.updates.none?
|
|
149
|
-
output << "Expected index `#{index_name}` to be updated, but it was not\n"
|
|
156
|
+
output << "Expected index `#{index_name}` to be updated#{' with no refresh' if @no_refresh}, but it was not\n"
|
|
150
157
|
elsif @missed_reindex.present? || @missed_delete.present?
|
|
151
158
|
message = "Expected index `#{index_name}` "
|
|
152
159
|
message << [
|
|
@@ -213,7 +220,7 @@ RSpec::Matchers.define :update_index do |index_name, options = {}| # rubocop:dis
|
|
|
213
220
|
expected_count = options[:times] || options[:count]
|
|
214
221
|
expected_attributes = (options[:with] || options[:attributes] || {}).deep_symbolize_keys
|
|
215
222
|
|
|
216
|
-
args.flatten.
|
|
223
|
+
args.flatten.to_h do |document|
|
|
217
224
|
id = document.respond_to?(:id) ? document.id.to_s : document.to_s
|
|
218
225
|
[id, {
|
|
219
226
|
document: document,
|
|
@@ -222,7 +229,7 @@ RSpec::Matchers.define :update_index do |index_name, options = {}| # rubocop:dis
|
|
|
222
229
|
real_count: 0,
|
|
223
230
|
real_attributes: {}
|
|
224
231
|
}]
|
|
225
|
-
end
|
|
232
|
+
end
|
|
226
233
|
end
|
|
227
234
|
|
|
228
235
|
def compare_attributes(expected, real)
|
|
@@ -5,7 +5,7 @@ module Chewy
|
|
|
5
5
|
attr_reader :major, :minor, :patch
|
|
6
6
|
|
|
7
7
|
def initialize(version)
|
|
8
|
-
@major, @minor, @patch = *(version.to_s.split('.', 3) + [0] * 3).first(3).map(&:to_i)
|
|
8
|
+
@major, @minor, @patch = *(version.to_s.split('.', 3) + ([0] * 3)).first(3).map(&:to_i)
|
|
9
9
|
end
|
|
10
10
|
|
|
11
11
|
def to_s
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
require 'chewy/search/parameters/storage'
|
|
2
|
+
|
|
3
|
+
module Chewy
|
|
4
|
+
module Search
|
|
5
|
+
class Parameters
|
|
6
|
+
# Just a standard hash storage. Nothing to see here.
|
|
7
|
+
#
|
|
8
|
+
# @see Chewy::Search::Parameters::HashStorage
|
|
9
|
+
# @see Chewy::Search::Request#collapse
|
|
10
|
+
# @see https://www.elastic.co/guide/en/elasticsearch/reference/current/collapse-search-results.html
|
|
11
|
+
class Collapse < Storage
|
|
12
|
+
include HashStorage
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -17,7 +17,7 @@ module Chewy
|
|
|
17
17
|
# @param other [Chewy::Search::Parameters::Storage] any storage instance
|
|
18
18
|
# @return [true, false] the result of comparison
|
|
19
19
|
def ==(other)
|
|
20
|
-
super || other.class == self.class && other.render == render
|
|
20
|
+
super || (other.class == self.class && other.render == render)
|
|
21
21
|
end
|
|
22
22
|
|
|
23
23
|
# Just adds indices to indices.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
require 'chewy/search/parameters/storage'
|
|
2
|
+
|
|
3
|
+
module Chewy
|
|
4
|
+
module Search
|
|
5
|
+
class Parameters
|
|
6
|
+
# Just a standard hash storage. Nothing to see here.
|
|
7
|
+
#
|
|
8
|
+
# @see Chewy::Search::Parameters::HashStorage
|
|
9
|
+
# @see Chewy::Search::Request#knn
|
|
10
|
+
# @see https://www.elastic.co/guide/en/elasticsearch/reference/current/knn-search.html
|
|
11
|
+
class Knn < Storage
|
|
12
|
+
include HashStorage
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -35,7 +35,7 @@ module Chewy
|
|
|
35
35
|
# @param other [Chewy::Search::Parameters::Storage] any storage instance
|
|
36
36
|
# @return [true, false] the result of comparision
|
|
37
37
|
def ==(other)
|
|
38
|
-
super || other.class == self.class && other.value == value
|
|
38
|
+
super || (other.class == self.class && other.value == value)
|
|
39
39
|
end
|
|
40
40
|
|
|
41
41
|
# Replaces current value with normalized provided one. Doesn't
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
Dir.glob(File.join(File.dirname(__FILE__), 'parameters', 'concerns', '*.rb')).
|
|
2
|
-
Dir.glob(File.join(File.dirname(__FILE__), 'parameters', '*.rb')).
|
|
1
|
+
Dir.glob(File.join(File.dirname(__FILE__), 'parameters', 'concerns', '*.rb')).each { |f| require f }
|
|
2
|
+
Dir.glob(File.join(File.dirname(__FILE__), 'parameters', '*.rb')).each { |f| require f }
|
|
3
3
|
|
|
4
4
|
module Chewy
|
|
5
5
|
module Search
|
|
@@ -53,7 +53,7 @@ module Chewy
|
|
|
53
53
|
# @param other [Object] any object
|
|
54
54
|
# @return [true, false]
|
|
55
55
|
def ==(other)
|
|
56
|
-
super || other.is_a?(self.class) && compare_storages(other)
|
|
56
|
+
super || (other.is_a?(self.class) && compare_storages(other))
|
|
57
57
|
end
|
|
58
58
|
|
|
59
59
|
# Clones the specified storage, performs the operation
|
data/lib/chewy/search/request.rb
CHANGED
|
@@ -20,11 +20,11 @@ module Chewy
|
|
|
20
20
|
UNDEFINED = Class.new.freeze
|
|
21
21
|
EVERFIELDS = %w[_index _type _id _parent _routing].freeze
|
|
22
22
|
DELEGATED_METHODS = %i[
|
|
23
|
-
query filter post_filter order reorder docvalue_fields
|
|
23
|
+
query filter post_filter knn order reorder docvalue_fields
|
|
24
24
|
track_scores track_total_hits request_cache explain version profile
|
|
25
25
|
search_type preference limit offset terminate_after
|
|
26
26
|
timeout min_score source stored_fields search_after
|
|
27
|
-
load script_fields suggest aggs aggregations none
|
|
27
|
+
load script_fields suggest aggs aggregations collapse none
|
|
28
28
|
indices_boost rescore highlight total total_count
|
|
29
29
|
total_entries indices types delete_all count exists?
|
|
30
30
|
exist? find pluck scroll_batches scroll_hits
|
|
@@ -41,7 +41,7 @@ module Chewy
|
|
|
41
41
|
EXTRA_STORAGES = %i[aggs suggest].freeze
|
|
42
42
|
# An array of storage names that are changing the returned hist collection in any way.
|
|
43
43
|
WHERE_STORAGES = %i[
|
|
44
|
-
query filter post_filter none min_score rescore indices_boost
|
|
44
|
+
query filter post_filter knn none min_score rescore indices_boost collapse
|
|
45
45
|
].freeze
|
|
46
46
|
|
|
47
47
|
delegate :hits, :wrappers, :objects, :records, :documents,
|
|
@@ -509,7 +509,29 @@ module Chewy
|
|
|
509
509
|
# @see https://www.elastic.co/guide/en/elasticsearch/reference/current/multi-index.html#multi-index
|
|
510
510
|
# @param value [true, false, nil]
|
|
511
511
|
# @return [Chewy::Search::Request]
|
|
512
|
-
|
|
512
|
+
#
|
|
513
|
+
# @!method collapse(value)
|
|
514
|
+
# Replaces the value of the `collapse` request part.
|
|
515
|
+
#
|
|
516
|
+
# @example
|
|
517
|
+
# PlacesIndex.collapse(field: :name)
|
|
518
|
+
# # => <PlacesIndex::Query {..., :body=>{:collapse=>{"field"=>:name}}}>
|
|
519
|
+
# @see Chewy::Search::Parameters::Collapse
|
|
520
|
+
# @see https://www.elastic.co/guide/en/elasticsearch/reference/current/collapse-search-results.html
|
|
521
|
+
# @param value [Hash]
|
|
522
|
+
# @return [Chewy::Search::Request]
|
|
523
|
+
#
|
|
524
|
+
# @!method knn(value)
|
|
525
|
+
# Replaces the value of the `knn` request part.
|
|
526
|
+
#
|
|
527
|
+
# @example
|
|
528
|
+
# PlacesIndex.knn(field: :vector, query_vector: [4, 2], k: 5, num_candidates: 50)
|
|
529
|
+
# # => <PlacesIndex::Query {..., :body=>{:knn=>{"field"=>:vector, "query_vector"=>[4, 2], "k"=>5, "num_candidates"=>50}}}>
|
|
530
|
+
# @see Chewy::Search::Parameters::Knn
|
|
531
|
+
# @see https://www.elastic.co/guide/en/elasticsearch/reference/current/knn-search.html
|
|
532
|
+
# @param value [Hash]
|
|
533
|
+
# @return [Chewy::Search::Request]
|
|
534
|
+
%i[request_cache search_type preference timeout limit offset terminate_after min_score ignore_unavailable collapse knn].each do |name|
|
|
513
535
|
define_method name do |value|
|
|
514
536
|
modify(name) { replace!(value) }
|
|
515
537
|
end
|
|
@@ -800,8 +822,8 @@ module Chewy
|
|
|
800
822
|
# Returns a new scope containing only specified storages.
|
|
801
823
|
#
|
|
802
824
|
# @example
|
|
803
|
-
# PlacesIndex.limit(10).offset(10).order(:name).
|
|
804
|
-
# # => <PlacesIndex::Query {..., :body=>{:
|
|
825
|
+
# PlacesIndex.limit(10).offset(10).order(:name).only(:offset, :order)
|
|
826
|
+
# # => <PlacesIndex::Query {..., :body=>{:from=>10, :sort=>["name"]}}>
|
|
805
827
|
# @param values [Array<String, Symbol>]
|
|
806
828
|
# @return [Chewy::Search::Request] new scope
|
|
807
829
|
def only(*values)
|
|
@@ -811,8 +833,8 @@ module Chewy
|
|
|
811
833
|
# Returns a new scope containing all the storages except specified.
|
|
812
834
|
#
|
|
813
835
|
# @example
|
|
814
|
-
# PlacesIndex.limit(10).offset(10).order(:name).
|
|
815
|
-
# # => <PlacesIndex::Query {..., :body=>{:
|
|
836
|
+
# PlacesIndex.limit(10).offset(10).order(:name).except(:offset, :order)
|
|
837
|
+
# # => <PlacesIndex::Query {..., :body=>{:size=>10}}>
|
|
816
838
|
# @param values [Array<String, Symbol>]
|
|
817
839
|
# @return [Chewy::Search::Request] new scope
|
|
818
840
|
def except(*values)
|
|
@@ -951,10 +973,22 @@ module Chewy
|
|
|
951
973
|
#
|
|
952
974
|
# @see https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-delete-by-query.html
|
|
953
975
|
# @note The result hash is different for different API used.
|
|
954
|
-
# @param refresh [true, false]
|
|
976
|
+
# @param refresh [true, false] Refreshes all shards involved in the delete by query
|
|
977
|
+
# @param wait_for_completion [true, false] wait for request completion or run it asynchronously
|
|
978
|
+
# and return task reference at `.tasks/task/${taskId}`.
|
|
979
|
+
# @param requests_per_second [Float] The throttle for this request in sub-requests per second
|
|
980
|
+
# @param scroll_size [Integer] Size of the scroll request that powers the operation
|
|
981
|
+
|
|
955
982
|
# @return [Hash] the result of query execution
|
|
956
|
-
def delete_all(refresh: true)
|
|
957
|
-
request_body = only(WHERE_STORAGES).render.merge(
|
|
983
|
+
def delete_all(refresh: true, wait_for_completion: nil, requests_per_second: nil, scroll_size: nil)
|
|
984
|
+
request_body = only(WHERE_STORAGES).render.merge(
|
|
985
|
+
{
|
|
986
|
+
refresh: refresh,
|
|
987
|
+
wait_for_completion: wait_for_completion,
|
|
988
|
+
requests_per_second: requests_per_second,
|
|
989
|
+
scroll_size: scroll_size
|
|
990
|
+
}.compact
|
|
991
|
+
)
|
|
958
992
|
ActiveSupport::Notifications.instrument 'delete_query.chewy', notification_payload(request: request_body) do
|
|
959
993
|
request_body[:body] = {query: {match_all: {}}} if request_body[:body].empty?
|
|
960
994
|
Chewy.client.delete_by_query(request_body)
|
data/lib/chewy/search.rb
CHANGED
|
@@ -56,7 +56,7 @@ module Chewy
|
|
|
56
56
|
#
|
|
57
57
|
# @example
|
|
58
58
|
# PlacesIndex.query(match: {name: 'Moscow'})
|
|
59
|
-
|
|
59
|
+
def method_missing(name, *args, &block)
|
|
60
60
|
if search_class::DELEGATED_METHODS.include?(name)
|
|
61
61
|
all.send(name, *args, &block)
|
|
62
62
|
else
|
|
@@ -84,9 +84,12 @@ module Chewy
|
|
|
84
84
|
def delegate_scoped(source, destination, methods)
|
|
85
85
|
methods.each do |method|
|
|
86
86
|
destination.class_eval do
|
|
87
|
-
define_method method do |*args, &block|
|
|
88
|
-
scoping
|
|
87
|
+
define_method method do |*args, **kwargs, &block|
|
|
88
|
+
scoping do
|
|
89
|
+
source.public_send(method, *args, **kwargs, &block)
|
|
90
|
+
end
|
|
89
91
|
end
|
|
92
|
+
method
|
|
90
93
|
end
|
|
91
94
|
end
|
|
92
95
|
end
|
data/lib/chewy/stash.rb
CHANGED
|
@@ -28,12 +28,12 @@ module Chewy
|
|
|
28
28
|
# Cleans up all the journal entries until the specified time. If nothing is
|
|
29
29
|
# specified - cleans up everything.
|
|
30
30
|
#
|
|
31
|
-
# @param
|
|
31
|
+
# @param until_time [Time, DateTime] Clean everything before that date
|
|
32
32
|
# @param only [Chewy::Index, Array<Chewy::Index>] indexes to clean up journal entries for
|
|
33
|
-
def self.clean(until_time = nil, only: [])
|
|
33
|
+
def self.clean(until_time = nil, only: [], delete_by_query_options: {})
|
|
34
34
|
scope = self.for(only)
|
|
35
35
|
scope = scope.filter(range: {created_at: {lte: until_time}}) if until_time
|
|
36
|
-
scope.delete_all
|
|
36
|
+
scope.delete_all(**delete_by_query_options)
|
|
37
37
|
end
|
|
38
38
|
|
|
39
39
|
# Selects all the journal entries for the specified indices.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
module Chewy
|
|
2
|
+
class Strategy
|
|
3
|
+
# This strategy works like atomic but import objects with `refresh=false` parameter.
|
|
4
|
+
#
|
|
5
|
+
# Chewy.strategy(:atomic_no_refresh) do
|
|
6
|
+
# User.all.map(&:save) # Does nothing here
|
|
7
|
+
# Post.all.map(&:save) # And here
|
|
8
|
+
# # It imports all the changed users and posts right here
|
|
9
|
+
# # before block leaving with bulk ES API, kinda optimization
|
|
10
|
+
# end
|
|
11
|
+
#
|
|
12
|
+
class AtomicNoRefresh < Atomic
|
|
13
|
+
def leave
|
|
14
|
+
@stash.all? { |type, ids| type.import!(ids, refresh: false) }
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
data/lib/chewy/strategy/base.rb
CHANGED
|
@@ -22,6 +22,16 @@ module Chewy
|
|
|
22
22
|
# strategies stack
|
|
23
23
|
#
|
|
24
24
|
def leave; end
|
|
25
|
+
|
|
26
|
+
# This method called when some model record is created or updated.
|
|
27
|
+
# Normally it will just evaluate all the Chewy callbacks and pass results
|
|
28
|
+
# to current strategy's update method.
|
|
29
|
+
# However it's possible to override it to achieve delayed evaluation of
|
|
30
|
+
# callbacks, e.g. using sidekiq.
|
|
31
|
+
#
|
|
32
|
+
def update_chewy_indices(object)
|
|
33
|
+
object.run_chewy_callbacks
|
|
34
|
+
end
|
|
25
35
|
end
|
|
26
36
|
end
|
|
27
37
|
end
|