chewy 0.8.4 → 5.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.gitignore +1 -0
- data/.rubocop.yml +56 -0
- data/.rubocop_todo.yml +44 -0
- data/.travis.yml +36 -67
- data/.yardopts +5 -0
- data/Appraisals +63 -58
- data/CHANGELOG.md +168 -11
- data/Gemfile +16 -9
- data/Guardfile +5 -5
- data/LEGACY_DSL.md +497 -0
- data/README.md +403 -470
- data/Rakefile +11 -1
- data/chewy.gemspec +12 -15
- data/gemfiles/rails.4.0.activerecord.gemfile +9 -9
- data/gemfiles/rails.4.1.activerecord.gemfile +9 -9
- data/gemfiles/rails.4.2.activerecord.gemfile +8 -8
- data/gemfiles/rails.4.2.mongoid.5.2.gemfile +16 -0
- data/gemfiles/rails.5.0.activerecord.gemfile +16 -0
- data/gemfiles/rails.5.0.mongoid.6.1.gemfile +16 -0
- data/gemfiles/rails.5.1.activerecord.gemfile +16 -0
- data/gemfiles/rails.5.1.mongoid.6.3.gemfile +16 -0
- data/gemfiles/rails.5.2.activerecord.gemfile +16 -0
- data/gemfiles/sequel.4.45.gemfile +11 -0
- data/lib/chewy/backports/deep_dup.rb +1 -1
- data/lib/chewy/backports/duplicable.rb +1 -0
- data/lib/chewy/config.rb +53 -21
- data/lib/chewy/errors.rb +6 -6
- data/lib/chewy/fields/base.rb +59 -29
- data/lib/chewy/fields/root.rb +49 -14
- data/lib/chewy/index/actions.rb +95 -36
- data/lib/chewy/index/aliases.rb +2 -1
- data/lib/chewy/index/settings.rb +10 -5
- data/lib/chewy/index/specification.rb +60 -0
- data/lib/chewy/index.rb +239 -138
- data/lib/chewy/journal.rb +55 -0
- data/lib/chewy/log_subscriber.rb +8 -8
- data/lib/chewy/minitest/helpers.rb +77 -0
- data/lib/chewy/minitest/search_index_receiver.rb +80 -0
- data/lib/chewy/minitest.rb +1 -0
- data/lib/chewy/query/compose.rb +18 -19
- data/lib/chewy/query/criteria.rb +34 -24
- data/lib/chewy/query/filters.rb +28 -11
- data/lib/chewy/query/loading.rb +3 -4
- data/lib/chewy/query/nodes/and.rb +1 -1
- data/lib/chewy/query/nodes/base.rb +1 -1
- data/lib/chewy/query/nodes/bool.rb +6 -4
- data/lib/chewy/query/nodes/equal.rb +4 -4
- data/lib/chewy/query/nodes/exists.rb +1 -1
- data/lib/chewy/query/nodes/expr.rb +2 -2
- data/lib/chewy/query/nodes/field.rb +35 -31
- data/lib/chewy/query/nodes/has_child.rb +1 -0
- data/lib/chewy/query/nodes/has_parent.rb +1 -0
- data/lib/chewy/query/nodes/has_relation.rb +10 -12
- data/lib/chewy/query/nodes/missing.rb +1 -1
- data/lib/chewy/query/nodes/not.rb +1 -1
- data/lib/chewy/query/nodes/or.rb +1 -1
- data/lib/chewy/query/nodes/prefix.rb +3 -2
- data/lib/chewy/query/nodes/query.rb +1 -1
- data/lib/chewy/query/nodes/range.rb +9 -9
- data/lib/chewy/query/nodes/raw.rb +1 -1
- data/lib/chewy/query/nodes/regexp.rb +13 -9
- data/lib/chewy/query/nodes/script.rb +4 -4
- data/lib/chewy/query/pagination.rb +10 -1
- data/lib/chewy/query.rb +286 -170
- data/lib/chewy/railtie.rb +7 -6
- data/lib/chewy/rake_helper.rb +275 -37
- data/lib/chewy/repository.rb +2 -2
- data/lib/chewy/rspec/update_index.rb +70 -65
- data/lib/chewy/rspec.rb +1 -1
- data/lib/chewy/runtime/version.rb +4 -4
- data/lib/chewy/search/loader.rb +83 -0
- data/lib/chewy/{query → search}/pagination/kaminari.rb +13 -5
- data/lib/chewy/search/pagination/will_paginate.rb +43 -0
- data/lib/chewy/search/parameters/aggs.rb +16 -0
- data/lib/chewy/search/parameters/allow_partial_search_results.rb +27 -0
- data/lib/chewy/search/parameters/concerns/bool_storage.rb +24 -0
- data/lib/chewy/search/parameters/concerns/hash_storage.rb +23 -0
- data/lib/chewy/search/parameters/concerns/integer_storage.rb +14 -0
- data/lib/chewy/search/parameters/concerns/query_storage.rb +238 -0
- data/lib/chewy/search/parameters/concerns/string_array_storage.rb +23 -0
- data/lib/chewy/search/parameters/concerns/string_storage.rb +14 -0
- data/lib/chewy/search/parameters/docvalue_fields.rb +12 -0
- data/lib/chewy/search/parameters/explain.rb +16 -0
- data/lib/chewy/search/parameters/filter.rb +47 -0
- data/lib/chewy/search/parameters/highlight.rb +16 -0
- data/lib/chewy/search/parameters/indices.rb +123 -0
- data/lib/chewy/search/parameters/indices_boost.rb +52 -0
- data/lib/chewy/search/parameters/limit.rb +17 -0
- data/lib/chewy/search/parameters/load.rb +32 -0
- data/lib/chewy/search/parameters/min_score.rb +16 -0
- data/lib/chewy/search/parameters/none.rb +27 -0
- data/lib/chewy/search/parameters/offset.rb +17 -0
- data/lib/chewy/search/parameters/order.rb +64 -0
- data/lib/chewy/search/parameters/post_filter.rb +19 -0
- data/lib/chewy/search/parameters/preference.rb +16 -0
- data/lib/chewy/search/parameters/profile.rb +16 -0
- data/lib/chewy/search/parameters/query.rb +19 -0
- data/lib/chewy/search/parameters/request_cache.rb +27 -0
- data/lib/chewy/search/parameters/rescore.rb +29 -0
- data/lib/chewy/search/parameters/script_fields.rb +16 -0
- data/lib/chewy/search/parameters/search_after.rb +20 -0
- data/lib/chewy/search/parameters/search_type.rb +16 -0
- data/lib/chewy/search/parameters/source.rb +73 -0
- data/lib/chewy/search/parameters/storage.rb +95 -0
- data/lib/chewy/search/parameters/stored_fields.rb +63 -0
- data/lib/chewy/search/parameters/suggest.rb +16 -0
- data/lib/chewy/search/parameters/terminate_after.rb +16 -0
- data/lib/chewy/search/parameters/timeout.rb +16 -0
- data/lib/chewy/search/parameters/track_scores.rb +16 -0
- data/lib/chewy/search/parameters/types.rb +20 -0
- data/lib/chewy/search/parameters/version.rb +16 -0
- data/lib/chewy/search/parameters.rb +167 -0
- data/lib/chewy/search/query_proxy.rb +257 -0
- data/lib/chewy/search/request.rb +1045 -0
- data/lib/chewy/search/response.rb +119 -0
- data/lib/chewy/search/scoping.rb +50 -0
- data/lib/chewy/search/scrolling.rb +134 -0
- data/lib/chewy/search.rb +81 -26
- data/lib/chewy/stash.rb +79 -0
- data/lib/chewy/strategy/active_job.rb +1 -0
- data/lib/chewy/strategy/atomic.rb +2 -4
- data/lib/chewy/strategy/base.rb +4 -4
- data/lib/chewy/strategy/bypass.rb +1 -2
- data/lib/chewy/strategy/resque.rb +1 -0
- data/lib/chewy/strategy/shoryuken.rb +40 -0
- data/lib/chewy/strategy/sidekiq.rb +13 -1
- data/lib/chewy/strategy/urgent.rb +1 -1
- data/lib/chewy/strategy.rb +19 -10
- data/lib/chewy/type/actions.rb +26 -2
- data/lib/chewy/type/adapter/active_record.rb +50 -24
- data/lib/chewy/type/adapter/base.rb +29 -9
- data/lib/chewy/type/adapter/mongoid.rb +19 -10
- data/lib/chewy/type/adapter/object.rb +195 -31
- data/lib/chewy/type/adapter/orm.rb +69 -33
- data/lib/chewy/type/adapter/sequel.rb +37 -19
- data/lib/chewy/type/crutch.rb +5 -4
- data/lib/chewy/type/import/bulk_builder.rb +122 -0
- data/lib/chewy/type/import/bulk_request.rb +78 -0
- data/lib/chewy/type/import/journal_builder.rb +45 -0
- data/lib/chewy/type/import/routine.rb +138 -0
- data/lib/chewy/type/import.rb +150 -176
- data/lib/chewy/type/mapping.rb +58 -42
- data/lib/chewy/type/observe.rb +21 -15
- data/lib/chewy/type/syncer.rb +222 -0
- data/lib/chewy/type/witchcraft.rb +89 -34
- data/lib/chewy/type/wrapper.rb +48 -16
- data/lib/chewy/type.rb +77 -49
- data/lib/chewy/version.rb +1 -1
- data/lib/chewy.rb +95 -52
- data/lib/generators/chewy/install_generator.rb +3 -3
- data/lib/sequel/plugins/chewy_observe.rb +4 -19
- data/lib/tasks/chewy.rake +91 -28
- data/spec/chewy/config_spec.rb +130 -12
- data/spec/chewy/fields/base_spec.rb +194 -172
- data/spec/chewy/fields/root_spec.rb +123 -17
- data/spec/chewy/fields/time_fields_spec.rb +10 -9
- data/spec/chewy/index/actions_spec.rb +228 -43
- data/spec/chewy/index/aliases_spec.rb +2 -2
- data/spec/chewy/index/settings_spec.rb +100 -49
- data/spec/chewy/index/specification_spec.rb +169 -0
- data/spec/chewy/index_spec.rb +159 -63
- data/spec/chewy/journal_spec.rb +268 -0
- data/spec/chewy/minitest/helpers_spec.rb +90 -0
- data/spec/chewy/minitest/search_index_receiver_spec.rb +120 -0
- data/spec/chewy/query/criteria_spec.rb +503 -236
- data/spec/chewy/query/filters_spec.rb +96 -68
- data/spec/chewy/query/loading_spec.rb +80 -42
- data/spec/chewy/query/nodes/and_spec.rb +3 -7
- data/spec/chewy/query/nodes/bool_spec.rb +5 -13
- data/spec/chewy/query/nodes/equal_spec.rb +20 -20
- data/spec/chewy/query/nodes/exists_spec.rb +7 -7
- data/spec/chewy/query/nodes/has_child_spec.rb +42 -23
- data/spec/chewy/query/nodes/has_parent_spec.rb +42 -23
- data/spec/chewy/query/nodes/match_all_spec.rb +2 -2
- data/spec/chewy/query/nodes/missing_spec.rb +6 -5
- data/spec/chewy/query/nodes/not_spec.rb +5 -7
- data/spec/chewy/query/nodes/or_spec.rb +3 -7
- data/spec/chewy/query/nodes/prefix_spec.rb +6 -6
- data/spec/chewy/query/nodes/query_spec.rb +3 -3
- data/spec/chewy/query/nodes/range_spec.rb +19 -19
- data/spec/chewy/query/nodes/raw_spec.rb +2 -2
- data/spec/chewy/query/nodes/regexp_spec.rb +31 -19
- data/spec/chewy/query/nodes/script_spec.rb +5 -5
- data/spec/chewy/query/pagination/kaminari_spec.rb +3 -55
- data/spec/chewy/query/pagination/will_paginate_spec.rb +5 -0
- data/spec/chewy/query/pagination_spec.rb +25 -22
- data/spec/chewy/query_spec.rb +510 -505
- data/spec/chewy/rake_helper_spec.rb +381 -0
- data/spec/chewy/repository_spec.rb +8 -8
- data/spec/chewy/rspec/update_index_spec.rb +215 -113
- data/spec/chewy/runtime_spec.rb +2 -2
- data/spec/chewy/search/loader_spec.rb +117 -0
- data/spec/chewy/search/pagination/kaminari_examples.rb +71 -0
- data/spec/chewy/search/pagination/kaminari_spec.rb +21 -0
- data/spec/chewy/search/pagination/will_paginate_examples.rb +63 -0
- data/spec/chewy/search/pagination/will_paginate_spec.rb +23 -0
- data/spec/chewy/search/parameters/aggs_spec.rb +5 -0
- data/spec/chewy/search/parameters/bool_storage_examples.rb +53 -0
- data/spec/chewy/search/parameters/docvalue_fields_spec.rb +5 -0
- data/spec/chewy/search/parameters/explain_spec.rb +5 -0
- data/spec/chewy/search/parameters/filter_spec.rb +5 -0
- data/spec/chewy/search/parameters/hash_storage_examples.rb +59 -0
- data/spec/chewy/search/parameters/highlight_spec.rb +5 -0
- data/spec/chewy/search/parameters/indices_spec.rb +191 -0
- data/spec/chewy/search/parameters/integer_storage_examples.rb +32 -0
- data/spec/chewy/search/parameters/limit_spec.rb +5 -0
- data/spec/chewy/search/parameters/load_spec.rb +60 -0
- data/spec/chewy/search/parameters/min_score_spec.rb +32 -0
- data/spec/chewy/search/parameters/none_spec.rb +5 -0
- data/spec/chewy/search/parameters/offset_spec.rb +5 -0
- data/spec/chewy/search/parameters/order_spec.rb +65 -0
- data/spec/chewy/search/parameters/post_filter_spec.rb +5 -0
- data/spec/chewy/search/parameters/preference_spec.rb +5 -0
- data/spec/chewy/search/parameters/profile_spec.rb +5 -0
- data/spec/chewy/search/parameters/query_spec.rb +5 -0
- data/spec/chewy/search/parameters/query_storage_examples.rb +388 -0
- data/spec/chewy/search/parameters/request_cache_spec.rb +67 -0
- data/spec/chewy/search/parameters/rescore_spec.rb +62 -0
- data/spec/chewy/search/parameters/script_fields_spec.rb +5 -0
- data/spec/chewy/search/parameters/search_after_spec.rb +32 -0
- data/spec/chewy/search/parameters/search_type_spec.rb +5 -0
- data/spec/chewy/search/parameters/source_spec.rb +156 -0
- data/spec/chewy/search/parameters/storage_spec.rb +60 -0
- data/spec/chewy/search/parameters/stored_fields_spec.rb +126 -0
- data/spec/chewy/search/parameters/string_array_storage_examples.rb +63 -0
- data/spec/chewy/search/parameters/string_storage_examples.rb +32 -0
- data/spec/chewy/search/parameters/suggest_spec.rb +5 -0
- data/spec/chewy/search/parameters/terminate_after_spec.rb +5 -0
- data/spec/chewy/search/parameters/timeout_spec.rb +5 -0
- data/spec/chewy/search/parameters/track_scores_spec.rb +5 -0
- data/spec/chewy/search/parameters/types_spec.rb +5 -0
- data/spec/chewy/search/parameters/version_spec.rb +5 -0
- data/spec/chewy/search/parameters_spec.rb +145 -0
- data/spec/chewy/search/query_proxy_spec.rb +68 -0
- data/spec/chewy/search/request_spec.rb +685 -0
- data/spec/chewy/search/response_spec.rb +192 -0
- data/spec/chewy/search/scrolling_spec.rb +169 -0
- data/spec/chewy/search_spec.rb +37 -20
- data/spec/chewy/stash_spec.rb +95 -0
- data/spec/chewy/strategy/active_job_spec.rb +8 -2
- data/spec/chewy/strategy/atomic_spec.rb +4 -1
- data/spec/chewy/strategy/resque_spec.rb +8 -2
- data/spec/chewy/strategy/shoryuken_spec.rb +66 -0
- data/spec/chewy/strategy/sidekiq_spec.rb +10 -2
- data/spec/chewy/strategy_spec.rb +6 -6
- data/spec/chewy/type/actions_spec.rb +29 -10
- data/spec/chewy/type/adapter/active_record_spec.rb +357 -139
- data/spec/chewy/type/adapter/mongoid_spec.rb +220 -101
- data/spec/chewy/type/adapter/object_spec.rb +129 -40
- data/spec/chewy/type/adapter/sequel_spec.rb +304 -152
- data/spec/chewy/type/import/bulk_builder_spec.rb +279 -0
- data/spec/chewy/type/import/bulk_request_spec.rb +102 -0
- data/spec/chewy/type/import/journal_builder_spec.rb +95 -0
- data/spec/chewy/type/import/routine_spec.rb +110 -0
- data/spec/chewy/type/import_spec.rb +360 -244
- data/spec/chewy/type/mapping_spec.rb +96 -29
- data/spec/chewy/type/observe_spec.rb +25 -15
- data/spec/chewy/type/syncer_spec.rb +123 -0
- data/spec/chewy/type/witchcraft_spec.rb +122 -44
- data/spec/chewy/type/wrapper_spec.rb +63 -23
- data/spec/chewy/type_spec.rb +32 -10
- data/spec/chewy_spec.rb +82 -12
- data/spec/spec_helper.rb +16 -2
- data/spec/support/active_record.rb +6 -2
- data/spec/support/class_helpers.rb +4 -19
- data/spec/support/mongoid.rb +17 -5
- data/spec/support/sequel.rb +6 -1
- metadata +250 -57
- data/gemfiles/rails.3.2.activerecord.gemfile +0 -15
- data/gemfiles/rails.3.2.activerecord.kaminari.gemfile +0 -14
- data/gemfiles/rails.3.2.activerecord.will_paginate.gemfile +0 -14
- data/gemfiles/rails.4.0.activerecord.kaminari.gemfile +0 -14
- data/gemfiles/rails.4.0.activerecord.will_paginate.gemfile +0 -14
- data/gemfiles/rails.4.0.mongoid.4.0.0.gemfile +0 -15
- data/gemfiles/rails.4.0.mongoid.4.0.0.kaminari.gemfile +0 -14
- data/gemfiles/rails.4.0.mongoid.4.0.0.will_paginate.gemfile +0 -14
- data/gemfiles/rails.4.0.mongoid.5.1.0.gemfile +0 -15
- data/gemfiles/rails.4.0.mongoid.5.1.0.kaminari.gemfile +0 -14
- data/gemfiles/rails.4.0.mongoid.5.1.0.will_paginate.gemfile +0 -14
- data/gemfiles/rails.4.1.activerecord.kaminari.gemfile +0 -14
- data/gemfiles/rails.4.1.activerecord.will_paginate.gemfile +0 -14
- data/gemfiles/rails.4.1.mongoid.4.0.0.gemfile +0 -15
- data/gemfiles/rails.4.1.mongoid.4.0.0.kaminari.gemfile +0 -14
- data/gemfiles/rails.4.1.mongoid.4.0.0.will_paginate.gemfile +0 -14
- data/gemfiles/rails.4.1.mongoid.5.1.0.gemfile +0 -15
- data/gemfiles/rails.4.1.mongoid.5.1.0.kaminari.gemfile +0 -14
- data/gemfiles/rails.4.1.mongoid.5.1.0.will_paginate.gemfile +0 -14
- data/gemfiles/rails.4.2.activerecord.kaminari.gemfile +0 -15
- data/gemfiles/rails.4.2.activerecord.will_paginate.gemfile +0 -15
- data/gemfiles/rails.4.2.mongoid.4.0.0.gemfile +0 -15
- data/gemfiles/rails.4.2.mongoid.4.0.0.kaminari.gemfile +0 -14
- data/gemfiles/rails.4.2.mongoid.4.0.0.will_paginate.gemfile +0 -14
- data/gemfiles/rails.4.2.mongoid.5.1.0.gemfile +0 -15
- data/gemfiles/rails.4.2.mongoid.5.1.0.kaminari.gemfile +0 -14
- data/gemfiles/rails.4.2.mongoid.5.1.0.will_paginate.gemfile +0 -14
- data/gemfiles/rails.5.0.0.beta3.activerecord.gemfile +0 -16
- data/gemfiles/rails.5.0.0.beta3.activerecord.kaminari.gemfile +0 -16
- data/gemfiles/rails.5.0.0.beta3.activerecord.will_paginate.gemfile +0 -15
- data/gemfiles/sequel.4.31.gemfile +0 -13
- data/lib/chewy/query/pagination/will_paginate.rb +0 -27
- data/lib/chewy/query/scoping.rb +0 -20
- data/spec/chewy/query/pagination/will_paginage_spec.rb +0 -60
data/README.md
CHANGED
@@ -4,11 +4,57 @@
|
|
4
4
|
[![Inline docs](http://inch-ci.org/github/toptal/chewy.svg?branch=master)](http://inch-ci.org/github/toptal/chewy)
|
5
5
|
|
6
6
|
<p align="right">Sponsored by</p>
|
7
|
-
<p align="right"><a href="
|
7
|
+
<p align="right"><a href="https://www.toptal.com/"><img src="https://www.toptal.com/assets/public/blocks/logo/big.png" alt="Toptal" width="105" height="34"></a></p>
|
8
8
|
|
9
9
|
# Chewy
|
10
10
|
|
11
|
-
Chewy is an ODM and wrapper for [the official Elasticsearch client](https://github.com/
|
11
|
+
Chewy is an ODM and wrapper for [the official Elasticsearch client](https://github.com/elastic/elasticsearch-ruby).
|
12
|
+
|
13
|
+
## Table of Contents
|
14
|
+
|
15
|
+
* [Why Chewy?](#why-chewy)
|
16
|
+
* [Installation](#installation)
|
17
|
+
* [Usage](#usage)
|
18
|
+
* [Client settings](#client-settings)
|
19
|
+
* [AWS ElasticSearch configuration](#aws-elastic-search)
|
20
|
+
* [Index definition](#index-definition)
|
21
|
+
* [Type default import options](#type-default-import-options)
|
22
|
+
* [Multi (nested) and object field types](#multi-nested-and-object-field-types)
|
23
|
+
* [Parent and children types](#parent-and-children-types)
|
24
|
+
* [Geo Point fields](#geo-point-fields)
|
25
|
+
* [Crutches™ technology](#crutches-technology)
|
26
|
+
* [Witchcraft™ technology](#witchcraft-technology)
|
27
|
+
* [Raw Import](#raw-import)
|
28
|
+
* [Index creation during import](#index-creation-during-import)
|
29
|
+
* [Journaling](#journaling)
|
30
|
+
* [Types access](#types-access)
|
31
|
+
* [Index manipulation](#index-manipulation)
|
32
|
+
* [Index update strategies](#index-update-strategies)
|
33
|
+
* [Nesting](#nesting)
|
34
|
+
* [Non-block notation](#non-block-notation)
|
35
|
+
* [Designing your own strategies](#designing-your-own-strategies)
|
36
|
+
* [Rails application strategies integration](#rails-application-strategies-integration)
|
37
|
+
* [ActiveSupport::Notifications support](#activesupportnotifications-support)
|
38
|
+
* [NewRelic integration](#newrelic-integration)
|
39
|
+
* [Search requests](#search-requests)
|
40
|
+
* [Composing requests](#composing-requests)
|
41
|
+
* [Pagination](#pagination)
|
42
|
+
* [Named scopes](#named-scopes)
|
43
|
+
* [Scroll API](#scroll-api)
|
44
|
+
* [Loading objects](#loading-objects)
|
45
|
+
* [Legacy DSL incompatibilities](#legacy-dsl-incompatibilities)
|
46
|
+
* [Rake tasks](#rake-tasks)
|
47
|
+
* [chewy:reset](#chewyreset)
|
48
|
+
* [chewy:upgrade](#chewyupgrade)
|
49
|
+
* [chewy:update](#chewyupdate)
|
50
|
+
* [chewy:sync](#chewysync)
|
51
|
+
* [chewy:deploy](#chewydeploy)
|
52
|
+
* [Parallelizing rake tasks](#parallelizing-rake-tasks)
|
53
|
+
* [chewy:journal](#chewyjournal)
|
54
|
+
* [Rspec integration](#rspec-integration)
|
55
|
+
* [Minitest integration](#minitest-integration)
|
56
|
+
* [TODO a.k.a coming soon](#todo-aka-coming-soon)
|
57
|
+
* [Contributing](#contributing)
|
12
58
|
|
13
59
|
## Why Chewy?
|
14
60
|
|
@@ -83,6 +129,26 @@ Chewy.logger = Logger.new(STDOUT)
|
|
83
129
|
|
84
130
|
See [config.rb](lib/chewy/config.rb) for more details.
|
85
131
|
|
132
|
+
#### Aws Elastic Search
|
133
|
+
If you would like to use AWS's ElasticSearch using an IAM user policy, you will need to sign your requests for the `es:*` action by injecting the appropriate headers passing a proc to `transport_options`.
|
134
|
+
|
135
|
+
```ruby
|
136
|
+
Chewy.settings = {
|
137
|
+
host: 'http://my-es-instance-on-aws.us-east-1.es.amazonaws.com:80',
|
138
|
+
transport_options: {
|
139
|
+
headers: { content_type: 'application/json' },
|
140
|
+
proc: -> (f) do
|
141
|
+
f.request :aws_signers_v4,
|
142
|
+
service_name: 'es',
|
143
|
+
region: 'us-east-1',
|
144
|
+
credentials: Aws::Credentials.new(
|
145
|
+
ENV['AWS_ACCESS_KEY'],
|
146
|
+
ENV['AWS_SECRET_ACCESS_KEY'])
|
147
|
+
end
|
148
|
+
}
|
149
|
+
}
|
150
|
+
```
|
151
|
+
|
86
152
|
### Index definition
|
87
153
|
|
88
154
|
1. Create `/app/chewy/users_index.rb`
|
@@ -125,7 +191,7 @@ See [config.rb](lib/chewy/config.rb) for more details.
|
|
125
191
|
end
|
126
192
|
```
|
127
193
|
|
128
|
-
[See here for mapping definitions](
|
194
|
+
[See here for mapping definitions](https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping.html).
|
129
195
|
|
130
196
|
4. Add some index- and type-related settings. Analyzer repositories might be used as well. See `Chewy::Index.settings` docs for details:
|
131
197
|
|
@@ -142,7 +208,7 @@ See [config.rb](lib/chewy/config.rb) for more details.
|
|
142
208
|
|
143
209
|
define_type User.active.includes(:country, :badges, :projects) do
|
144
210
|
root date_detection: false do
|
145
|
-
template 'about_translations.*', type: '
|
211
|
+
template 'about_translations.*', type: 'text', analyzer: 'standard'
|
146
212
|
|
147
213
|
field :first_name, :last_name
|
148
214
|
field :email, analyzer: 'email'
|
@@ -161,8 +227,8 @@ See [config.rb](lib/chewy/config.rb) for more details.
|
|
161
227
|
end
|
162
228
|
```
|
163
229
|
|
164
|
-
[See index settings here](
|
165
|
-
[See root object settings here](
|
230
|
+
[See index settings here](https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-update-settings.html).
|
231
|
+
[See root object settings here](https://www.elastic.co/guide/en/elasticsearch/reference/current/dynamic-field-mapping.html).
|
166
232
|
|
167
233
|
See [mapping.rb](lib/chewy/type/mapping.rb) for more details.
|
168
234
|
|
@@ -269,17 +335,29 @@ This will automatically set the type or root field to `object`. You may also spe
|
|
269
335
|
To define a multi field you have to specify any type except for `object` or `nested` in the root field:
|
270
336
|
|
271
337
|
```ruby
|
272
|
-
field :full_name, type: '
|
338
|
+
field :full_name, type: 'text', value: ->{ full_name.strip } do
|
273
339
|
field :ordered, analyzer: 'ordered'
|
274
340
|
field :untouched, index: 'not_analyzed'
|
275
341
|
end
|
276
342
|
```
|
277
343
|
|
278
|
-
The `value:` option for internal fields
|
344
|
+
The `value:` option for internal fields will no longer be effective.
|
345
|
+
|
346
|
+
### Parent and children types
|
279
347
|
|
348
|
+
To define [parent](https://www.elastic.co/guide/en/elasticsearch/guide/current/parent-child-mapping.html) type for a given index_type, you can include root options for the type where you can specify parent_type and parent_id
|
349
|
+
|
350
|
+
```ruby
|
351
|
+
define_type User.includes(:account) do
|
352
|
+
root parent: 'account', parent_id: ->{ account_id } do
|
353
|
+
field :created_at, type: 'date'
|
354
|
+
field :task_id, type: 'integer'
|
355
|
+
end
|
356
|
+
end
|
357
|
+
```
|
280
358
|
### Geo Point fields
|
281
359
|
|
282
|
-
You can use [Elasticsearch's geo mapping](https://www.elastic.co/guide/en/elasticsearch/reference/current/
|
360
|
+
You can use [Elasticsearch's geo mapping](https://www.elastic.co/guide/en/elasticsearch/reference/current/geo-point.html) with the `geo_point` field type, allowing you to query, filter and order by latitude and longitude. You can use the following hash format:
|
283
361
|
|
284
362
|
```ruby
|
285
363
|
field :coordinates, type: 'geo_point', value: ->{ {lat: latitude, lon: longitude} }
|
@@ -309,7 +387,7 @@ class ProductsIndex < Chewy::Index
|
|
309
387
|
end
|
310
388
|
```
|
311
389
|
|
312
|
-
Then the Chewy reindexing flow
|
390
|
+
Then the Chewy reindexing flow will look like the following pseudo-code (even in Mongoid):
|
313
391
|
|
314
392
|
```ruby
|
315
393
|
Product.includes(:categories).find_in_batches(1000) do |batch|
|
@@ -344,7 +422,7 @@ class ProductsIndex < Chewy::Index
|
|
344
422
|
end
|
345
423
|
```
|
346
424
|
|
347
|
-
An example flow
|
425
|
+
An example flow will look like this:
|
348
426
|
|
349
427
|
```ruby
|
350
428
|
Product.includes(:categories).find_in_batches(1000) do |batch|
|
@@ -395,7 +473,110 @@ end
|
|
395
473
|
```
|
396
474
|
|
397
475
|
And don't even ask how is it possible, it is a witchcraft.
|
398
|
-
Obviously not every type of definition might be compiled
|
476
|
+
Obviously not every type of definition might be compiled. There are some restrictions:
|
477
|
+
|
478
|
+
1. Use reasonable formatting to make `method_source` be able to extract field value proc sources.
|
479
|
+
2. Value procs with splat arguments are not supported right now.
|
480
|
+
3. If you are generating fields dynamically use value proc with arguments, argumentless value procs are not supported yet:
|
481
|
+
|
482
|
+
```ruby
|
483
|
+
[:first_name, :last_name].each do |name|
|
484
|
+
field name, value: -> (o) { o.send(name) }
|
485
|
+
end
|
486
|
+
```
|
487
|
+
|
488
|
+
However, it is quite possible that your type definition will be supported by Witchcraft™ technology out of the box in the most of the cases.
|
489
|
+
|
490
|
+
### Raw Import
|
491
|
+
|
492
|
+
Another way to speed up import time is Raw Imports. This technology is only available in ActiveRecord adapter. Very often, ActiveRecord model instantiation is what consumes most of the CPU and RAM resources. Precious time is wasted on converting, say, timestamps from strings and then serializing them back to strings. Chewy can operate on raw hashes of data directly obtained from the database. All you need is to provide a way to convert that hash to a lightweight object that mimics the behaviour of the normal ActiveRecord object.
|
493
|
+
|
494
|
+
```ruby
|
495
|
+
class LightweightProduct
|
496
|
+
def initialize(attributes)
|
497
|
+
@attributes = attributes
|
498
|
+
end
|
499
|
+
|
500
|
+
# Depending on the database, `created_at` might
|
501
|
+
# be in different formats. In PostgreSQL, for example,
|
502
|
+
# you might see the following format:
|
503
|
+
# "2016-03-22 16:23:22"
|
504
|
+
#
|
505
|
+
# Taking into account that Elastic expects something different,
|
506
|
+
# one might do something like the following, just to avoid
|
507
|
+
# unnecessary String -> DateTime -> String conversion.
|
508
|
+
#
|
509
|
+
# "2016-03-22 16:23:22" -> "2016-03-22T16:23:22Z"
|
510
|
+
def created_at
|
511
|
+
@attributes['created_at'].tr(' ', 'T') << 'Z'
|
512
|
+
end
|
513
|
+
end
|
514
|
+
|
515
|
+
define_type Product do
|
516
|
+
default_import_options raw_import: ->(hash) {
|
517
|
+
LightweightProduct.new(hash)
|
518
|
+
}
|
519
|
+
|
520
|
+
field :created_at, 'datetime'
|
521
|
+
end
|
522
|
+
```
|
523
|
+
|
524
|
+
Also, you can pass `:raw_import` option to the `import` method explicitly.
|
525
|
+
|
526
|
+
### Index creation during import
|
527
|
+
|
528
|
+
By default, when you perform import Chewy checks whether an index exists and creates it if it's absent.
|
529
|
+
You can turn off this feature to decrease Elasticsearch hits count.
|
530
|
+
To do so you need to set `skip_index_creation_on_import` parameter to `false` in your `config/chewy.yml`
|
531
|
+
|
532
|
+
|
533
|
+
### Journaling
|
534
|
+
|
535
|
+
You can record all actions that were made to the separate journal index in ElasticSearch.
|
536
|
+
When you create/update/destroy your documents, it will be saved in this special index.
|
537
|
+
If you make something with a batch of documents (e.g. during index reset) it will be saved as a one record, including primary keys of each document that was affected.
|
538
|
+
Common journal record looks like this:
|
539
|
+
|
540
|
+
```json
|
541
|
+
{
|
542
|
+
"action": "index",
|
543
|
+
"object_id": [1, 2, 3],
|
544
|
+
"index_name": "...",
|
545
|
+
"type_name": "...",
|
546
|
+
"created_at": "<timestamp>"
|
547
|
+
}
|
548
|
+
```
|
549
|
+
|
550
|
+
This feature is turned off by default.
|
551
|
+
But you can turn it on by setting `journal` setting to `true` in `config/chewy.yml`.
|
552
|
+
Also, you can specify journal index name. For example:
|
553
|
+
|
554
|
+
```yaml
|
555
|
+
# config/chewy.yml
|
556
|
+
production:
|
557
|
+
journal: true
|
558
|
+
journal_name: my_super_journal
|
559
|
+
```
|
560
|
+
|
561
|
+
Also, you can provide this option while you're importing some index:
|
562
|
+
|
563
|
+
```ruby
|
564
|
+
CityIndex.import journal: true
|
565
|
+
```
|
566
|
+
|
567
|
+
Or as a default import option for an index:
|
568
|
+
|
569
|
+
```ruby
|
570
|
+
class CityIndex
|
571
|
+
define_type City do
|
572
|
+
default_import_options journal: true
|
573
|
+
end
|
574
|
+
end
|
575
|
+
```
|
576
|
+
|
577
|
+
You may be wondering why do you need it? The answer is simple: not to lose the data.
|
578
|
+
|
579
|
+
Imagine that you reset your index in a zero-downtime manner (to separate index), and at the meantime somebody keeps updating the data frequently (to old index). So all these actions will be written to the journal index and you'll be able to apply them after index reset using the `Chewy::Journal` interface.
|
399
580
|
|
400
581
|
### Types access
|
401
582
|
|
@@ -404,6 +585,8 @@ You can access index-defined types with the following API:
|
|
404
585
|
```ruby
|
405
586
|
UsersIndex::User # => UsersIndex::User
|
406
587
|
UsersIndex.type_hash['user'] # => UsersIndex::User
|
588
|
+
UsersIndex.type('user') # => UsersIndex::User
|
589
|
+
UsersIndex.type('foo') # => raises error UndefinedType("Unknown type in UsersIndex: foo")
|
407
590
|
UsersIndex.types # => [UsersIndex::User]
|
408
591
|
UsersIndex.type_names # => ['user']
|
409
592
|
```
|
@@ -425,6 +608,7 @@ UsersIndex::User.import # import with 0 arguments process all the data specified
|
|
425
608
|
UsersIndex::User.import User.where('rating > 100') # or import specified users scope
|
426
609
|
UsersIndex::User.import User.where('rating > 100').to_a # or import specified users array
|
427
610
|
UsersIndex::User.import [1, 2, 42] # pass even ids for import, it will be handled in the most effective way
|
611
|
+
UsersIndex::User.import User.where('rating > 100'), update_fields: [:email] # if update fields are specified - it will update their values only with the `update` bulk action.
|
428
612
|
|
429
613
|
UsersIndex.import # import every defined type
|
430
614
|
UsersIndex.import user: User.where('rating > 100') # import only active users to `user` type.
|
@@ -504,6 +688,16 @@ Chewy.strategy(:active_job) do
|
|
504
688
|
end
|
505
689
|
```
|
506
690
|
|
691
|
+
#### `:shoryuken`
|
692
|
+
|
693
|
+
This does the same thing as `:atomic`, but asynchronously using shoryuken. Patch `Chewy::Strategy::Shoryuken::Worker` for index updates improving.
|
694
|
+
|
695
|
+
```ruby
|
696
|
+
Chewy.strategy(:shoryuken) do
|
697
|
+
City.popular.map(&:do_some_update_action!)
|
698
|
+
end
|
699
|
+
```
|
700
|
+
|
507
701
|
#### `:urgent`
|
508
702
|
|
509
703
|
The following strategy is convenient if you are going to update documents in your index one by one.
|
@@ -514,7 +708,7 @@ Chewy.strategy(:urgent) do
|
|
514
708
|
end
|
515
709
|
```
|
516
710
|
|
517
|
-
This code
|
711
|
+
This code will perform `City.popular.count` requests for ES documents update.
|
518
712
|
|
519
713
|
It is convenient for use in e.g. the Rails console with non-block notation:
|
520
714
|
|
@@ -579,569 +773,309 @@ RSpec.configure do |config|
|
|
579
773
|
end
|
580
774
|
```
|
581
775
|
|
582
|
-
###
|
583
|
-
|
584
|
-
```ruby
|
585
|
-
scope = UsersIndex.query(term: {name: 'foo'})
|
586
|
-
.filter(range: {rating: {gte: 100}})
|
587
|
-
.order(created: :desc)
|
588
|
-
.limit(20).offset(100)
|
589
|
-
|
590
|
-
scope.to_a # => will produce array of UserIndex::User or other types instances
|
591
|
-
scope.map { |user| user.email }
|
592
|
-
scope.total_count # => will return total objects count
|
593
|
-
|
594
|
-
scope.per(10).page(3) # supports kaminari pagination
|
595
|
-
scope.explain.map { |user| user._explanation }
|
596
|
-
scope.only(:id, :email) # returns ids and emails only
|
597
|
-
|
598
|
-
scope.merge(other_scope) # queries could be merged
|
599
|
-
```
|
776
|
+
### `ActiveSupport::Notifications` support
|
600
777
|
|
601
|
-
|
778
|
+
Chewy has notifying the following events:
|
602
779
|
|
603
|
-
|
604
|
-
UsersIndex::User.filter(term: {name: 'foo'}) # will return UserIndex::User collection only
|
605
|
-
```
|
780
|
+
#### `search_query.chewy` payload
|
606
781
|
|
607
|
-
|
608
|
-
`
|
782
|
+
* `payload[:index]`: requested index class
|
783
|
+
* `payload[:request]`: request hash
|
609
784
|
|
610
|
-
|
785
|
+
#### `import_objects.chewy` payload
|
611
786
|
|
612
|
-
|
787
|
+
* `payload[:type]`: currently imported type
|
788
|
+
* `payload[:import]`: imports stats, total imported and deleted objects count:
|
613
789
|
|
614
|
-
|
790
|
+
```ruby
|
791
|
+
{index: 30, delete: 5}
|
792
|
+
```
|
615
793
|
|
616
|
-
|
617
|
-
UsersIndex::User.filter{ name == 'Fred' }.filter{ age < 42 } # will be wrapped with `and` filter
|
618
|
-
UsersIndex::User.filter{ name == 'Fred' }.filter{ age < 42 }.filter_mode(:should) # will be wrapped with bool `should` filter
|
619
|
-
UsersIndex::User.filter{ name == 'Fred' }.filter{ age < 42 }.filter_mode('75%') # will be wrapped with bool `should` filter with `minimum_should_match: '75%'`
|
620
|
-
```
|
794
|
+
* `payload[:errors]`: might not exists. Contains grouped errors with objects ids list:
|
621
795
|
|
622
|
-
|
796
|
+
```ruby
|
797
|
+
{index: {
|
798
|
+
'error 1 text' => ['1', '2', '3'],
|
799
|
+
'error 2 text' => ['4']
|
800
|
+
}, delete: {
|
801
|
+
'delete error text' => ['10', '12']
|
802
|
+
}}
|
803
|
+
```
|
623
804
|
|
624
|
-
###
|
805
|
+
### NewRelic integration
|
625
806
|
|
626
|
-
|
807
|
+
To integrate with NewRelic you may use the following example source (config/initializers/chewy.rb):
|
627
808
|
|
628
809
|
```ruby
|
629
|
-
|
630
|
-
UsersIndex::User.delete_all
|
631
|
-
UsersIndex.filter{ age < 42 }.delete_all
|
632
|
-
UsersIndex::User.filter{ age < 42 }.delete_all
|
633
|
-
```
|
810
|
+
require 'new_relic/agent/instrumentation/evented_subscriber'
|
634
811
|
|
635
|
-
|
812
|
+
class ChewySubscriber < NewRelic::Agent::Instrumentation::EventedSubscriber
|
813
|
+
def start(name, id, payload)
|
814
|
+
event = ChewyEvent.new(name, Time.current, nil, id, payload)
|
815
|
+
push_event(event)
|
816
|
+
end
|
636
817
|
|
637
|
-
|
818
|
+
def finish(_name, id, _payload)
|
819
|
+
pop_event(id).finish
|
820
|
+
end
|
638
821
|
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
822
|
+
class ChewyEvent < NewRelic::Agent::Instrumentation::Event
|
823
|
+
OPERATIONS = {
|
824
|
+
'import_objects.chewy' => 'import',
|
825
|
+
'search_query.chewy' => 'search',
|
826
|
+
'delete_query.chewy' => 'delete'
|
827
|
+
}.freeze
|
643
828
|
|
644
|
-
|
829
|
+
def initialize(*args)
|
830
|
+
super
|
831
|
+
@segment = start_segment
|
832
|
+
end
|
645
833
|
|
646
|
-
|
834
|
+
def start_segment
|
835
|
+
segment = NewRelic::Agent::Transaction::DatastoreSegment.new product, operation, collection, host, port
|
836
|
+
if (txn = state.current_transaction)
|
837
|
+
segment.transaction = txn
|
838
|
+
end
|
839
|
+
segment.notice_sql @payload[:request].to_s
|
840
|
+
segment.start
|
841
|
+
segment
|
842
|
+
end
|
647
843
|
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
844
|
+
def finish
|
845
|
+
if (txn = state.current_transaction)
|
846
|
+
txn.add_segment @segment
|
847
|
+
end
|
848
|
+
@segment.finish
|
849
|
+
end
|
652
850
|
|
653
|
-
|
654
|
-
Consists of the field name (with or without dot notation), a value, and an action operator between them. The field name might take additional options for passing to the resulting expression.
|
851
|
+
private
|
655
852
|
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
UsersIndex.filter{ answers.title =~ /regexp/ } # regexp filter for `answers.title` field
|
660
|
-
```
|
661
|
-
|
662
|
-
You can combine expressions as you wish with the help of combination operators.
|
853
|
+
def state
|
854
|
+
@state ||= NewRelic::Agent::TransactionState.tl_get
|
855
|
+
end
|
663
856
|
|
664
|
-
|
665
|
-
|
666
|
-
|
667
|
-
must(
|
668
|
-
should(name =~ 'Fr').should_not(name == 'Fred') & (age == 42), email =~ /gmail\.com/
|
669
|
-
) | ((roles.admin == true) & name?)
|
670
|
-
} # many of the combination possibilities
|
671
|
-
```
|
857
|
+
def product
|
858
|
+
'Elasticsearch'
|
859
|
+
end
|
672
860
|
|
673
|
-
|
861
|
+
def operation
|
862
|
+
OPERATIONS[name]
|
863
|
+
end
|
674
864
|
|
675
|
-
|
676
|
-
|
677
|
-
|
865
|
+
def collection
|
866
|
+
payload.values_at(:type, :index)
|
867
|
+
.reject { |value| value.try(:empty?) }
|
868
|
+
.first
|
869
|
+
.to_s
|
870
|
+
end
|
678
871
|
|
679
|
-
|
680
|
-
|
681
|
-
|
872
|
+
def host
|
873
|
+
Chewy.client.transport.hosts.first[:host]
|
874
|
+
end
|
682
875
|
|
683
|
-
|
684
|
-
|
685
|
-
|
876
|
+
def port
|
877
|
+
Chewy.client.transport.hosts.first[:port]
|
878
|
+
end
|
879
|
+
end
|
880
|
+
end
|
686
881
|
|
687
|
-
|
688
|
-
UsersIndex.filter{ name(cache: 'name_regexp') =~ /Name/ }
|
689
|
-
# Or not
|
690
|
-
UsersIndex.filter{ name(cache: true) =~ /Name/ }
|
882
|
+
ActiveSupport::Notifications.subscribe(/.chewy$/, ChewySubscriber.new)
|
691
883
|
```
|
692
884
|
|
693
|
-
|
694
|
-
|
695
|
-
* Term filter
|
696
|
-
|
697
|
-
```json
|
698
|
-
{"term": {"name": "Fred"}}
|
699
|
-
{"not": {"term": {"name": "Johny"}}}
|
700
|
-
```
|
701
|
-
|
702
|
-
```ruby
|
703
|
-
UsersIndex.filter{ name == 'Fred' }
|
704
|
-
UsersIndex.filter{ name != 'Johny' }
|
705
|
-
```
|
706
|
-
|
707
|
-
* Terms filter
|
708
|
-
|
709
|
-
```json
|
710
|
-
{"terms": {"name": ["Fred", "Johny"]}}
|
711
|
-
{"not": {"terms": {"name": ["Fred", "Johny"]}}}
|
712
|
-
|
713
|
-
{"terms": {"name": ["Fred", "Johny"], "execution": "or"}}
|
714
|
-
|
715
|
-
{"terms": {"name": ["Fred", "Johny"], "execution": "and"}}
|
716
|
-
|
717
|
-
{"terms": {"name": ["Fred", "Johny"], "execution": "bool"}}
|
718
|
-
|
719
|
-
{"terms": {"name": ["Fred", "Johny"], "execution": "fielddata"}}
|
720
|
-
```
|
721
|
-
|
722
|
-
```ruby
|
723
|
-
UsersIndex.filter{ name == ['Fred', 'Johny'] }
|
724
|
-
UsersIndex.filter{ name != ['Fred', 'Johny'] }
|
725
|
-
|
726
|
-
UsersIndex.filter{ name(:|) == ['Fred', 'Johny'] }
|
727
|
-
UsersIndex.filter{ name(:or) == ['Fred', 'Johny'] }
|
728
|
-
UsersIndex.filter{ name(execution: :or) == ['Fred', 'Johny'] }
|
729
|
-
|
730
|
-
UsersIndex.filter{ name(:&) == ['Fred', 'Johny'] }
|
731
|
-
UsersIndex.filter{ name(:and) == ['Fred', 'Johny'] }
|
732
|
-
UsersIndex.filter{ name(execution: :and) == ['Fred', 'Johny'] }
|
885
|
+
### Search requests
|
733
886
|
|
734
|
-
|
735
|
-
UsersIndex.filter{ name(:bool) == ['Fred', 'Johny'] }
|
736
|
-
UsersIndex.filter{ name(execution: :bool) == ['Fred', 'Johny'] }
|
887
|
+
Long story short: there is a new DSL that supports ES2 and ES5, the previous DSL version (which supports ES1 and ES2) documentation was moved to [LEGACY_DSL.md](LEGACY_DSL.md).
|
737
888
|
|
738
|
-
|
739
|
-
UsersIndex.filter{ name(:fielddata) == ['Fred', 'Johny'] }
|
740
|
-
UsersIndex.filter{ name(execution: :fielddata) == ['Fred', 'Johny'] }
|
741
|
-
```
|
889
|
+
If you want to use the old DSL - simply do `Chewy.search_class = Chewy::Query` somewhere before indices are initialized.
|
742
890
|
|
743
|
-
|
891
|
+
The new DSL is enabled by default, here is a quick introduction.
|
744
892
|
|
745
|
-
|
746
|
-
{"regexp": {"name.first": "s.*y"}}
|
893
|
+
#### Composing requests
|
747
894
|
|
748
|
-
|
749
|
-
|
750
|
-
{"regexp": {"name.first": {"value": "s.*y", "flags": "ANYSTRING|INTERSECTION"}}}
|
751
|
-
```
|
895
|
+
The request DSL have the same chainable nature as AR or Mongoid ones. The main class is `Chewy::Search::Request`. It is possible to perform requests on behalf of indices or types:
|
752
896
|
|
753
|
-
|
754
|
-
|
755
|
-
|
756
|
-
|
757
|
-
UsersIndex.filter{ name.first != /s.*y/ }
|
758
|
-
UsersIndex.filter{ name.first !~ /s.*y/ }
|
759
|
-
|
760
|
-
UsersIndex.filter{ name.first(:anystring, :intersection) == /s.*y/ }
|
761
|
-
UsersIndex.filter{ name.first(flags: [:anystring, :intersection]) == /s.*y/ }
|
762
|
-
```
|
763
|
-
|
764
|
-
* Prefix filter
|
765
|
-
|
766
|
-
```json
|
767
|
-
{"prefix": {"name": "Fre"}}
|
768
|
-
{"not": {"prefix": {"name": "Joh"}}}
|
769
|
-
```
|
770
|
-
|
771
|
-
```ruby
|
772
|
-
UsersIndex.filter{ name =~ re' }
|
773
|
-
UsersIndex.filter{ name !~ 'Joh' }
|
774
|
-
```
|
775
|
-
|
776
|
-
* Exists filter
|
777
|
-
|
778
|
-
```json
|
779
|
-
{"exists": {"field": "name"}}
|
780
|
-
```
|
781
|
-
|
782
|
-
```ruby
|
783
|
-
UsersIndex.filter{ name? }
|
784
|
-
UsersIndex.filter{ !!name }
|
785
|
-
UsersIndex.filter{ !!name? }
|
786
|
-
UsersIndex.filter{ name != nil }
|
787
|
-
UsersIndex.filter{ !(name == nil) }
|
788
|
-
```
|
789
|
-
|
790
|
-
* Missing filter
|
791
|
-
|
792
|
-
```json
|
793
|
-
{"missing": {"field": "name", "existence": true, "null_value": false}}
|
794
|
-
{"missing": {"field": "name", "existence": true, "null_value": true}}
|
795
|
-
{"missing": {"field": "name", "existence": false, "null_value": true}}
|
796
|
-
```
|
797
|
-
|
798
|
-
```ruby
|
799
|
-
UsersIndex.filter{ !name }
|
800
|
-
UsersIndex.filter{ !name? }
|
801
|
-
UsersIndex.filter{ name == nil }
|
802
|
-
```
|
803
|
-
|
804
|
-
* Range
|
805
|
-
|
806
|
-
```json
|
807
|
-
{"range": {"age": {"gt": 42}}}
|
808
|
-
{"range": {"age": {"gte": 42}}}
|
809
|
-
{"range": {"age": {"lt": 42}}}
|
810
|
-
{"range": {"age": {"lte": 42}}}
|
811
|
-
|
812
|
-
{"range": {"age": {"gt": 40, "lt": 50}}}
|
813
|
-
{"range": {"age": {"gte": 40, "lte": 50}}}
|
814
|
-
|
815
|
-
{"range": {"age": {"gt": 40, "lte": 50}}}
|
816
|
-
{"range": {"age": {"gte": 40, "lt": 50}}}
|
817
|
-
```
|
818
|
-
|
819
|
-
```ruby
|
820
|
-
UsersIndex.filter{ age > 42 }
|
821
|
-
UsersIndex.filter{ age >= 42 }
|
822
|
-
UsersIndex.filter{ age < 42 }
|
823
|
-
UsersIndex.filter{ age <= 42 }
|
824
|
-
|
825
|
-
UsersIndex.filter{ age == (40..50) }
|
826
|
-
UsersIndex.filter{ (age > 40) & (age < 50) }
|
827
|
-
UsersIndex.filter{ age == [40..50] }
|
828
|
-
UsersIndex.filter{ (age >= 40) & (age <= 50) }
|
829
|
-
|
830
|
-
UsersIndex.filter{ (age > 40) & (age <= 50) }
|
831
|
-
UsersIndex.filter{ (age >= 40) & (age < 50) }
|
832
|
-
```
|
833
|
-
|
834
|
-
* Bool filter
|
835
|
-
|
836
|
-
```json
|
837
|
-
{"bool": {
|
838
|
-
"must": [{"term": {"name": "Name"}}],
|
839
|
-
"should": [{"term": {"age": 42}}, {"term": {"age": 45}}]
|
840
|
-
}}
|
841
|
-
```
|
842
|
-
|
843
|
-
```ruby
|
844
|
-
UsersIndex.filter{ must(name == 'Name').should(age == 42, age == 45) }
|
845
|
-
```
|
846
|
-
|
847
|
-
* And filter
|
848
|
-
|
849
|
-
```json
|
850
|
-
{"and": [{"term": {"name": "Name"}}, {"range": {"age": {"lt": 42}}}]}
|
851
|
-
```
|
852
|
-
|
853
|
-
```ruby
|
854
|
-
UsersIndex.filter{ (name == 'Name') & (age < 42) }
|
855
|
-
```
|
856
|
-
|
857
|
-
* Or filter
|
897
|
+
```ruby
|
898
|
+
PlaceIndex.query(match: {name: 'London'}) # returns documents of any type
|
899
|
+
PlaceIndex::City.query(match: {name: 'London'}) # returns cities only.
|
900
|
+
```
|
858
901
|
|
859
|
-
|
860
|
-
{"or": [{"term": {"name": "Name"}}, {"range": {"age": {"lt": 42}}}]}
|
861
|
-
```
|
902
|
+
Main methods of the request DSL are: `query`, `filter` and `post_filter`, it is possible to pass pure query hashes or use `elasticsearch-dsl`. Also, there is an additional
|
862
903
|
|
863
|
-
|
864
|
-
|
865
|
-
|
904
|
+
```ruby
|
905
|
+
PlaceIndex
|
906
|
+
.filter(term: {name: 'Bangkok'})
|
907
|
+
.query { match name: 'London' }
|
908
|
+
.query.not(range: {population: {gt: 1_000_000}})
|
909
|
+
```
|
866
910
|
|
867
|
-
|
868
|
-
{"not": {"term": {"name": "Name"}}}
|
869
|
-
{"not": {"range": {"age": {"lt": 42}}}}
|
870
|
-
```
|
911
|
+
See https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl.html and https://github.com/elastic/elasticsearch-ruby/tree/master/elasticsearch-dsl for more details.
|
871
912
|
|
872
|
-
|
873
|
-
UsersIndex.filter{ !(name == 'Name') } # or UsersIndex.filter{ name != 'Name' }
|
874
|
-
UsersIndex.filter{ !(age < 42) }
|
875
|
-
```
|
913
|
+
An important part of requests manipulation is merging. There are 4 methods to perform it: `merge`, `and`, `or`, `not`. See [Chewy::Search::QueryProxy](lib/chewy/search/query_proxy.rb) for details. Also, `only` and `except` methods help to remove unneeded parts of the request.
|
876
914
|
|
877
|
-
|
915
|
+
Every other request part is covered by a bunch of additional methods, see [Chewy::Search::Request](lib/chewy/search/request.rb) for details:
|
878
916
|
|
879
|
-
|
880
|
-
|
881
|
-
|
917
|
+
```ruby
|
918
|
+
PlaceIndex.limit(10).offset(30).order(:name, {population: {order: :desc}})
|
919
|
+
```
|
882
920
|
|
883
|
-
|
884
|
-
UsersIndex.filter{ match_all }
|
885
|
-
```
|
921
|
+
Request DSL also provides additional scope actions, like `delete_all`, `exists?`, `count`, `pluck`, etc.
|
886
922
|
|
887
|
-
|
923
|
+
#### Pagination
|
888
924
|
|
889
|
-
|
890
|
-
{"has_child": {"type": "blog_tag", "query": {"term": {"tag": "something"}}}
|
891
|
-
{"has_child": {"type": "comment", "filter": {"term": {"user": "john"}}}
|
892
|
-
```
|
925
|
+
The request DSL supports pagination with `Kaminari` and `WillPaginate`. An appropriate extension is enabled on initializtion if any of libraries is available. See [Chewy::Search](lib/chewy/search.rb) and [Chewy::Search::Pagination](lib/chewy/search/pagination/) namespace for details.
|
893
926
|
|
894
|
-
|
895
|
-
UsersIndex.filter{ has_child(:blog_tag).query(term: {tag: 'something'}) }
|
896
|
-
UsersIndex.filter{ has_child(:comment).filter{ user == 'john' } }
|
897
|
-
```
|
927
|
+
#### Named scopes
|
898
928
|
|
899
|
-
|
929
|
+
Chewy supports named scopes functionality. There is no specialized DSL for named scopes definition, it is simply about defining class methods.
|
900
930
|
|
901
|
-
|
902
|
-
{"has_parent": {"type": "blog", "query": {"term": {"tag": "something"}}}}
|
903
|
-
{"has_parent": {"type": "blog", "filter": {"term": {"text": "bonsai three"}}}}
|
904
|
-
```
|
931
|
+
See [Chewy::Search::Scoping](lib/chewy/search/scoping.rb) for details.
|
905
932
|
|
906
|
-
|
907
|
-
UsersIndex.filter{ has_parent(:blog).query(term: {tag: 'something'}) }
|
908
|
-
UsersIndex.filter{ has_parent(:blog).filter{ text == 'bonsai three' } }
|
909
|
-
```
|
933
|
+
#### Scroll API
|
910
934
|
|
911
|
-
|
935
|
+
ElasticSearch scroll API is utilized by a bunch of methods: `scroll_batches`, `scroll_hits`, `scroll_wrappers` and `scroll_objects`.
|
912
936
|
|
913
|
-
|
937
|
+
See [Chewy::Search::Scrolling](lib/chewy/search/scrolling.rb) for details.
|
914
938
|
|
915
|
-
|
939
|
+
#### Loading objects
|
916
940
|
|
917
|
-
|
941
|
+
It is possible to load ORM/ODM source objects with the `objects` method. To provide additional loading options use `load` method:
|
918
942
|
|
919
943
|
```ruby
|
920
|
-
|
921
|
-
|
922
|
-
|
923
|
-
Let's look at what we asked from Elasticsearch. The facets setter method accepts a hash. You can choose custom/semantic key names for this hash for your own convenience (in this case I used the plural version of the actual field), in our case `countries`. The following nested hash tells ES to grab and aggregate values (terms) from the `country` field on our indexed records.
|
924
|
-
|
925
|
-
The response will include the `:facets` sidechannel:
|
926
|
-
|
944
|
+
PlacesIndex.load(scope: -> { active }).to_a # to_a returns `Chewy::Type` wrappers.
|
945
|
+
PlacesIndex.load(scope: -> { active }).objects # An array of AR source objects.
|
927
946
|
```
|
928
|
-
< { ... ,"facets":{"countries":{"_type":"terms","missing":?,"total":?,"other":?,"terms":[{"term":"USA","count":?},{"term":"Brazil","count":?}, ...}}
|
929
|
-
```
|
930
|
-
|
931
|
-
### Aggregations
|
932
|
-
|
933
|
-
Aggregations are part of the optional sidechannel that can be requested with a query.
|
934
947
|
|
935
|
-
|
948
|
+
See [Chewy::Search::Loader](lib/chewy/search/loader.rb) for more details.
|
936
949
|
|
937
|
-
|
950
|
+
In case when it is necessary to iterate through both of the wrappers and objects simultaneously, `object_hash` method helps a lot:
|
938
951
|
|
939
952
|
```ruby
|
940
|
-
|
941
|
-
|
942
|
-
|
943
|
-
field :rating
|
944
|
-
end
|
953
|
+
scope = PlacesIndex.load(scope: -> { active })
|
954
|
+
scope.each do |wrapper|
|
955
|
+
scope.object_hash[wrapper]
|
945
956
|
end
|
946
|
-
|
947
|
-
all_johns = UsersIndex::User.filter { name == 'john' }.aggs({ avg_rating: { avg: { field: 'rating' } } })
|
948
|
-
|
949
|
-
avg_johns_rating = all_johns.aggs
|
950
|
-
# => {"avg_rating"=>{"value"=>3.5}}
|
951
957
|
```
|
952
958
|
|
953
|
-
|
954
|
-
which is also available under the .agg alias method.
|
955
|
-
|
956
|
-
Here's the same example from before
|
957
|
-
|
958
|
-
```ruby
|
959
|
-
class UsersIndex < Chewy::Index
|
960
|
-
define_type User do
|
961
|
-
field :name
|
962
|
-
field :rating, type: "long"
|
963
|
-
agg :avg_rating do
|
964
|
-
{ avg: { field: 'rating' } }
|
965
|
-
end
|
966
|
-
end
|
967
|
-
end
|
959
|
+
#### Legacy DSL incompatibilities
|
968
960
|
|
969
|
-
|
961
|
+
* Filters advanced block DSL is not supported anymore, `elasticsearch-dsl` is used instead.
|
962
|
+
* Things like `query_mode` and `filter_mode` are in past, use advanced DSL to achieve similar behavior. See [Chewy::Search::QueryProxy](lib/chewy/search/query_proxy.rb) for details.
|
963
|
+
* `preload` method is no more, the collection returned by scope doesn't depend on loading options, scope always returns `Chewy::Type` wrappers. To get ORM/ODM objects, use `#objects` method.
|
964
|
+
* Some of the methods have changed their purpose: `only` was used to filter fields before, now it filters the scope. To filter fields use `source` or `stored_fields`.
|
965
|
+
* `types!` method is no more, use `except(:types).types(...)`
|
966
|
+
* Named aggregations are not supported, use named scopes instead.
|
967
|
+
* A lot of query-level methods were not ported: everything that is related to boost and scoring. Use `query` manipulation to provide them.
|
968
|
+
* `Chewy::Type#_object` returns nil always. Use `Chewy::Search::Response#object_hash` instead.
|
970
969
|
|
971
|
-
|
972
|
-
# => {"avg_rating"=>{"value"=>3.5}}
|
973
|
-
```
|
970
|
+
### Rake tasks
|
974
971
|
|
975
|
-
|
976
|
-
with the same name. To explicitly reference an aggregation you provide a string to the #aggs method of the form:
|
977
|
-
`index_name#document_type.aggregation_name`
|
972
|
+
For a Rails application, some index-maintaining rake tasks are defined.
|
978
973
|
|
979
|
-
|
974
|
+
#### `chewy:reset`
|
980
975
|
|
981
|
-
|
982
|
-
class UsersIndex < Chewy::Index
|
983
|
-
define_type User do
|
984
|
-
field :name
|
985
|
-
field :rating, type: "long"
|
986
|
-
agg :avg_rating do
|
987
|
-
{ avg: { field: 'rating' } }
|
988
|
-
end
|
989
|
-
end
|
990
|
-
define_type Post do
|
991
|
-
field :title
|
992
|
-
field :body
|
993
|
-
field :comments do
|
994
|
-
field :message
|
995
|
-
field :rating, type: "long"
|
996
|
-
end
|
997
|
-
agg :avg_rating do
|
998
|
-
{ avg: { field: 'comments.rating' } }
|
999
|
-
end
|
1000
|
-
end
|
1001
|
-
end
|
976
|
+
Performs zero-downtime reindexing as described [here](https://www.elastic.co/blog/changing-mapping-with-zero-downtime). So the rake task creates a new index with unique suffix and then simply aliases it to the common index name. The previous index is deleted afterwards (see `Chewy::Index.reset!` for more details).
|
1002
977
|
|
1003
|
-
|
1004
|
-
|
1005
|
-
#
|
978
|
+
```bash
|
979
|
+
rake chewy:reset # resets all the existing indices
|
980
|
+
rake chewy:reset[users] # resets UsersIndex only
|
981
|
+
rake chewy:reset[users,places] # resets UsersIndex and PlacesIndex
|
982
|
+
rake chewy:reset[-users,places] # resets every index in the application except specified ones
|
1006
983
|
```
|
1007
984
|
|
1008
|
-
|
985
|
+
#### `chewy:upgrade`
|
1009
986
|
|
1010
|
-
|
987
|
+
Performs reset exactly the same way as `chewy:reset` does, but only when the index specification (setting or mapping) was changed.
|
1011
988
|
|
1012
|
-
|
1013
|
-
UsersIndex.script_fields(
|
1014
|
-
distance: {
|
1015
|
-
params: {
|
1016
|
-
lat: 37.569976,
|
1017
|
-
lon: -122.351591
|
1018
|
-
},
|
1019
|
-
script: "doc['coordinates'].distanceInMiles(lat, lon)"
|
1020
|
-
}
|
1021
|
-
)
|
1022
|
-
```
|
1023
|
-
Here, `coordinates` is a field with type `geo_point`. There will be a `distance` field for the index's model in the search result.
|
989
|
+
It works only when index specification is locked in `Chewy::Stash::Specification` index. The first run will reset all indexes and lock their specifications.
|
1024
990
|
|
1025
|
-
|
991
|
+
See [Chewy::Stash::Specification](lib/chewy/stash.rb) and [Chewy::Index::Specification](lib/chewy/index/specification.rb) for more details.
|
1026
992
|
|
1027
|
-
Script scoring is used to score the search results. All scores are added to the search request and combined according to boost mode and score mode. This can be useful if, for example, a score function is computationally expensive and it is sufficient to compute the score on a filtered set of documents. For example, you might want to multiply the score by another numeric field in the doc:
|
1028
993
|
|
1029
|
-
```
|
1030
|
-
|
994
|
+
```bash
|
995
|
+
rake chewy:upgrade # upgrades all the existing indices
|
996
|
+
rake chewy:upgrade[users] # upgrades UsersIndex only
|
997
|
+
rake chewy:upgrade[users,places] # upgrades UsersIndex and PlacesIndex
|
998
|
+
rake chewy:upgrade[-users,places] # upgrades every index in the application except specified ones
|
1031
999
|
```
|
1032
1000
|
|
1033
|
-
|
1001
|
+
#### `chewy:update`
|
1034
1002
|
|
1035
|
-
|
1003
|
+
It doesn't create indexes, it simply imports everything to the existing ones and fails if the index was not created before.
|
1036
1004
|
|
1037
|
-
|
1038
|
-
|
1005
|
+
Unlike `reset` or `upgrade` tasks, it is possible to pass type references to update the particular type. In index name is passed without the type specified, it will update all the types defined for this index.
|
1006
|
+
|
1007
|
+
```bash
|
1008
|
+
rake chewy:update # updates all the existing indices
|
1009
|
+
rake chewy:update[users] # updates UsersIndex only
|
1010
|
+
rake chewy:update[users,places#city] # updates the whole UsersIndex and PlacesIndex::City type
|
1011
|
+
rake chewy:update[-users,places#city] # updates every index in the application except every type defined in UsersIndex and the rest of the types defined in PlacesIndex
|
1039
1012
|
```
|
1040
1013
|
|
1041
|
-
|
1014
|
+
#### `chewy:sync`
|
1042
1015
|
|
1043
|
-
|
1016
|
+
Provides a way to synchronize outdated indexes with the source quickly and without doing a full reset.
|
1044
1017
|
|
1045
|
-
|
1046
|
-
scope = UsersIndex.filter(range: {rating: {gte: 100}})
|
1018
|
+
Arguments are similar to the ones taken by `chewy:update` task. It is possible to specify a particular type or a whole index.
|
1047
1019
|
|
1048
|
-
|
1049
|
-
scope.load.query(...) # => since objects are loaded lazily you can complete scope
|
1050
|
-
scope.load(user: { scope: ->{ includes(:country) }}) # you can also pass loading scopes for each
|
1051
|
-
# possibly returned type
|
1052
|
-
scope.load(user: { scope: User.includes(:country) }) # the second scope passing way.
|
1053
|
-
scope.load(scope: ->{ includes(:country) }) # and more common scope applied to every loaded object type.
|
1020
|
+
See [Chewy::Type::Syncer](lib/chewy/type/syncer.rb) for more details.
|
1054
1021
|
|
1055
|
-
|
1022
|
+
```bash
|
1023
|
+
rake chewy:sync # synchronizes all the existing indices
|
1024
|
+
rake chewy:sync[users] # synchronizes UsersIndex only
|
1025
|
+
rake chewy:sync[users,places#city] # synchronizes the whole UsersIndex and PlacesIndex::City type
|
1026
|
+
rake chewy:sync[-users,places#city] # synchronizes every index in the application except every type defined in UsersIndex and the rest of the types defined in PlacesIndex
|
1056
1027
|
```
|
1057
1028
|
|
1058
|
-
|
1029
|
+
#### `chewy:deploy`
|
1059
1030
|
|
1060
|
-
|
1061
|
-
UsersIndex.filter(range: {rating: {gte: 100}}).preload(...).query(...).map(&:_object)
|
1062
|
-
```
|
1031
|
+
This rake task is especially useful during the production deploy. It is a combination of `chewy:upgrade` and `chewy:sync` and the latter is called only for the indexes that were not reset during the first stage.
|
1063
1032
|
|
1064
|
-
|
1033
|
+
It is not possible to specify any particular types/indexes for this task as it doesn't make much sense.
|
1065
1034
|
|
1066
|
-
|
1035
|
+
Right now the approach is that if some data had been updated, but index definition was not changed (no changes satisfying the synchronization algorithm were done), it would be much faster to perform manual partial index update inside data migrations or even manually after the deploy.
|
1067
1036
|
|
1068
|
-
|
1037
|
+
Also, there is always full reset alternative with `rake chewy:reset`.
|
1069
1038
|
|
1070
|
-
####
|
1039
|
+
#### Parallelizing rake tasks
|
1071
1040
|
|
1072
|
-
|
1073
|
-
* `payload[:request]`: request hash
|
1041
|
+
Every task described above has its own parallel version. Every parallel rake task takes the number for processes for execution as the first argument and the rest of the arguments are exactly the same as for the non-parallel task version.
|
1074
1042
|
|
1075
|
-
|
1043
|
+
[https://github.com/grosser/parallel](https://github.com/grosser/parallel) gem is required to use these tasks.
|
1076
1044
|
|
1077
|
-
|
1078
|
-
* `payload[:import]`: imports stats, total imported and deleted objects count:
|
1079
|
-
|
1080
|
-
```ruby
|
1081
|
-
{index: 30, delete: 5}
|
1082
|
-
```
|
1083
|
-
|
1084
|
-
* `payload[:errors]`: might not exists. Contains grouped errors with objects ids list:
|
1085
|
-
|
1086
|
-
```ruby
|
1087
|
-
{index: {
|
1088
|
-
'error 1 text' => ['1', '2', '3'],
|
1089
|
-
'error 2 text' => ['4']
|
1090
|
-
}, delete: {
|
1091
|
-
'delete error text' => ['10', '12']
|
1092
|
-
}}
|
1093
|
-
```
|
1045
|
+
If the number of processes is not specified explicitly - `parallel` gem tries to automatically derive the number of processes to use.
|
1094
1046
|
|
1095
|
-
|
1096
|
-
|
1097
|
-
|
1047
|
+
```bash
|
1048
|
+
rake chewy:parallel:reset
|
1049
|
+
rake chewy:parallel:upgrade[4]
|
1050
|
+
rake chewy:parallel:update[4,places#city]
|
1051
|
+
rake chewy:parallel:sync[4,-users]
|
1052
|
+
rake chewy:parallel:deploy[4] # performs parallel upgrade and parallel sync afterwards
|
1053
|
+
```
|
1098
1054
|
|
1099
|
-
|
1100
|
-
ActiveSupport::Notifications.subscribe('import_objects.chewy') do |name, start, finish, id, payload|
|
1101
|
-
metric_name = "Database/ElasticSearch/import"
|
1102
|
-
duration = (finish - start).to_f
|
1103
|
-
logged = "#{payload[:type]} #{payload[:import].to_a.map{ |i| i.join(':') }.join(', ')}"
|
1104
|
-
|
1105
|
-
self.class.trace_execution_scoped([metric_name]) do
|
1106
|
-
NewRelic::Agent.instance.transaction_sampler.notice_sql(logged, nil, duration)
|
1107
|
-
NewRelic::Agent.instance.sql_sampler.notice_sql(logged, metric_name, nil, duration)
|
1108
|
-
NewRelic::Agent.record_metric(metric_name, duration)
|
1109
|
-
end
|
1110
|
-
end
|
1055
|
+
#### `chewy:journal`
|
1111
1056
|
|
1112
|
-
|
1113
|
-
metric_name = "Database/ElasticSearch/search"
|
1114
|
-
duration = (finish - start).to_f
|
1115
|
-
logged = "#{payload[:type].presence || payload[:index]} #{payload[:request]}"
|
1057
|
+
This namespace contains two tasks for the journal manipulations: `chewy:journal:apply` and `chewy:journal:clean`. Both are taking time as the first argument (optional for clean) and a list of indexes/types exactly as the tasks above. Time can be in any format parsable by ActiveSupport.
|
1116
1058
|
|
1117
|
-
|
1118
|
-
|
1119
|
-
|
1120
|
-
NewRelic::Agent.record_metric(metric_name, duration)
|
1121
|
-
end
|
1122
|
-
end
|
1059
|
+
```bash
|
1060
|
+
rake chewy:journal:apply["$(date -v-1H -u +%FT%TZ)"] # apply journaled changes for the past hour
|
1061
|
+
rake chewy:journal:apply["$(date -v-1H -u +%FT%TZ)",users] # apply journaled changes for the past hour on UsersIndex only
|
1123
1062
|
```
|
1124
1063
|
|
1125
|
-
###
|
1126
|
-
|
1127
|
-
Inside the Rails application, some index-maintaining rake tasks are defined.
|
1064
|
+
### Rspec integration
|
1128
1065
|
|
1129
|
-
|
1130
|
-
rake chewy:reset # resets all the existing indices, declared in app/chewy
|
1131
|
-
rake chewy:reset[users] # resets UsersIndex only
|
1066
|
+
Just add `require 'chewy/rspec'` to your spec_helper.rb and you will get additional features: See [update_index.rb](lib/chewy/rspec/update_index.rb) for more details.
|
1132
1067
|
|
1133
|
-
|
1134
|
-
rake chewy:update[users] # updates UsersIndex only
|
1135
|
-
```
|
1068
|
+
### Minitest integration
|
1136
1069
|
|
1137
|
-
`
|
1070
|
+
Add `require 'chewy/minitest'` to your test_helper.rb, and then for tests which you'd like indexing test hooks, `include Chewy::Minitest::Helpers`.
|
1138
1071
|
|
1072
|
+
Since you can set `:bypass` strategy for test suites and manually handle import for the index and manually flush test indices using `Chewy.massacre`. This will help reduce unnecessary ES requests
|
1139
1073
|
|
1140
|
-
|
1074
|
+
But if you require chewy to index/update model regularly in your test suite then you can specify `:urgent` strategy for documents indexing. Add `Chewy.strategy(:urgent)` to test_helper.rb.
|
1141
1075
|
|
1142
|
-
|
1076
|
+
### DatabaseCleaner
|
1143
1077
|
|
1144
|
-
If you use `DatabaseCleaner` in your tests with [the `transaction` strategy](https://github.com/DatabaseCleaner/database_cleaner#how-to-use), you may run into the problem that `ActiveRecord`'s models are not indexed automatically on save despite the fact that you set the callbacks to do this with the `update_index` method. The issue arises because `chewy`
|
1078
|
+
If you use `DatabaseCleaner` in your tests with [the `transaction` strategy](https://github.com/DatabaseCleaner/database_cleaner#how-to-use), you may run into the problem that `ActiveRecord`'s models are not indexed automatically on save despite the fact that you set the callbacks to do this with the `update_index` method. The issue arises because `chewy` indices data on `after_commit` run as default, but all `after_commit` callbacks are not run with the `DatabaseCleaner`'s' `transaction` strategy. You can solve this issue by changing the `Chewy.use_after_commit_callbacks` option. Just add the following initializer in your Rails application:
|
1145
1079
|
|
1146
1080
|
```ruby
|
1147
1081
|
#config/initializers/chewy.rb
|
@@ -1151,7 +1085,6 @@ Chewy.use_after_commit_callbacks = !Rails.env.test?
|
|
1151
1085
|
## TODO a.k.a coming soon:
|
1152
1086
|
|
1153
1087
|
* Typecasting support
|
1154
|
-
* Advanced (simplified) query DSL: `UsersIndex.query { email == 'my@gmail.com' }` will produce term query
|
1155
1088
|
* update_all support
|
1156
1089
|
* Maybe, closer ORM/ODM integration, creating index classes implicitly
|
1157
1090
|
|