chewy 6.0.0 → 7.5.1
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/ISSUE_TEMPLATE/bug_report.md +39 -0
- data/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
- data/.github/PULL_REQUEST_TEMPLATE.md +16 -0
- data/.github/dependabot.yml +42 -0
- data/.github/workflows/ruby.yml +48 -0
- data/.rubocop.yml +16 -8
- data/.rubocop_todo.yml +110 -22
- data/CHANGELOG.md +385 -105
- data/CODE_OF_CONDUCT.md +14 -0
- data/CONTRIBUTING.md +63 -0
- data/Gemfile +4 -10
- data/Guardfile +3 -1
- data/README.md +494 -275
- data/chewy.gemspec +5 -20
- data/gemfiles/base.gemfile +12 -0
- data/gemfiles/rails.6.1.activerecord.gemfile +10 -15
- data/gemfiles/rails.7.0.activerecord.gemfile +14 -0
- data/gemfiles/rails.7.1.activerecord.gemfile +14 -0
- data/lib/chewy/config.rb +58 -50
- data/lib/chewy/elastic_client.rb +31 -0
- data/lib/chewy/errors.rb +7 -10
- data/lib/chewy/fields/base.rb +79 -13
- data/lib/chewy/fields/root.rb +4 -14
- data/lib/chewy/index/actions.rb +54 -37
- data/lib/chewy/{type → index}/adapter/active_record.rb +30 -6
- data/lib/chewy/{type → index}/adapter/base.rb +2 -3
- data/lib/chewy/{type → index}/adapter/object.rb +27 -31
- data/lib/chewy/{type → index}/adapter/orm.rb +17 -18
- data/lib/chewy/index/aliases.rb +14 -5
- data/lib/chewy/index/crutch.rb +40 -0
- data/lib/chewy/index/import/bulk_builder.rb +311 -0
- data/lib/chewy/{type → index}/import/bulk_request.rb +6 -7
- data/lib/chewy/{type → index}/import/journal_builder.rb +11 -12
- data/lib/chewy/{type → index}/import/routine.rb +18 -17
- data/lib/chewy/{type → index}/import.rb +76 -32
- data/lib/chewy/{type → index}/mapping.rb +29 -34
- 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 +17 -0
- data/lib/chewy/index/specification.rb +1 -0
- data/lib/chewy/{type → index}/syncer.rb +59 -59
- data/lib/chewy/{type → index}/witchcraft.rb +11 -7
- data/lib/chewy/{type → index}/wrapper.rb +2 -2
- data/lib/chewy/index.rb +67 -94
- data/lib/chewy/journal.rb +25 -14
- data/lib/chewy/log_subscriber.rb +5 -1
- data/lib/chewy/minitest/helpers.rb +86 -13
- data/lib/chewy/minitest/search_index_receiver.rb +24 -26
- data/lib/chewy/railtie.rb +6 -20
- data/lib/chewy/rake_helper.rb +169 -113
- data/lib/chewy/rspec/build_query.rb +12 -0
- data/lib/chewy/rspec/helpers.rb +55 -0
- data/lib/chewy/rspec/update_index.rb +55 -44
- data/lib/chewy/rspec.rb +2 -0
- data/lib/chewy/runtime/version.rb +1 -1
- data/lib/chewy/runtime.rb +1 -1
- data/lib/chewy/search/loader.rb +19 -41
- data/lib/chewy/search/parameters/collapse.rb +16 -0
- data/lib/chewy/search/parameters/concerns/query_storage.rb +2 -2
- data/lib/chewy/search/parameters/ignore_unavailable.rb +27 -0
- data/lib/chewy/search/parameters/indices.rb +13 -58
- data/lib/chewy/search/parameters/knn.rb +16 -0
- data/lib/chewy/search/parameters/order.rb +6 -19
- data/lib/chewy/search/parameters/source.rb +5 -1
- data/lib/chewy/search/parameters/storage.rb +1 -1
- data/lib/chewy/search/parameters/track_total_hits.rb +16 -0
- data/lib/chewy/search/parameters.rb +6 -4
- data/lib/chewy/search/query_proxy.rb +9 -2
- data/lib/chewy/search/request.rb +169 -134
- data/lib/chewy/search/response.rb +5 -5
- data/lib/chewy/search/scoping.rb +7 -8
- data/lib/chewy/search/scrolling.rb +13 -13
- data/lib/chewy/search.rb +9 -19
- data/lib/chewy/stash.rb +19 -30
- data/lib/chewy/strategy/active_job.rb +1 -1
- 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 +151 -0
- data/lib/chewy/strategy/delayed_sidekiq/worker.rb +52 -0
- data/lib/chewy/strategy/delayed_sidekiq.rb +30 -0
- data/lib/chewy/strategy/lazy_sidekiq.rb +64 -0
- data/lib/chewy/strategy/sidekiq.rb +2 -1
- data/lib/chewy/strategy.rb +6 -19
- data/lib/chewy/version.rb +1 -1
- data/lib/chewy.rb +39 -86
- data/lib/generators/chewy/install_generator.rb +1 -1
- data/lib/tasks/chewy.rake +36 -32
- data/migration_guide.md +46 -8
- data/spec/chewy/config_spec.rb +14 -39
- data/spec/chewy/elastic_client_spec.rb +26 -0
- data/spec/chewy/fields/base_spec.rb +432 -147
- data/spec/chewy/fields/root_spec.rb +20 -28
- data/spec/chewy/fields/time_fields_spec.rb +5 -5
- data/spec/chewy/index/actions_spec.rb +368 -59
- data/spec/chewy/{type → index}/adapter/active_record_spec.rb +156 -40
- data/spec/chewy/{type → index}/adapter/object_spec.rb +21 -6
- data/spec/chewy/index/aliases_spec.rb +3 -3
- data/spec/chewy/index/import/bulk_builder_spec.rb +494 -0
- data/spec/chewy/{type → index}/import/bulk_request_spec.rb +5 -12
- data/spec/chewy/{type → index}/import/journal_builder_spec.rb +9 -19
- data/spec/chewy/{type → index}/import/routine_spec.rb +19 -19
- data/spec/chewy/{type → index}/import_spec.rb +164 -98
- data/spec/chewy/index/mapping_spec.rb +135 -0
- 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 +143 -0
- data/spec/chewy/index/settings_spec.rb +3 -1
- data/spec/chewy/index/specification_spec.rb +20 -30
- data/spec/chewy/{type → index}/syncer_spec.rb +14 -19
- data/spec/chewy/{type → index}/witchcraft_spec.rb +20 -22
- data/spec/chewy/index/wrapper_spec.rb +100 -0
- data/spec/chewy/index_spec.rb +60 -105
- data/spec/chewy/journal_spec.rb +25 -74
- data/spec/chewy/minitest/helpers_spec.rb +123 -15
- data/spec/chewy/minitest/search_index_receiver_spec.rb +28 -30
- data/spec/chewy/multi_search_spec.rb +4 -5
- data/spec/chewy/rake_helper_spec.rb +315 -55
- data/spec/chewy/rspec/build_query_spec.rb +34 -0
- data/spec/chewy/rspec/helpers_spec.rb +61 -0
- data/spec/chewy/rspec/update_index_spec.rb +74 -71
- data/spec/chewy/runtime_spec.rb +2 -2
- data/spec/chewy/search/loader_spec.rb +19 -53
- data/spec/chewy/search/pagination/kaminari_examples.rb +4 -6
- data/spec/chewy/search/pagination/kaminari_spec.rb +2 -2
- data/spec/chewy/search/parameters/collapse_spec.rb +5 -0
- data/spec/chewy/search/parameters/ignore_unavailable_spec.rb +67 -0
- data/spec/chewy/search/parameters/indices_spec.rb +26 -117
- data/spec/chewy/search/parameters/knn_spec.rb +5 -0
- data/spec/chewy/search/parameters/order_spec.rb +18 -11
- data/spec/chewy/search/parameters/query_storage_examples.rb +67 -21
- data/spec/chewy/search/parameters/search_after_spec.rb +4 -1
- data/spec/chewy/search/parameters/source_spec.rb +8 -2
- data/spec/chewy/search/parameters/track_total_hits_spec.rb +5 -0
- data/spec/chewy/search/parameters_spec.rb +18 -4
- data/spec/chewy/search/query_proxy_spec.rb +68 -17
- data/spec/chewy/search/request_spec.rb +292 -110
- data/spec/chewy/search/response_spec.rb +12 -12
- data/spec/chewy/search/scrolling_spec.rb +10 -17
- data/spec/chewy/search_spec.rb +40 -34
- data/spec/chewy/stash_spec.rb +9 -21
- data/spec/chewy/strategy/active_job_spec.rb +16 -16
- data/spec/chewy/strategy/atomic_no_refresh_spec.rb +60 -0
- data/spec/chewy/strategy/atomic_spec.rb +9 -10
- data/spec/chewy/strategy/delayed_sidekiq_spec.rb +202 -0
- data/spec/chewy/strategy/lazy_sidekiq_spec.rb +214 -0
- data/spec/chewy/strategy/sidekiq_spec.rb +12 -12
- data/spec/chewy/strategy_spec.rb +19 -15
- data/spec/chewy_spec.rb +24 -107
- data/spec/spec_helper.rb +3 -22
- data/spec/support/active_record.rb +25 -7
- metadata +78 -339
- data/.circleci/config.yml +0 -240
- data/Appraisals +0 -81
- data/gemfiles/rails.5.2.activerecord.gemfile +0 -17
- data/gemfiles/rails.5.2.mongoid.6.4.gemfile +0 -17
- data/gemfiles/rails.6.0.activerecord.gemfile +0 -17
- data/gemfiles/sequel.4.45.gemfile +0 -11
- data/lib/chewy/backports/deep_dup.rb +0 -46
- data/lib/chewy/backports/duplicable.rb +0 -91
- data/lib/chewy/search/pagination/will_paginate.rb +0 -43
- data/lib/chewy/search/parameters/types.rb +0 -20
- data/lib/chewy/strategy/resque.rb +0 -27
- data/lib/chewy/strategy/shoryuken.rb +0 -40
- data/lib/chewy/type/actions.rb +0 -43
- data/lib/chewy/type/adapter/mongoid.rb +0 -67
- data/lib/chewy/type/adapter/sequel.rb +0 -93
- data/lib/chewy/type/crutch.rb +0 -32
- data/lib/chewy/type/import/bulk_builder.rb +0 -122
- data/lib/chewy/type/observe.rb +0 -82
- data/lib/chewy/type.rb +0 -120
- data/lib/sequel/plugins/chewy_observe.rb +0 -63
- data/spec/chewy/search/pagination/will_paginate_examples.rb +0 -63
- data/spec/chewy/search/pagination/will_paginate_spec.rb +0 -23
- data/spec/chewy/search/parameters/types_spec.rb +0 -5
- data/spec/chewy/strategy/resque_spec.rb +0 -46
- data/spec/chewy/strategy/shoryuken_spec.rb +0 -70
- data/spec/chewy/type/actions_spec.rb +0 -50
- data/spec/chewy/type/adapter/mongoid_spec.rb +0 -372
- data/spec/chewy/type/adapter/sequel_spec.rb +0 -472
- data/spec/chewy/type/import/bulk_builder_spec.rb +0 -194
- data/spec/chewy/type/mapping_spec.rb +0 -175
- data/spec/chewy/type/observe_spec.rb +0 -137
- data/spec/chewy/type/wrapper_spec.rb +0 -100
- data/spec/chewy/type_spec.rb +0 -55
- data/spec/support/mongoid.rb +0 -93
- data/spec/support/sequel.rb +0 -80
data/lib/chewy/rake_helper.rb
CHANGED
@@ -3,14 +3,12 @@ module Chewy
|
|
3
3
|
IMPORT_CALLBACK = lambda do |output, _name, start, finish, _id, payload|
|
4
4
|
duration = (finish - start).ceil
|
5
5
|
stats = payload.fetch(:import, {}).map { |key, count| "#{key} #{count}" }.join(', ')
|
6
|
-
output.puts " Imported #{payload[:
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
output.puts " on #{documents.count} documents: #{documents}"
|
13
|
-
end
|
6
|
+
output.puts " Imported #{payload[:index]} in #{human_duration(duration)}, stats: #{stats}"
|
7
|
+
payload[:errors]&.each do |action, errors|
|
8
|
+
output.puts " #{action.to_s.humanize} errors:"
|
9
|
+
errors.each do |error, documents|
|
10
|
+
output.puts " `#{error}`"
|
11
|
+
output.puts " on #{documents.count} documents: #{documents}"
|
14
12
|
end
|
15
13
|
end
|
16
14
|
end
|
@@ -21,6 +19,9 @@ module Chewy
|
|
21
19
|
output.puts " Applying journal to #{targets}, #{count} entries, stage #{payload[:stage]}"
|
22
20
|
end
|
23
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
|
+
|
24
25
|
class << self
|
25
26
|
# Performs zero-downtime reindexing of all documents for the specified indexes
|
26
27
|
#
|
@@ -36,7 +37,9 @@ module Chewy
|
|
36
37
|
# @param parallel [true, Integer, Hash] any acceptable parallel options for import
|
37
38
|
# @param output [IO] output io for logging
|
38
39
|
# @return [Array<Chewy::Index>] indexes that were reset
|
39
|
-
def reset(only: nil, except: nil, parallel: nil, output:
|
40
|
+
def reset(only: nil, except: nil, parallel: nil, output: $stdout)
|
41
|
+
warn_missing_index(output)
|
42
|
+
|
40
43
|
subscribed_task_stats(output) do
|
41
44
|
indexes_from(only: only, except: except).each do |index|
|
42
45
|
reset_one(index, output, parallel: parallel)
|
@@ -59,7 +62,9 @@ module Chewy
|
|
59
62
|
# @param parallel [true, Integer, Hash] any acceptable parallel options for import
|
60
63
|
# @param output [IO] output io for logging
|
61
64
|
# @return [Array<Chewy::Index>] indexes that were actually reset
|
62
|
-
def upgrade(only: nil, except: nil, parallel: nil, output:
|
65
|
+
def upgrade(only: nil, except: nil, parallel: nil, output: $stdout)
|
66
|
+
warn_missing_index(output)
|
67
|
+
|
63
68
|
subscribed_task_stats(output) do
|
64
69
|
indexes = indexes_from(only: only, except: except)
|
65
70
|
|
@@ -87,23 +92,21 @@ module Chewy
|
|
87
92
|
#
|
88
93
|
# @example
|
89
94
|
# Chewy::RakeHelper.update # updates everything
|
90
|
-
# Chewy::RakeHelper.update(only: 'places') # updates only PlacesIndex
|
91
|
-
# Chewy::RakeHelper.update(
|
92
|
-
# Chewy::RakeHelper.update(except: PlacesIndex::Country) # updates everything, but PlacesIndex::Country
|
93
|
-
# Chewy::RakeHelper.update(only: 'places', except: 'places#country') # updates PlacesIndex::City only
|
95
|
+
# Chewy::RakeHelper.update(only: 'places') # updates only PlacesIndex
|
96
|
+
# Chewy::RakeHelper.update(except: PlacesIndex) # updates everything, but PlacesIndex
|
94
97
|
#
|
95
|
-
# @param only [Array<Chewy::Index,
|
96
|
-
# @param except [Array<Chewy::Index,
|
98
|
+
# @param only [Array<Chewy::Index, String>, Chewy::Index, String] indexes to update; if nothing is passed - uses all the indexes defined in the app
|
99
|
+
# @param except [Array<Chewy::Index, String>, Chewy::Index, String] indexes to exclude from processing
|
97
100
|
# @param parallel [true, Integer, Hash] any acceptable parallel options for import
|
98
101
|
# @param output [IO] output io for logging
|
99
|
-
# @return [Array<Chewy::
|
100
|
-
def update(only: nil, except: nil, parallel: nil, output:
|
102
|
+
# @return [Array<Chewy::Index>] indexes that were actually updated
|
103
|
+
def update(only: nil, except: nil, parallel: nil, output: $stdout)
|
101
104
|
subscribed_task_stats(output) do
|
102
|
-
|
105
|
+
indexes_from(only: only, except: except).each_with_object([]) do |index, updated_indexes|
|
103
106
|
if index.exists?
|
104
107
|
output.puts "Updating #{index}"
|
105
|
-
|
106
|
-
|
108
|
+
index.import(parallel: parallel)
|
109
|
+
updated_indexes.push(index)
|
107
110
|
else
|
108
111
|
output.puts "Skipping #{index}, it does not exists (use rake chewy:reset[#{index.derivable_name}] to create and update it)"
|
109
112
|
end
|
@@ -115,31 +118,29 @@ module Chewy
|
|
115
118
|
#
|
116
119
|
# @example
|
117
120
|
# Chewy::RakeHelper.sync # synchronizes everything
|
118
|
-
# Chewy::RakeHelper.sync(only: 'places') # synchronizes only PlacesIndex
|
119
|
-
# Chewy::RakeHelper.sync(
|
120
|
-
# Chewy::RakeHelper.sync(except: PlacesIndex::Country) # synchronizes everything, but PlacesIndex::Country
|
121
|
-
# Chewy::RakeHelper.sync(only: 'places', except: 'places#country') # synchronizes PlacesIndex::City only
|
121
|
+
# Chewy::RakeHelper.sync(only: 'places') # synchronizes only PlacesIndex
|
122
|
+
# Chewy::RakeHelper.sync(except: PlacesIndex) # synchronizes everything, but PlacesIndex
|
122
123
|
#
|
123
|
-
# @param only [Array<Chewy::Index,
|
124
|
-
# @param except [Array<Chewy::Index,
|
124
|
+
# @param only [Array<Chewy::Index, String>, Chewy::Index, String] indexes to synchronize; if nothing is passed - uses all the indexes defined in the app
|
125
|
+
# @param except [Array<Chewy::Index, String>, Chewy::Index, String] indexes to exclude from processing
|
125
126
|
# @param parallel [true, Integer, Hash] any acceptable parallel options for sync
|
126
127
|
# @param output [IO] output io for logging
|
127
|
-
# @return [Array<Chewy::
|
128
|
-
def sync(only: nil, except: nil, parallel: nil, output:
|
128
|
+
# @return [Array<Chewy::Index>] indexes that were actually updated
|
129
|
+
def sync(only: nil, except: nil, parallel: nil, output: $stdout)
|
129
130
|
subscribed_task_stats(output) do
|
130
|
-
|
131
|
-
output.puts "Synchronizing #{
|
132
|
-
output.puts " #{
|
131
|
+
indexes_from(only: only, except: except).each_with_object([]) do |index, synced_indexes|
|
132
|
+
output.puts "Synchronizing #{index}"
|
133
|
+
output.puts " #{index} doesn't support outdated synchronization" unless index.supports_outdated_sync?
|
133
134
|
time = Time.now
|
134
|
-
sync_result =
|
135
|
+
sync_result = index.sync(parallel: parallel)
|
135
136
|
if !sync_result
|
136
|
-
output.puts " Something went wrong with the #{
|
137
|
-
elsif sync_result[:count]
|
137
|
+
output.puts " Something went wrong with the #{index} synchronization"
|
138
|
+
elsif (sync_result[:count]).positive?
|
138
139
|
output.puts " Missing documents: #{sync_result[:missing]}" if sync_result[:missing].present?
|
139
140
|
output.puts " Outdated documents: #{sync_result[:outdated]}" if sync_result[:outdated].present?
|
140
|
-
|
141
|
+
synced_indexes.push(index)
|
141
142
|
else
|
142
|
-
output.puts " Skipping #{
|
143
|
+
output.puts " Skipping #{index}, up to date"
|
143
144
|
end
|
144
145
|
output.puts " Took #{human_duration(Time.now - time)}"
|
145
146
|
end
|
@@ -147,51 +148,65 @@ module Chewy
|
|
147
148
|
end
|
148
149
|
|
149
150
|
# Applies changes that were done after the specified time for the
|
150
|
-
# specified indexes
|
151
|
+
# specified indexes or all of them.
|
151
152
|
#
|
152
153
|
# @example
|
153
154
|
# Chewy::RakeHelper.journal_apply(time: 1.minute.ago) # applies entries created for the last minute
|
154
|
-
# Chewy::RakeHelper.journal_apply(time: 1.minute.ago, only: 'places') # applies only PlacesIndex
|
155
|
-
# Chewy::RakeHelper.journal_apply(time: 1.minute.ago,
|
156
|
-
# Chewy::RakeHelper.journal_apply(time: 1.minute.ago, except: PlacesIndex::Country) # applies everything, but PlacesIndex::Country entries reated for the last minute
|
157
|
-
# Chewy::RakeHelper.journal_apply(time: 1.minute.ago, only: 'places', except: 'places#country') # applies PlacesIndex::City entries reated for the last minute only
|
155
|
+
# Chewy::RakeHelper.journal_apply(time: 1.minute.ago, only: 'places') # applies only PlacesIndex entries created for the last minute
|
156
|
+
# Chewy::RakeHelper.journal_apply(time: 1.minute.ago, except: PlacesIndex) # applies everything, but PlacesIndex, entries created for the last minute
|
158
157
|
#
|
159
158
|
# @param time [Time, DateTime] use only journal entries created after this time
|
160
|
-
# @param only [Array<Chewy::Index,
|
161
|
-
# @param except [Array<Chewy::Index,
|
159
|
+
# @param only [Array<Chewy::Index, String>, Chewy::Index, String] indexes to synchronize; if nothing is passed - uses all the indexes defined in the app
|
160
|
+
# @param except [Array<Chewy::Index, String>, Chewy::Index, String] indexes to exclude from processing
|
162
161
|
# @param output [IO] output io for logging
|
163
|
-
# @return [Array<Chewy::
|
164
|
-
def journal_apply(time: nil, only: nil, except: nil, output:
|
162
|
+
# @return [Array<Chewy::Index>] indexes that were actually updated
|
163
|
+
def journal_apply(time: nil, only: nil, except: nil, output: $stdout)
|
165
164
|
raise ArgumentError, 'Please specify the time to start with' unless time
|
165
|
+
|
166
166
|
subscribed_task_stats(output) do
|
167
167
|
output.puts "Applying journal entries created after #{time}"
|
168
|
-
count = Chewy::Journal.new(
|
168
|
+
count = Chewy::Journal.new(journal_indexes_from(only: only, except: except)).apply(time)
|
169
169
|
output.puts 'No journal entries were created after the specified time' if count.zero?
|
170
170
|
end
|
171
171
|
end
|
172
172
|
|
173
173
|
# Removes journal records created before the specified timestamp for
|
174
|
-
# the specified indexes
|
174
|
+
# the specified indexes or all of them.
|
175
175
|
#
|
176
176
|
# @example
|
177
177
|
# Chewy::RakeHelper.journal_clean # cleans everything
|
178
178
|
# Chewy::RakeHelper.journal_clean(time: 1.minute.ago) # leaves only entries created for the last minute
|
179
|
-
# Chewy::RakeHelper.journal_clean(only: 'places') # cleans only PlacesIndex
|
180
|
-
# Chewy::RakeHelper.journal_clean(
|
181
|
-
# Chewy::RakeHelper.journal_clean(except: PlacesIndex::Country) # cleans everything, but PlacesIndex::Country entries
|
182
|
-
# Chewy::RakeHelper.journal_clean(only: 'places', except: 'places#country') # cleans PlacesIndex::City entries only
|
179
|
+
# Chewy::RakeHelper.journal_clean(only: 'places') # cleans only PlacesIndex entries
|
180
|
+
# Chewy::RakeHelper.journal_clean(except: PlacesIndex) # cleans everything, but PlacesIndex entries
|
183
181
|
#
|
184
182
|
# @param time [Time, DateTime] clean all the journal entries created before this time
|
185
|
-
# @param only [Array<Chewy::Index,
|
186
|
-
# @param except [Array<Chewy::Index,
|
183
|
+
# @param only [Array<Chewy::Index, String>, Chewy::Index, String] indexes to synchronize; if nothing is passed - uses all the indexes defined in the app
|
184
|
+
# @param except [Array<Chewy::Index, String>, Chewy::Index, String] indexes to exclude from processing
|
187
185
|
# @param output [IO] output io for logging
|
188
|
-
# @return [Array<Chewy::
|
189
|
-
def journal_clean(time: nil, only: nil, except: nil, output:
|
186
|
+
# @return [Array<Chewy::Index>] indexes that were actually updated
|
187
|
+
def journal_clean(time: nil, only: nil, except: nil, delete_by_query_options: {}, output: $stdout)
|
190
188
|
subscribed_task_stats(output) do
|
191
189
|
output.puts "Cleaning journal entries created before #{time}" if time
|
192
|
-
response = Chewy::Journal.new(
|
193
|
-
|
194
|
-
|
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!
|
195
210
|
end
|
196
211
|
end
|
197
212
|
|
@@ -204,47 +219,100 @@ module Chewy
|
|
204
219
|
Chewy::Index.descendants - [Chewy::Stash::Journal, Chewy::Stash::Specification]
|
205
220
|
end
|
206
221
|
|
222
|
+
# Reindex data from source index to destination index
|
223
|
+
#
|
224
|
+
# @example
|
225
|
+
# Chewy::RakeHelper.reindex(source: 'users_index', dest: 'cities_index') reindex data from 'users_index' index to 'cities_index'
|
226
|
+
#
|
227
|
+
# @param source [String], dest [String] indexes to reindex
|
228
|
+
def reindex(source:, dest:, output: $stdout)
|
229
|
+
subscribed_task_stats(output) do
|
230
|
+
output.puts "Source index is #{source}\nDestination index is #{dest}"
|
231
|
+
Chewy::Index.reindex(source: source, dest: dest)
|
232
|
+
output.puts "#{source} index successfully reindexed with #{dest} index data"
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
# Adds new fields to an existing data stream or index.
|
237
|
+
# Change the search settings of existing fields.
|
238
|
+
#
|
239
|
+
# @example
|
240
|
+
# Chewy::RakeHelper.update_mapping('cities', {properties: {new_field: {type: :text}}}) update 'cities' index with new_field of text type
|
241
|
+
#
|
242
|
+
# @param name [String], body_hash [Hash] index name and body hash to update
|
243
|
+
def update_mapping(name:, output: $stdout)
|
244
|
+
subscribed_task_stats(output) do
|
245
|
+
output.puts "Index name is #{name}"
|
246
|
+
normalize_index(name).update_mapping
|
247
|
+
output.puts "#{name} index successfully updated"
|
248
|
+
end
|
249
|
+
end
|
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
|
+
|
207
289
|
def normalize_indexes(*identifiers)
|
208
290
|
identifiers.flatten(1).map { |identifier| normalize_index(identifier) }
|
209
291
|
end
|
210
292
|
|
211
293
|
def normalize_index(identifier)
|
212
294
|
return identifier if identifier.is_a?(Class) && identifier < Chewy::Index
|
213
|
-
|
295
|
+
|
296
|
+
"#{identifier.to_s.camelize}Index".constantize
|
214
297
|
end
|
215
298
|
|
216
|
-
def subscribed_task_stats(output =
|
299
|
+
def subscribed_task_stats(output = $stdout, &block)
|
217
300
|
start = Time.now
|
218
301
|
ActiveSupport::Notifications.subscribed(JOURNAL_CALLBACK.curry[output], 'apply_journal.chewy') do
|
219
|
-
ActiveSupport::Notifications.subscribed(IMPORT_CALLBACK.curry[output], 'import_objects.chewy')
|
220
|
-
yield
|
221
|
-
end
|
302
|
+
ActiveSupport::Notifications.subscribed(IMPORT_CALLBACK.curry[output], 'import_objects.chewy', &block)
|
222
303
|
end
|
304
|
+
ensure
|
223
305
|
output.puts "Total: #{human_duration(Time.now - start)}"
|
224
306
|
end
|
225
307
|
|
226
|
-
|
227
|
-
ActiveSupport::Deprecation.warn '`Chewy::RakeHelper.reset_index` is deprecated and will be removed soon, use `Chewy::RakeHelper.reset` instead'
|
228
|
-
reset(only: indexes)
|
229
|
-
end
|
230
|
-
|
231
|
-
def reset_all(*except)
|
232
|
-
ActiveSupport::Deprecation.warn '`Chewy::RakeHelper.reset_all` is deprecated and will be removed soon, use `Chewy::RakeHelper.reset` instead'
|
233
|
-
reset(except: except)
|
234
|
-
end
|
308
|
+
private
|
235
309
|
|
236
|
-
def
|
237
|
-
|
238
|
-
update(only: indexes)
|
239
|
-
end
|
310
|
+
def journal_indexes_from(only: nil, except: nil)
|
311
|
+
return if Array.wrap(only).empty? && Array.wrap(except).empty?
|
240
312
|
|
241
|
-
|
242
|
-
ActiveSupport::Deprecation.warn '`Chewy::RakeHelper.update_all` is deprecated and will be removed soon, use `Chewy::RakeHelper.update` instead'
|
243
|
-
update(except: except)
|
313
|
+
indexes_from(only: only, except: except)
|
244
314
|
end
|
245
315
|
|
246
|
-
private
|
247
|
-
|
248
316
|
def indexes_from(only: nil, except: nil)
|
249
317
|
indexes = if only.present?
|
250
318
|
normalize_indexes(Array.wrap(only))
|
@@ -252,42 +320,14 @@ module Chewy
|
|
252
320
|
all_indexes
|
253
321
|
end
|
254
322
|
|
255
|
-
indexes
|
256
|
-
indexes - normalize_indexes(Array.wrap(except))
|
257
|
-
else
|
258
|
-
indexes
|
259
|
-
end
|
323
|
+
indexes -= normalize_indexes(Array.wrap(except)) if except.present?
|
260
324
|
|
261
325
|
indexes.sort_by(&:derivable_name)
|
262
326
|
end
|
263
327
|
|
264
|
-
def types_from(only: nil, except: nil)
|
265
|
-
types = if only.present?
|
266
|
-
normalize_types(Array.wrap(only))
|
267
|
-
else
|
268
|
-
all_indexes.flat_map(&:types)
|
269
|
-
end
|
270
|
-
|
271
|
-
types = if except.present?
|
272
|
-
types - normalize_types(Array.wrap(except))
|
273
|
-
else
|
274
|
-
types
|
275
|
-
end
|
276
|
-
|
277
|
-
types.sort_by(&:derivable_name)
|
278
|
-
end
|
279
|
-
|
280
|
-
def normalize_types(*identifiers)
|
281
|
-
identifiers.flatten(1).flat_map { |identifier| normalize_type(identifier) }
|
282
|
-
end
|
283
|
-
|
284
|
-
def normalize_type(identifier)
|
285
|
-
Chewy.derive_types(identifier)
|
286
|
-
end
|
287
|
-
|
288
328
|
def human_duration(seconds)
|
289
329
|
[[60, :s], [60, :m], [24, :h]].map do |amount, unit|
|
290
|
-
if seconds
|
330
|
+
if seconds.positive?
|
291
331
|
seconds, n = seconds.divmod(amount)
|
292
332
|
"#{n.to_i}#{unit}"
|
293
333
|
end
|
@@ -296,7 +336,23 @@ module Chewy
|
|
296
336
|
|
297
337
|
def reset_one(index, output, parallel: false)
|
298
338
|
output.puts "Resetting #{index}"
|
299
|
-
index.reset!((Time.now.to_f * 1000).round, parallel: parallel)
|
339
|
+
index.reset!((Time.now.to_f * 1000).round, parallel: parallel, apply_journal: journal_exists?)
|
340
|
+
end
|
341
|
+
|
342
|
+
def warn_missing_index(output)
|
343
|
+
return if journal_exists?
|
344
|
+
|
345
|
+
output.puts "############################################################\n" \
|
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" \
|
349
|
+
'############################################################'
|
350
|
+
end
|
351
|
+
|
352
|
+
def journal_exists?
|
353
|
+
@journal_exists = Chewy::Stash::Journal.exists? if @journal_exists.nil?
|
354
|
+
|
355
|
+
@journal_exists
|
300
356
|
end
|
301
357
|
end
|
302
358
|
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# Rspec helper to compare request and expected query
|
2
|
+
# To use it - add `require 'chewy/rspec/build_query'` to the `spec_helper.rb`
|
3
|
+
# Simple usage - just pass expected response as argument
|
4
|
+
# and then call needed query.
|
5
|
+
#
|
6
|
+
# expect { method1.method2...methodN }.to build_query(expected_query)
|
7
|
+
#
|
8
|
+
RSpec::Matchers.define :build_query do |expected_query = {}|
|
9
|
+
match do |request|
|
10
|
+
request.render == expected_query
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module Chewy
|
2
|
+
module Rspec
|
3
|
+
module Helpers
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
# Rspec helper to mock elasticsearch response
|
6
|
+
# To use it - add `require 'chewy/rspec'` to the `spec_helper.rb`
|
7
|
+
#
|
8
|
+
# mock_elasticsearch_response(CitiesIndex, raw_response)
|
9
|
+
# expect(CitiesIndex.query({}).hits).to eq(hits)
|
10
|
+
#
|
11
|
+
def mock_elasticsearch_response(index, raw_response)
|
12
|
+
mocked_request = Chewy::Search::Request.new(index)
|
13
|
+
allow(Chewy::Search::Request).to receive(:new).and_return(mocked_request)
|
14
|
+
allow(mocked_request).to receive(:perform).and_return(raw_response)
|
15
|
+
end
|
16
|
+
|
17
|
+
# Rspec helper to mock Elasticsearch response source
|
18
|
+
# To use it - add `require 'chewy/rspec'` to the `spec_helper.rb`
|
19
|
+
#
|
20
|
+
# mock_elasticsearch_response_sources(CitiesIndex, sources)
|
21
|
+
# expect(CitiesIndex.query({}).hits).to eq(hits)
|
22
|
+
#
|
23
|
+
def mock_elasticsearch_response_sources(index, hits)
|
24
|
+
raw_response = {
|
25
|
+
'took' => 4,
|
26
|
+
'timed_out' => false,
|
27
|
+
'_shards' => {
|
28
|
+
'total' => 1,
|
29
|
+
'successful' => 1,
|
30
|
+
'skipped' => 0,
|
31
|
+
'failed' => 0
|
32
|
+
},
|
33
|
+
'hits' => {
|
34
|
+
'total' => {
|
35
|
+
'value' => hits.count,
|
36
|
+
'relation' => 'eq'
|
37
|
+
},
|
38
|
+
'max_score' => 1.0,
|
39
|
+
'hits' => hits.each_with_index.map do |hit, i|
|
40
|
+
{
|
41
|
+
'_index' => index.index_name,
|
42
|
+
'_type' => '_doc',
|
43
|
+
'_id' => (i + 1).to_s,
|
44
|
+
'_score' => 3.14,
|
45
|
+
'_source' => hit
|
46
|
+
}
|
47
|
+
end
|
48
|
+
}
|
49
|
+
}
|
50
|
+
|
51
|
+
mock_elasticsearch_response(index, raw_response)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|