chewy 0.10.1 → 7.3.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- 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/workflows/ruby.yml +74 -0
- data/.rubocop.yml +28 -23
- data/.rubocop_todo.yml +110 -22
- data/CHANGELOG.md +480 -298
- data/CODE_OF_CONDUCT.md +14 -0
- data/CONTRIBUTING.md +63 -0
- data/Gemfile +3 -5
- data/Guardfile +3 -1
- data/LICENSE.txt +1 -1
- data/README.md +571 -333
- data/chewy.gemspec +12 -15
- data/gemfiles/rails.5.2.activerecord.gemfile +11 -0
- data/gemfiles/rails.6.0.activerecord.gemfile +11 -0
- data/gemfiles/rails.6.1.activerecord.gemfile +13 -0
- data/gemfiles/rails.7.0.activerecord.gemfile +13 -0
- data/lib/chewy/config.rb +48 -77
- data/lib/chewy/errors.rb +4 -10
- data/lib/chewy/fields/base.rb +88 -16
- data/lib/chewy/fields/root.rb +15 -21
- data/lib/chewy/index/actions.rb +67 -38
- data/lib/chewy/{type → index}/adapter/active_record.rb +18 -4
- data/lib/chewy/{type → index}/adapter/base.rb +11 -12
- data/lib/chewy/{type → index}/adapter/object.rb +28 -32
- data/lib/chewy/{type → index}/adapter/orm.rb +26 -24
- 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 +10 -9
- data/lib/chewy/{type → index}/import/journal_builder.rb +11 -12
- data/lib/chewy/{type → index}/import/routine.rb +19 -18
- data/lib/chewy/{type → index}/import.rb +82 -36
- data/lib/chewy/{type → index}/mapping.rb +63 -62
- 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/settings.rb +2 -0
- data/lib/chewy/index/specification.rb +13 -10
- data/lib/chewy/{type → index}/syncer.rb +62 -63
- data/lib/chewy/{type → index}/witchcraft.rb +15 -9
- data/lib/chewy/{type → index}/wrapper.rb +16 -6
- data/lib/chewy/index.rb +68 -93
- data/lib/chewy/journal.rb +25 -14
- data/lib/chewy/minitest/helpers.rb +91 -18
- data/lib/chewy/minitest/search_index_receiver.rb +29 -33
- data/lib/chewy/multi_search.rb +62 -0
- data/lib/chewy/railtie.rb +8 -24
- data/lib/chewy/rake_helper.rb +141 -112
- data/lib/chewy/rspec/build_query.rb +12 -0
- data/lib/chewy/rspec/helpers.rb +55 -0
- data/lib/chewy/rspec/update_index.rb +58 -49
- data/lib/chewy/rspec.rb +2 -0
- data/lib/chewy/runtime.rb +1 -1
- data/lib/chewy/search/loader.rb +19 -41
- data/lib/chewy/search/parameters/allow_partial_search_results.rb +27 -0
- data/lib/chewy/search/parameters/collapse.rb +16 -0
- data/lib/chewy/search/parameters/concerns/query_storage.rb +6 -5
- data/lib/chewy/search/parameters/ignore_unavailable.rb +27 -0
- data/lib/chewy/search/parameters/indices.rb +78 -0
- data/lib/chewy/search/parameters/none.rb +1 -3
- data/lib/chewy/search/parameters/order.rb +6 -19
- data/lib/chewy/search/parameters/source.rb +5 -1
- data/lib/chewy/search/parameters/track_total_hits.rb +16 -0
- data/lib/chewy/search/parameters.rb +28 -8
- data/lib/chewy/search/query_proxy.rb +9 -2
- data/lib/chewy/search/request.rb +207 -157
- data/lib/chewy/search/response.rb +5 -5
- data/lib/chewy/search/scoping.rb +7 -8
- data/lib/chewy/search/scrolling.rb +14 -13
- data/lib/chewy/search.rb +7 -26
- data/lib/chewy/stash.rb +27 -29
- data/lib/chewy/strategy/active_job.rb +2 -2
- data/lib/chewy/strategy/atomic.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 +148 -0
- data/lib/chewy/strategy/delayed_sidekiq/worker.rb +52 -0
- data/lib/chewy/strategy/delayed_sidekiq.rb +17 -0
- data/lib/chewy/strategy/lazy_sidekiq.rb +64 -0
- data/lib/chewy/strategy/sidekiq.rb +3 -2
- data/lib/chewy/strategy.rb +6 -19
- data/lib/chewy/version.rb +1 -1
- data/lib/chewy.rb +37 -80
- data/lib/generators/chewy/install_generator.rb +1 -1
- data/lib/tasks/chewy.rake +26 -32
- data/migration_guide.md +56 -0
- data/spec/chewy/config_spec.rb +27 -57
- data/spec/chewy/fields/base_spec.rb +457 -174
- data/spec/chewy/fields/root_spec.rb +24 -32
- data/spec/chewy/fields/time_fields_spec.rb +5 -5
- data/spec/chewy/index/actions_spec.rb +425 -60
- data/spec/chewy/{type → index}/adapter/active_record_spec.rb +110 -44
- 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 +22 -30
- data/spec/chewy/{type → index}/import/routine_spec.rb +19 -19
- data/spec/chewy/{type → index}/import_spec.rb +154 -95
- 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 +32 -33
- data/spec/chewy/{type → index}/syncer_spec.rb +14 -19
- data/spec/chewy/{type → index}/witchcraft_spec.rb +34 -21
- data/spec/chewy/index/wrapper_spec.rb +100 -0
- data/spec/chewy/index_spec.rb +99 -114
- data/spec/chewy/journal_spec.rb +56 -101
- data/spec/chewy/minitest/helpers_spec.rb +122 -14
- data/spec/chewy/minitest/search_index_receiver_spec.rb +24 -26
- data/spec/chewy/multi_search_spec.rb +84 -0
- data/spec/chewy/rake_helper_spec.rb +325 -101
- 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 +106 -102
- 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 +3 -5
- 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/ignore_unavailable_spec.rb +67 -0
- data/spec/chewy/search/parameters/indices_spec.rb +99 -0
- data/spec/chewy/search/parameters/none_spec.rb +1 -1
- 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 +39 -8
- data/spec/chewy/search/query_proxy_spec.rb +68 -17
- data/spec/chewy/search/request_spec.rb +360 -149
- data/spec/chewy/search/response_spec.rb +35 -25
- data/spec/chewy/search/scrolling_spec.rb +28 -26
- data/spec/chewy/search_spec.rb +73 -53
- data/spec/chewy/stash_spec.rb +16 -26
- data/spec/chewy/strategy/active_job_spec.rb +23 -10
- 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 +190 -0
- data/spec/chewy/strategy/lazy_sidekiq_spec.rb +214 -0
- data/spec/chewy/strategy/sidekiq_spec.rb +14 -10
- data/spec/chewy/strategy_spec.rb +19 -15
- data/spec/chewy_spec.rb +17 -110
- data/spec/spec_helper.rb +7 -22
- data/spec/support/active_record.rb +43 -5
- metadata +123 -198
- data/.travis.yml +0 -53
- data/Appraisals +0 -79
- data/LEGACY_DSL.md +0 -497
- data/gemfiles/rails.4.0.activerecord.gemfile +0 -14
- data/gemfiles/rails.4.1.activerecord.gemfile +0 -14
- data/gemfiles/rails.4.2.activerecord.gemfile +0 -15
- data/gemfiles/rails.4.2.mongoid.5.1.gemfile +0 -15
- data/gemfiles/rails.5.0.activerecord.gemfile +0 -15
- data/gemfiles/rails.5.0.mongoid.6.0.gemfile +0 -15
- data/gemfiles/rails.5.1.activerecord.gemfile +0 -15
- data/gemfiles/rails.5.1.mongoid.6.1.gemfile +0 -15
- 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/query/compose.rb +0 -68
- data/lib/chewy/query/criteria.rb +0 -191
- data/lib/chewy/query/filters.rb +0 -227
- data/lib/chewy/query/loading.rb +0 -111
- data/lib/chewy/query/nodes/and.rb +0 -25
- data/lib/chewy/query/nodes/base.rb +0 -17
- data/lib/chewy/query/nodes/bool.rb +0 -34
- data/lib/chewy/query/nodes/equal.rb +0 -34
- data/lib/chewy/query/nodes/exists.rb +0 -20
- data/lib/chewy/query/nodes/expr.rb +0 -28
- data/lib/chewy/query/nodes/field.rb +0 -110
- data/lib/chewy/query/nodes/has_child.rb +0 -15
- data/lib/chewy/query/nodes/has_parent.rb +0 -15
- data/lib/chewy/query/nodes/has_relation.rb +0 -59
- data/lib/chewy/query/nodes/match_all.rb +0 -11
- data/lib/chewy/query/nodes/missing.rb +0 -20
- data/lib/chewy/query/nodes/not.rb +0 -25
- data/lib/chewy/query/nodes/or.rb +0 -25
- data/lib/chewy/query/nodes/prefix.rb +0 -19
- data/lib/chewy/query/nodes/query.rb +0 -20
- data/lib/chewy/query/nodes/range.rb +0 -63
- data/lib/chewy/query/nodes/raw.rb +0 -15
- data/lib/chewy/query/nodes/regexp.rb +0 -35
- data/lib/chewy/query/nodes/script.rb +0 -20
- data/lib/chewy/query/pagination.rb +0 -25
- data/lib/chewy/query.rb +0 -1098
- 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 -69
- data/lib/chewy/type/adapter/sequel.rb +0 -95
- 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 -78
- data/lib/chewy/type.rb +0 -117
- data/lib/sequel/plugins/chewy_observe.rb +0 -78
- data/spec/chewy/query/criteria_spec.rb +0 -700
- data/spec/chewy/query/filters_spec.rb +0 -201
- data/spec/chewy/query/loading_spec.rb +0 -124
- data/spec/chewy/query/nodes/and_spec.rb +0 -12
- data/spec/chewy/query/nodes/bool_spec.rb +0 -14
- data/spec/chewy/query/nodes/equal_spec.rb +0 -32
- data/spec/chewy/query/nodes/exists_spec.rb +0 -18
- data/spec/chewy/query/nodes/has_child_spec.rb +0 -59
- data/spec/chewy/query/nodes/has_parent_spec.rb +0 -59
- data/spec/chewy/query/nodes/match_all_spec.rb +0 -11
- data/spec/chewy/query/nodes/missing_spec.rb +0 -16
- data/spec/chewy/query/nodes/not_spec.rb +0 -13
- data/spec/chewy/query/nodes/or_spec.rb +0 -12
- data/spec/chewy/query/nodes/prefix_spec.rb +0 -16
- data/spec/chewy/query/nodes/query_spec.rb +0 -12
- data/spec/chewy/query/nodes/range_spec.rb +0 -32
- data/spec/chewy/query/nodes/raw_spec.rb +0 -11
- data/spec/chewy/query/nodes/regexp_spec.rb +0 -43
- data/spec/chewy/query/nodes/script_spec.rb +0 -15
- data/spec/chewy/query/pagination/kaminari_spec.rb +0 -5
- data/spec/chewy/query/pagination/will_paginate_spec.rb +0 -5
- data/spec/chewy/query/pagination_spec.rb +0 -39
- data/spec/chewy/query_spec.rb +0 -636
- 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/indices_boost_spec.rb +0 -83
- 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 -64
- 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 -279
- data/spec/chewy/type/mapping_spec.rb +0 -142
- data/spec/chewy/type/observe_spec.rb +0 -137
- data/spec/chewy/type/wrapper_spec.rb +0 -98
- 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/index/actions.rb
CHANGED
@@ -30,8 +30,8 @@ module Chewy
|
|
30
30
|
# Suffixed index names might be used for zero-downtime mapping change, for example.
|
31
31
|
# Description: (http://www.elasticsearch.org/blog/changing-mapping-with-zero-downtime/).
|
32
32
|
#
|
33
|
-
def create(*args)
|
34
|
-
create!(*args)
|
33
|
+
def create(*args, **kwargs)
|
34
|
+
create!(*args, **kwargs)
|
35
35
|
rescue Elasticsearch::Transport::Transport::Errors::BadRequest
|
36
36
|
false
|
37
37
|
end
|
@@ -57,14 +57,9 @@ module Chewy
|
|
57
57
|
general_name = index_name
|
58
58
|
suffixed_name = index_name(suffix: suffix)
|
59
59
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
result = client.indices.create(index: suffixed_name, body: body)
|
64
|
-
else
|
65
|
-
result = client.indices.create(index: suffixed_name, body: specification_hash)
|
66
|
-
result &&= client.indices.put_alias(index: suffixed_name, name: general_name) if options[:alias] && name != index_name
|
67
|
-
end
|
60
|
+
body = specification_hash
|
61
|
+
body[:aliases] = {general_name => {}} if options[:alias] && suffixed_name != general_name
|
62
|
+
result = client.indices.create(index: suffixed_name, body: body)
|
68
63
|
|
69
64
|
Chewy.wait_for_status if result
|
70
65
|
result
|
@@ -79,7 +74,13 @@ module Chewy
|
|
79
74
|
# UsersIndex.delete '01-2014' # deletes `users_01-2014` index
|
80
75
|
#
|
81
76
|
def delete(suffix = nil)
|
82
|
-
|
77
|
+
# Verify that the index_name is really the index_name and not an alias.
|
78
|
+
#
|
79
|
+
# "The index parameter in the delete index API no longer accepts alias names.
|
80
|
+
# Instead, it accepts only index names (or wildcards which will expand to matching indices)."
|
81
|
+
# https://www.elastic.co/guide/en/elasticsearch/reference/6.8/breaking-changes-6.0.html#_delete_index_api_resolves_indices_expressions_only_against_indices
|
82
|
+
index_names = client.indices.get_alias(index: index_name(suffix: suffix)).keys
|
83
|
+
result = client.indices.delete index: index_names.join(',')
|
83
84
|
Chewy.wait_for_status if result
|
84
85
|
result
|
85
86
|
# es-ruby >= 1.0.10 handles Elasticsearch::Transport::Transport::Errors::NotFound
|
@@ -128,28 +129,6 @@ module Chewy
|
|
128
129
|
create! suffix
|
129
130
|
end
|
130
131
|
|
131
|
-
# Perform import operation for every defined type
|
132
|
-
#
|
133
|
-
# UsersIndex.import # imports default data for every index type
|
134
|
-
# UsersIndex.import user: User.active # imports specified objects for user type and default data for other types
|
135
|
-
# UsersIndex.import refresh: false # to disable index refreshing after import
|
136
|
-
# UsersIndex.import suffix: Time.now.to_i # imports data to index with specified suffix if such is exists
|
137
|
-
# UsersIndex.import batch_size: 300 # import batch size
|
138
|
-
#
|
139
|
-
# See [import.rb](lib/chewy/type/import.rb) for more details.
|
140
|
-
#
|
141
|
-
%i[import import!].each do |method|
|
142
|
-
class_eval <<-METHOD, __FILE__, __LINE__ + 1
|
143
|
-
def #{method} options = {}
|
144
|
-
objects = options.reject { |k, v| !type_names.map(&:to_sym).include?(k) }
|
145
|
-
types.map do |type|
|
146
|
-
args = [objects[type.type_name.to_sym], options.dup].reject(&:blank?)
|
147
|
-
type.#{method} *args
|
148
|
-
end.all?
|
149
|
-
end
|
150
|
-
METHOD
|
151
|
-
end
|
152
|
-
|
153
132
|
# Deletes, creates and imports data to the index. Returns the
|
154
133
|
# import result. If index name suffix is passed as the first
|
155
134
|
# argument - performs zero-downtime index resetting.
|
@@ -164,20 +143,24 @@ module Chewy
|
|
164
143
|
# @see http://www.elasticsearch.org/blog/changing-mapping-with-zero-downtime
|
165
144
|
# @param suffix [String] a suffix for the newly created index
|
166
145
|
# @param apply_journal [true, false] if true, journal is applied after the import is completed
|
167
|
-
# @param journal [true, false]
|
146
|
+
# @param journal [true, false] journaling is switched off for import during reset by default
|
168
147
|
# @param import_options [Hash] options, passed to the import call
|
169
148
|
# @return [true, false] false in case of errors
|
170
149
|
def reset!(suffix = nil, apply_journal: true, journal: false, **import_options)
|
171
150
|
result = if suffix.present?
|
172
151
|
start_time = Time.now
|
173
|
-
indexes = self.indexes
|
152
|
+
indexes = self.indexes - [index_name]
|
174
153
|
create! suffix, alias: false
|
175
154
|
|
176
155
|
general_name = index_name
|
177
156
|
suffixed_name = index_name(suffix: suffix)
|
178
157
|
|
179
158
|
optimize_index_settings suffixed_name
|
180
|
-
result = import
|
159
|
+
result = import(**import_options.merge(
|
160
|
+
suffix: suffix,
|
161
|
+
journal: journal,
|
162
|
+
refresh: !Chewy.reset_disable_refresh_interval
|
163
|
+
))
|
181
164
|
original_index_settings suffixed_name
|
182
165
|
|
183
166
|
delete if indexes.blank?
|
@@ -193,12 +176,13 @@ module Chewy
|
|
193
176
|
result
|
194
177
|
else
|
195
178
|
purge!
|
196
|
-
import
|
179
|
+
import(**import_options.merge(journal: journal))
|
197
180
|
end
|
198
181
|
|
199
182
|
specification.lock!
|
200
183
|
result
|
201
184
|
end
|
185
|
+
alias_method :reset, :reset!
|
202
186
|
|
203
187
|
# A {Chewy::Journal} instance for the particular index
|
204
188
|
#
|
@@ -207,6 +191,50 @@ module Chewy
|
|
207
191
|
@journal ||= Chewy::Journal.new(self)
|
208
192
|
end
|
209
193
|
|
194
|
+
def clear_cache(args = {index: index_name})
|
195
|
+
client.indices.clear_cache(args)
|
196
|
+
end
|
197
|
+
|
198
|
+
def reindex(source: index_name, dest: index_name)
|
199
|
+
client.reindex(
|
200
|
+
{
|
201
|
+
body:
|
202
|
+
{
|
203
|
+
source: {index: source},
|
204
|
+
dest: {index: dest}
|
205
|
+
}
|
206
|
+
}
|
207
|
+
)
|
208
|
+
end
|
209
|
+
|
210
|
+
# Adds new fields to an existing data stream or index.
|
211
|
+
# Change the search settings of existing fields.
|
212
|
+
#
|
213
|
+
# @example
|
214
|
+
# Chewy.client.update_mapping('cities', {properties: {new_field: {type: :text}}})
|
215
|
+
#
|
216
|
+
def update_mapping(name = index_name, body = root.mappings_hash)
|
217
|
+
client.indices.put_mapping(
|
218
|
+
index: name,
|
219
|
+
body: body
|
220
|
+
)['acknowledged']
|
221
|
+
end
|
222
|
+
|
223
|
+
# Performs missing and outdated objects synchronization for the current index.
|
224
|
+
#
|
225
|
+
# @example
|
226
|
+
# UsersIndex.sync
|
227
|
+
#
|
228
|
+
# @see Chewy::Index::Syncer
|
229
|
+
# @param parallel [true, Integer, Hash] options for parallel execution or the number of processes
|
230
|
+
# @return [Hash{Symbol, Object}, nil] a number of missing and outdated documents re-indexed and their ids,
|
231
|
+
# nil in case of errors
|
232
|
+
def sync(parallel: nil)
|
233
|
+
syncer = Syncer.new(self, parallel: parallel)
|
234
|
+
count = syncer.perform
|
235
|
+
{count: count, missing: syncer.missing_ids, outdated: syncer.outdated_ids} if count
|
236
|
+
end
|
237
|
+
|
210
238
|
private
|
211
239
|
|
212
240
|
def optimize_index_settings(index_name)
|
@@ -231,7 +259,8 @@ module Chewy
|
|
231
259
|
end
|
232
260
|
|
233
261
|
def index_settings(setting_name)
|
234
|
-
return {} unless settings_hash.key?(:settings)
|
262
|
+
return {} unless settings_hash.key?(:settings) && settings_hash[:settings].key?(:index)
|
263
|
+
|
235
264
|
settings_hash[:settings][:index].slice(setting_name)
|
236
265
|
end
|
237
266
|
end
|
@@ -1,7 +1,7 @@
|
|
1
|
-
require 'chewy/
|
1
|
+
require 'chewy/index/adapter/orm'
|
2
2
|
|
3
3
|
module Chewy
|
4
|
-
class
|
4
|
+
class Index
|
5
5
|
module Adapter
|
6
6
|
class ActiveRecord < Orm
|
7
7
|
def self.accepts?(target)
|
@@ -22,7 +22,7 @@ module Chewy
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def import_scope(scope, options)
|
25
|
-
pluck_in_batches(scope, options.slice(:batch_size)).inject(true) do |result, ids|
|
25
|
+
pluck_in_batches(scope, **options.slice(:batch_size)).inject(true) do |result, ids|
|
26
26
|
objects = if options[:raw_import]
|
27
27
|
raw_default_scope_where_ids_in(ids, options[:raw_import])
|
28
28
|
else
|
@@ -60,7 +60,15 @@ module Chewy
|
|
60
60
|
end
|
61
61
|
|
62
62
|
def pluck_in_batches(scope, fields: [], batch_size: nil, typecast: true)
|
63
|
-
|
63
|
+
unless block_given?
|
64
|
+
return enum_for(
|
65
|
+
:pluck_in_batches,
|
66
|
+
scope,
|
67
|
+
fields: fields,
|
68
|
+
batch_size: batch_size,
|
69
|
+
typecast: typecast
|
70
|
+
)
|
71
|
+
end
|
64
72
|
|
65
73
|
scope = scope.reorder(target_id.asc).limit(batch_size)
|
66
74
|
ids = pluck(scope, fields: fields, typecast: typecast)
|
@@ -69,6 +77,7 @@ module Chewy
|
|
69
77
|
while ids.present?
|
70
78
|
yield ids
|
71
79
|
break if ids.size < batch_size
|
80
|
+
|
72
81
|
last_id = ids.last.is_a?(Array) ? ids.last.first : ids.last
|
73
82
|
ids = pluck(scope.where(target_id.gt(last_id)), fields: fields, typecast: typecast)
|
74
83
|
end
|
@@ -85,6 +94,11 @@ module Chewy
|
|
85
94
|
object_class.connection.execute(sql).map(&converter)
|
86
95
|
end
|
87
96
|
|
97
|
+
def raw(scope, converter)
|
98
|
+
sql = scope.to_sql
|
99
|
+
object_class.connection.execute(sql).map(&converter)
|
100
|
+
end
|
101
|
+
|
88
102
|
def relation_class
|
89
103
|
::ActiveRecord::Relation
|
90
104
|
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
module Chewy
|
2
|
-
class
|
2
|
+
class Index
|
3
3
|
module Adapter
|
4
4
|
# Basic adapter class. Contains interface, need to implement to add any classes support
|
5
5
|
class Base
|
@@ -13,8 +13,7 @@ module Chewy
|
|
13
13
|
true
|
14
14
|
end
|
15
15
|
|
16
|
-
# Camelcased name
|
17
|
-
# For returned value 'Product' will be generated class name `ProductsIndex::Product`
|
16
|
+
# Camelcased name.
|
18
17
|
#
|
19
18
|
def name
|
20
19
|
raise NotImplementedError
|
@@ -41,19 +40,19 @@ module Chewy
|
|
41
40
|
#
|
42
41
|
# { delete: [object_or_id1, object_or_id2], index: [object3, object4, object5] }
|
43
42
|
#
|
44
|
-
# @
|
43
|
+
# @yieldparam _batch [Array<Object>] each batch of objects
|
45
44
|
# @return [true, false] returns true if all the block call returns true and false otherwise
|
46
|
-
def import(
|
45
|
+
def import(_batch, &_block)
|
47
46
|
raise NotImplementedError
|
48
47
|
end
|
49
48
|
|
50
49
|
# Unlike {#import} fetches only ids (references) to the imported objects,
|
51
50
|
# using the same procedures as {#import}.
|
52
51
|
#
|
53
|
-
# @param
|
54
|
-
# @param
|
55
|
-
# @
|
56
|
-
def import_fields(
|
52
|
+
# @param _fields [Array<Symbol>] additional fields to fetch
|
53
|
+
# @param _batch_size [Integer] batch size, defaults to 1000
|
54
|
+
# @yieldparam batch [Array<Object>] each batch of objects
|
55
|
+
def import_fields(_fields, _batch_size, &_block)
|
57
56
|
raise NotImplementedError
|
58
57
|
end
|
59
58
|
|
@@ -61,9 +60,9 @@ module Chewy
|
|
61
60
|
# an array of references to the passed objects. Returns ids if possible.
|
62
61
|
# Otherwise - and array of objects themselves.
|
63
62
|
#
|
64
|
-
# @param
|
65
|
-
# @
|
66
|
-
def import_references(
|
63
|
+
# @param _batch_size [Integer] batch size, defaults to 1000
|
64
|
+
# @yieldparam batch [Array<Object>] each batch of objects
|
65
|
+
def import_references(_batch_size, &_block)
|
67
66
|
raise NotImplementedError
|
68
67
|
end
|
69
68
|
|
@@ -1,7 +1,7 @@
|
|
1
|
-
require 'chewy/
|
1
|
+
require 'chewy/index/adapter/base'
|
2
2
|
|
3
3
|
module Chewy
|
4
|
-
class
|
4
|
+
class Index
|
5
5
|
module Adapter
|
6
6
|
# This adapter provides an ability to import documents from any
|
7
7
|
# source. You can actually use any class or even a symbol as
|
@@ -14,15 +14,15 @@ module Chewy
|
|
14
14
|
# @see #import
|
15
15
|
# @see #load
|
16
16
|
class Object < Base
|
17
|
-
# The signature of the
|
17
|
+
# The signature of the index scope definition.
|
18
18
|
#
|
19
19
|
# @example
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
20
|
+
# index_scope :geoname
|
21
|
+
# index_scope Geoname
|
22
|
+
# index_scope -> { Geoname.all_the_places }, name: 'geoname'
|
23
23
|
#
|
24
24
|
# @param target [Class, Symbol, String, Proc] a source of data and everything
|
25
|
-
# @option options [String, Symbol] :name redefines the inferred
|
25
|
+
# @option options [String, Symbol] :name redefines the inferred name if necessary
|
26
26
|
# @option options [String, Symbol] :import_all_method redefines import method name
|
27
27
|
# @option options [String, Symbol] :load_all_method redefines batch load method name
|
28
28
|
# @option options [String, Symbol] :load_one_method redefines per-object load method name
|
@@ -31,14 +31,13 @@ module Chewy
|
|
31
31
|
@options = options
|
32
32
|
end
|
33
33
|
|
34
|
-
#
|
35
|
-
# by default if possible.
|
34
|
+
# Inferred from the target by default if possible.
|
36
35
|
#
|
37
36
|
# @example
|
38
|
-
# # defines
|
39
|
-
#
|
40
|
-
# # still defines
|
41
|
-
#
|
37
|
+
# # defines name = Geoname
|
38
|
+
# index_scope :geoname
|
39
|
+
# # still defines name = Geoname
|
40
|
+
# index_scope -> { Geoname.all_the_places }, name: 'geoname'
|
42
41
|
#
|
43
42
|
# @return [String]
|
44
43
|
def name
|
@@ -54,14 +53,14 @@ module Chewy
|
|
54
53
|
Array.wrap(collection)
|
55
54
|
end
|
56
55
|
|
57
|
-
# This method is used internally by `Chewy::
|
56
|
+
# This method is used internally by `Chewy::Index.import`.
|
58
57
|
#
|
59
58
|
# The idea is that any object can be imported to ES if
|
60
59
|
# it responds to `#to_json` method.
|
61
60
|
#
|
62
61
|
# If method `destroyed?` is defined for object (or, in case of hash object,
|
63
62
|
# it has `:_destroyed` or `'_destroyed'` key) and returns `true` or object
|
64
|
-
# satisfy `delete_if`
|
63
|
+
# satisfy `delete_if` option then object will be deleted from index.
|
65
64
|
# But in order to be destroyable, objects need to respond to `id` method
|
66
65
|
# or have an `id` key so ElasticSearch could know which one to delete.
|
67
66
|
#
|
@@ -78,15 +77,15 @@ module Chewy
|
|
78
77
|
# end
|
79
78
|
# end
|
80
79
|
#
|
81
|
-
# # All the
|
82
|
-
#
|
83
|
-
#
|
84
|
-
#
|
80
|
+
# # All the following variants will work:
|
81
|
+
# index_scope Geoname
|
82
|
+
# index_scope Geoname, import_all_method: 'import_all'
|
83
|
+
# index_scope -> { FancyGeoAPI.all_points_collection }, name: 'geoname'
|
85
84
|
#
|
86
85
|
# @param args [Array<#to_json>]
|
87
86
|
# @option options [Integer] :batch_size import processing batch size
|
88
87
|
# @return [true, false]
|
89
|
-
def import(*args, &block)
|
88
|
+
ruby2_keywords def import(*args, &block)
|
90
89
|
collection, options = import_args(*args)
|
91
90
|
import_objects(collection, options, &block)
|
92
91
|
end
|
@@ -113,16 +112,15 @@ module Chewy
|
|
113
112
|
# end
|
114
113
|
# end
|
115
114
|
#
|
116
|
-
# @see Chewy::
|
117
|
-
def import_fields(*args)
|
115
|
+
# @see Chewy::Index::Adapter::Base#import_fields
|
116
|
+
ruby2_keywords def import_fields(*args, &block)
|
118
117
|
return enum_for(:import_fields, *args) unless block_given?
|
118
|
+
|
119
119
|
options = args.extract_options!
|
120
120
|
options[:batch_size] ||= BATCH_SIZE
|
121
121
|
|
122
122
|
if args.empty? && @target.respond_to?(pluck_method)
|
123
|
-
@target.send(pluck_method, :id, *options[:fields]).each_slice(options[:batch_size])
|
124
|
-
yield batch
|
125
|
-
end
|
123
|
+
@target.send(pluck_method, :id, *options[:fields]).each_slice(options[:batch_size], &block)
|
126
124
|
elsif options[:fields].blank?
|
127
125
|
import_references(*args, options) do |batch|
|
128
126
|
yield batch.map { |object| object_field(object, :id) || object }
|
@@ -140,14 +138,12 @@ module Chewy
|
|
140
138
|
|
141
139
|
# For the Object adapter returns the objects themselves in batches.
|
142
140
|
#
|
143
|
-
# @see Chewy::
|
144
|
-
def import_references(*args)
|
141
|
+
# @see Chewy::Index::Adapter::Base#import_references
|
142
|
+
ruby2_keywords def import_references(*args, &block)
|
145
143
|
return enum_for(:import_references, *args) unless block_given?
|
146
144
|
|
147
145
|
collection, options = import_args(*args)
|
148
|
-
collection.each_slice(options[:batch_size])
|
149
|
-
yield batch
|
150
|
-
end
|
146
|
+
collection.each_slice(options[:batch_size], &block)
|
151
147
|
end
|
152
148
|
|
153
149
|
# This method is used internally by the request DSL when the
|
@@ -157,7 +153,7 @@ module Chewy
|
|
157
153
|
#
|
158
154
|
# If none of the `load_all_method` or `load_one_method` is implemented
|
159
155
|
# for the target - the method will return nil. This means that the
|
160
|
-
# loader will return an array `Chewy::
|
156
|
+
# loader will return an array `Chewy::Index` objects that actually was passed.
|
161
157
|
#
|
162
158
|
# To use loading for objects it is obviously required to provide
|
163
159
|
# some meaningful ids for ES documents.
|
@@ -175,7 +171,7 @@ module Chewy
|
|
175
171
|
# end
|
176
172
|
# end
|
177
173
|
#
|
178
|
-
# MyIndex
|
174
|
+
# MyIndex.load(additional_data: true).objects
|
179
175
|
#
|
180
176
|
# @param ids [Array<Hash>] an array of ids from ES hits
|
181
177
|
# @param options [Hash] any options passed here with the request DSL `load` method.
|
@@ -1,7 +1,7 @@
|
|
1
|
-
require 'chewy/
|
1
|
+
require 'chewy/index/adapter/base'
|
2
2
|
|
3
3
|
module Chewy
|
4
|
-
class
|
4
|
+
class Index
|
5
5
|
module Adapter
|
6
6
|
class Orm < Base
|
7
7
|
attr_reader :default_scope
|
@@ -45,6 +45,7 @@ module Chewy
|
|
45
45
|
# Import options:
|
46
46
|
#
|
47
47
|
# <tt>:batch_size</tt> - import batch size, 1000 objects by default
|
48
|
+
# <tt>:direct_import</tt> - import objects without reloading
|
48
49
|
#
|
49
50
|
# Method handles destroyed objects as well. In case of objects ORM scope
|
50
51
|
# or array passed, objects, responding with true to `destroyed?` method will be deleted
|
@@ -53,72 +54,73 @@ module Chewy
|
|
53
54
|
#
|
54
55
|
# users = User.all
|
55
56
|
# users.each { |user| user.destroy if user.inactive? }
|
56
|
-
# UsersIndex
|
57
|
+
# UsersIndex.import users # inactive users will be deleted from index
|
57
58
|
# # or
|
58
|
-
# UsersIndex
|
59
|
+
# UsersIndex.import users.map(&:id) # deleted user ids will be deleted from index
|
59
60
|
#
|
60
61
|
# Also there is custom type option `delete_if`. It it returns `true`
|
61
62
|
# object will be deleted from index. Note that if this option is defined and
|
62
63
|
# return `false` Chewy will still check `destroyed?` method. This is useful
|
63
64
|
# for paranoid objects deleting implementation.
|
64
65
|
#
|
65
|
-
#
|
66
|
-
#
|
67
|
-
# end
|
66
|
+
# index_scope User, delete_if: ->{ deleted_at }
|
67
|
+
# ...
|
68
68
|
#
|
69
69
|
# users = User.all
|
70
70
|
# users.each { |user| user.deleted_at = Time.now }
|
71
|
-
# UsersIndex
|
71
|
+
# UsersIndex.import users # paranoid deleted users will be deleted from index
|
72
72
|
# # or
|
73
|
-
# UsersIndex
|
73
|
+
# UsersIndex.import users.map(&:id) # user ids will be deleted from index
|
74
74
|
#
|
75
|
-
def import(*args, &block)
|
75
|
+
ruby2_keywords def import(*args, &block)
|
76
76
|
collection, options = import_args(*args)
|
77
77
|
|
78
|
-
if collection.is_a?(relation_class)
|
79
|
-
import_scope(collection, options, &block)
|
80
|
-
else
|
78
|
+
if !collection.is_a?(relation_class) || options[:direct_import]
|
81
79
|
import_objects(collection, options, &block)
|
80
|
+
else
|
81
|
+
import_scope(collection, options, &block)
|
82
82
|
end
|
83
83
|
end
|
84
84
|
|
85
|
-
def import_fields(*args, &block)
|
85
|
+
ruby2_keywords def import_fields(*args, &block)
|
86
86
|
return enum_for(:import_fields, *args) unless block_given?
|
87
87
|
|
88
88
|
collection, options = import_args(*args)
|
89
89
|
|
90
90
|
if options[:fields].present? || collection.is_a?(relation_class)
|
91
91
|
collection = all_scope_where_ids_in(identify(collection)) unless collection.is_a?(relation_class)
|
92
|
-
pluck_in_batches(collection, options.slice(:fields, :batch_size, :typecast), &block)
|
92
|
+
pluck_in_batches(collection, **options.slice(:fields, :batch_size, :typecast), &block)
|
93
93
|
else
|
94
|
-
identify(collection).each_slice(options[:batch_size])
|
95
|
-
yield batch
|
96
|
-
end
|
94
|
+
identify(collection).each_slice(options[:batch_size], &block)
|
97
95
|
end
|
98
96
|
end
|
99
97
|
alias_method :import_references, :import_fields
|
100
98
|
|
101
99
|
def load(ids, **options)
|
102
100
|
scope = all_scope_where_ids_in(ids)
|
103
|
-
additional_scope = options[options[:
|
101
|
+
additional_scope = options[options[:_index].to_sym].try(:[], :scope) || options[:scope]
|
104
102
|
|
105
103
|
loaded_objects = load_scope_objects(scope, additional_scope)
|
106
|
-
|
107
|
-
|
108
|
-
|
104
|
+
loaded_objects = raw(loaded_objects, options[:raw_import]) if options[:raw_import]
|
105
|
+
|
106
|
+
indexed_objects = loaded_objects.index_by do |object|
|
107
|
+
object.public_send(primary_key).to_s
|
108
|
+
end
|
109
109
|
|
110
|
-
ids.map { |id|
|
110
|
+
ids.map { |id| indexed_objects[id.to_s] }
|
111
111
|
end
|
112
112
|
|
113
113
|
private
|
114
114
|
|
115
115
|
def import_objects(collection, options)
|
116
116
|
collection_ids = identify(collection)
|
117
|
-
hash =
|
117
|
+
hash = collection_ids.map(&:to_s).zip(collection).to_h
|
118
118
|
|
119
119
|
indexed = collection_ids.each_slice(options[:batch_size]).map do |ids|
|
120
120
|
batch = if options[:raw_import]
|
121
121
|
raw_default_scope_where_ids_in(ids, options[:raw_import])
|
122
|
+
elsif options[:direct_import]
|
123
|
+
hash.values_at(*ids.map(&:to_s))
|
122
124
|
else
|
123
125
|
default_scope_where_ids_in(ids)
|
124
126
|
end
|
data/lib/chewy/index/aliases.rb
CHANGED
@@ -5,14 +5,23 @@ module Chewy
|
|
5
5
|
|
6
6
|
module ClassMethods
|
7
7
|
def indexes
|
8
|
-
client.indices.
|
9
|
-
|
10
|
-
|
8
|
+
indexes = empty_if_not_found { client.indices.get(index: index_name).keys }
|
9
|
+
indexes += empty_if_not_found { client.indices.get_alias(name: index_name).keys }
|
10
|
+
indexes.compact.uniq
|
11
11
|
end
|
12
12
|
|
13
13
|
def aliases
|
14
|
-
|
15
|
-
|
14
|
+
empty_if_not_found do
|
15
|
+
client.indices.get_alias(index: index_name, name: '*').values.flat_map do |aliases|
|
16
|
+
aliases['aliases'].keys
|
17
|
+
end
|
18
|
+
end.compact.uniq
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def empty_if_not_found
|
24
|
+
yield
|
16
25
|
rescue Elasticsearch::Transport::Transport::Errors::NotFound
|
17
26
|
[]
|
18
27
|
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Chewy
|
2
|
+
class Index
|
3
|
+
module Crutch
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
class_attribute :_crutches
|
8
|
+
self._crutches = {}
|
9
|
+
end
|
10
|
+
|
11
|
+
class Crutches
|
12
|
+
def initialize(index, collection)
|
13
|
+
@index = index
|
14
|
+
@collection = collection
|
15
|
+
@crutches_instances = {}
|
16
|
+
end
|
17
|
+
|
18
|
+
def method_missing(name, *, **)
|
19
|
+
return self[name] if @index._crutches.key?(name)
|
20
|
+
|
21
|
+
super
|
22
|
+
end
|
23
|
+
|
24
|
+
def respond_to_missing?(name, include_private = false)
|
25
|
+
@index._crutches.key?(name) || super
|
26
|
+
end
|
27
|
+
|
28
|
+
def [](name)
|
29
|
+
@crutches_instances[name] ||= @index._crutches[:"#{name}"].call(@collection)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
module ClassMethods
|
34
|
+
def crutch(name, &block)
|
35
|
+
self._crutches = _crutches.merge(name.to_sym => block)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|