chewy 0.9.0 → 5.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (275) hide show
  1. checksums.yaml +5 -5
  2. data/.circleci/config.yml +214 -0
  3. data/.gitignore +1 -0
  4. data/.rubocop.yml +41 -19
  5. data/.rubocop_todo.yml +2 -2
  6. data/.yardopts +5 -0
  7. data/Appraisals +58 -28
  8. data/CHANGELOG.md +153 -12
  9. data/Gemfile +20 -12
  10. data/LEGACY_DSL.md +497 -0
  11. data/LICENSE.txt +1 -1
  12. data/README.md +338 -528
  13. data/chewy.gemspec +11 -12
  14. data/gemfiles/rails.5.2.activerecord.gemfile +17 -0
  15. data/gemfiles/rails.5.2.mongoid.6.4.gemfile +17 -0
  16. data/gemfiles/rails.6.0.activerecord.gemfile +17 -0
  17. data/gemfiles/rails.6.1.activerecord.gemfile +19 -0
  18. data/gemfiles/ruby3.gemfile +10 -0
  19. data/gemfiles/sequel.4.45.gemfile +11 -0
  20. data/lib/chewy.rb +79 -44
  21. data/lib/chewy/backports/duplicable.rb +1 -1
  22. data/lib/chewy/config.rb +43 -17
  23. data/lib/chewy/errors.rb +2 -2
  24. data/lib/chewy/fields/base.rb +56 -31
  25. data/lib/chewy/fields/root.rb +44 -11
  26. data/lib/chewy/index.rb +237 -149
  27. data/lib/chewy/index/actions.rb +100 -35
  28. data/lib/chewy/index/aliases.rb +2 -1
  29. data/lib/chewy/index/settings.rb +11 -5
  30. data/lib/chewy/index/specification.rb +60 -0
  31. data/lib/chewy/journal.rb +40 -92
  32. data/lib/chewy/minitest/helpers.rb +6 -6
  33. data/lib/chewy/minitest/search_index_receiver.rb +17 -17
  34. data/lib/chewy/query.rb +182 -122
  35. data/lib/chewy/query/compose.rb +13 -13
  36. data/lib/chewy/query/criteria.rb +13 -13
  37. data/lib/chewy/query/filters.rb +21 -4
  38. data/lib/chewy/query/loading.rb +1 -2
  39. data/lib/chewy/query/nodes/and.rb +2 -2
  40. data/lib/chewy/query/nodes/bool.rb +1 -1
  41. data/lib/chewy/query/nodes/equal.rb +2 -2
  42. data/lib/chewy/query/nodes/exists.rb +1 -1
  43. data/lib/chewy/query/nodes/field.rb +1 -1
  44. data/lib/chewy/query/nodes/has_relation.rb +2 -2
  45. data/lib/chewy/query/nodes/match_all.rb +1 -1
  46. data/lib/chewy/query/nodes/missing.rb +1 -1
  47. data/lib/chewy/query/nodes/not.rb +2 -2
  48. data/lib/chewy/query/nodes/or.rb +2 -2
  49. data/lib/chewy/query/nodes/prefix.rb +1 -1
  50. data/lib/chewy/query/nodes/query.rb +2 -2
  51. data/lib/chewy/query/nodes/range.rb +4 -4
  52. data/lib/chewy/query/nodes/regexp.rb +4 -4
  53. data/lib/chewy/query/nodes/script.rb +3 -3
  54. data/lib/chewy/query/pagination.rb +10 -1
  55. data/lib/chewy/railtie.rb +4 -3
  56. data/lib/chewy/rake_helper.rb +265 -48
  57. data/lib/chewy/rspec/update_index.rb +33 -27
  58. data/lib/chewy/search.rb +79 -26
  59. data/lib/chewy/search/loader.rb +83 -0
  60. data/lib/chewy/{query → search}/pagination/kaminari.rb +13 -5
  61. data/lib/chewy/search/pagination/will_paginate.rb +43 -0
  62. data/lib/chewy/search/parameters.rb +168 -0
  63. data/lib/chewy/search/parameters/aggs.rb +16 -0
  64. data/lib/chewy/search/parameters/allow_partial_search_results.rb +27 -0
  65. data/lib/chewy/search/parameters/concerns/bool_storage.rb +24 -0
  66. data/lib/chewy/search/parameters/concerns/hash_storage.rb +23 -0
  67. data/lib/chewy/search/parameters/concerns/integer_storage.rb +14 -0
  68. data/lib/chewy/search/parameters/concerns/query_storage.rb +238 -0
  69. data/lib/chewy/search/parameters/concerns/string_array_storage.rb +23 -0
  70. data/lib/chewy/search/parameters/concerns/string_storage.rb +14 -0
  71. data/lib/chewy/search/parameters/docvalue_fields.rb +12 -0
  72. data/lib/chewy/search/parameters/explain.rb +16 -0
  73. data/lib/chewy/search/parameters/filter.rb +47 -0
  74. data/lib/chewy/search/parameters/highlight.rb +16 -0
  75. data/lib/chewy/search/parameters/indices.rb +123 -0
  76. data/lib/chewy/search/parameters/indices_boost.rb +52 -0
  77. data/lib/chewy/search/parameters/limit.rb +17 -0
  78. data/lib/chewy/search/parameters/load.rb +32 -0
  79. data/lib/chewy/search/parameters/min_score.rb +16 -0
  80. data/lib/chewy/search/parameters/none.rb +27 -0
  81. data/lib/chewy/search/parameters/offset.rb +17 -0
  82. data/lib/chewy/search/parameters/order.rb +64 -0
  83. data/lib/chewy/search/parameters/post_filter.rb +19 -0
  84. data/lib/chewy/search/parameters/preference.rb +16 -0
  85. data/lib/chewy/search/parameters/profile.rb +16 -0
  86. data/lib/chewy/search/parameters/query.rb +19 -0
  87. data/lib/chewy/search/parameters/request_cache.rb +27 -0
  88. data/lib/chewy/search/parameters/rescore.rb +29 -0
  89. data/lib/chewy/search/parameters/script_fields.rb +16 -0
  90. data/lib/chewy/search/parameters/search_after.rb +20 -0
  91. data/lib/chewy/search/parameters/search_type.rb +16 -0
  92. data/lib/chewy/search/parameters/source.rb +73 -0
  93. data/lib/chewy/search/parameters/storage.rb +95 -0
  94. data/lib/chewy/search/parameters/stored_fields.rb +63 -0
  95. data/lib/chewy/search/parameters/suggest.rb +16 -0
  96. data/lib/chewy/search/parameters/terminate_after.rb +16 -0
  97. data/lib/chewy/search/parameters/timeout.rb +16 -0
  98. data/lib/chewy/search/parameters/track_scores.rb +16 -0
  99. data/lib/chewy/search/parameters/types.rb +20 -0
  100. data/lib/chewy/search/parameters/version.rb +16 -0
  101. data/lib/chewy/search/query_proxy.rb +257 -0
  102. data/lib/chewy/search/request.rb +1046 -0
  103. data/lib/chewy/search/response.rb +119 -0
  104. data/lib/chewy/search/scoping.rb +50 -0
  105. data/lib/chewy/search/scrolling.rb +134 -0
  106. data/lib/chewy/stash.rb +79 -0
  107. data/lib/chewy/strategy.rb +10 -3
  108. data/lib/chewy/strategy/active_job.rb +2 -1
  109. data/lib/chewy/strategy/atomic.rb +2 -4
  110. data/lib/chewy/strategy/bypass.rb +1 -1
  111. data/lib/chewy/strategy/resque.rb +1 -0
  112. data/lib/chewy/strategy/shoryuken.rb +40 -0
  113. data/lib/chewy/strategy/sidekiq.rb +13 -3
  114. data/lib/chewy/type.rb +29 -7
  115. data/lib/chewy/type/actions.rb +26 -2
  116. data/lib/chewy/type/adapter/active_record.rb +44 -29
  117. data/lib/chewy/type/adapter/base.rb +27 -7
  118. data/lib/chewy/type/adapter/mongoid.rb +19 -10
  119. data/lib/chewy/type/adapter/object.rb +187 -26
  120. data/lib/chewy/type/adapter/orm.rb +59 -32
  121. data/lib/chewy/type/adapter/sequel.rb +33 -19
  122. data/lib/chewy/type/crutch.rb +1 -1
  123. data/lib/chewy/type/import.rb +146 -191
  124. data/lib/chewy/type/import/bulk_builder.rb +122 -0
  125. data/lib/chewy/type/import/bulk_request.rb +78 -0
  126. data/lib/chewy/type/import/journal_builder.rb +45 -0
  127. data/lib/chewy/type/import/routine.rb +138 -0
  128. data/lib/chewy/type/mapping.rb +51 -35
  129. data/lib/chewy/type/observe.rb +17 -13
  130. data/lib/chewy/type/syncer.rb +222 -0
  131. data/lib/chewy/type/witchcraft.rb +32 -16
  132. data/lib/chewy/type/wrapper.rb +30 -4
  133. data/lib/chewy/version.rb +1 -1
  134. data/lib/sequel/plugins/chewy_observe.rb +4 -19
  135. data/lib/tasks/chewy.rake +84 -26
  136. data/spec/chewy/config_spec.rb +98 -1
  137. data/spec/chewy/fields/base_spec.rb +170 -135
  138. data/spec/chewy/fields/root_spec.rb +124 -20
  139. data/spec/chewy/fields/time_fields_spec.rb +2 -3
  140. data/spec/chewy/index/actions_spec.rb +214 -52
  141. data/spec/chewy/index/aliases_spec.rb +2 -2
  142. data/spec/chewy/index/settings_spec.rb +67 -38
  143. data/spec/chewy/index/specification_spec.rb +169 -0
  144. data/spec/chewy/index_spec.rb +108 -64
  145. data/spec/chewy/journal_spec.rb +150 -55
  146. data/spec/chewy/minitest/helpers_spec.rb +4 -4
  147. data/spec/chewy/minitest/search_index_receiver_spec.rb +1 -1
  148. data/spec/chewy/query/criteria_spec.rb +179 -179
  149. data/spec/chewy/query/filters_spec.rb +16 -16
  150. data/spec/chewy/query/loading_spec.rb +22 -20
  151. data/spec/chewy/query/nodes/and_spec.rb +2 -2
  152. data/spec/chewy/query/nodes/bool_spec.rb +4 -4
  153. data/spec/chewy/query/nodes/equal_spec.rb +19 -19
  154. data/spec/chewy/query/nodes/exists_spec.rb +6 -6
  155. data/spec/chewy/query/nodes/has_child_spec.rb +19 -19
  156. data/spec/chewy/query/nodes/has_parent_spec.rb +19 -19
  157. data/spec/chewy/query/nodes/missing_spec.rb +5 -5
  158. data/spec/chewy/query/nodes/not_spec.rb +4 -2
  159. data/spec/chewy/query/nodes/or_spec.rb +2 -2
  160. data/spec/chewy/query/nodes/prefix_spec.rb +5 -5
  161. data/spec/chewy/query/nodes/query_spec.rb +2 -2
  162. data/spec/chewy/query/nodes/range_spec.rb +18 -18
  163. data/spec/chewy/query/nodes/raw_spec.rb +1 -1
  164. data/spec/chewy/query/nodes/regexp_spec.rb +14 -14
  165. data/spec/chewy/query/nodes/script_spec.rb +4 -4
  166. data/spec/chewy/query/pagination/kaminari_spec.rb +3 -55
  167. data/spec/chewy/query/pagination/will_paginate_spec.rb +5 -0
  168. data/spec/chewy/query/pagination_spec.rb +25 -21
  169. data/spec/chewy/query_spec.rb +503 -561
  170. data/spec/chewy/rake_helper_spec.rb +381 -0
  171. data/spec/chewy/repository_spec.rb +4 -4
  172. data/spec/chewy/rspec/update_index_spec.rb +89 -56
  173. data/spec/chewy/runtime_spec.rb +2 -2
  174. data/spec/chewy/search/loader_spec.rb +117 -0
  175. data/spec/chewy/search/pagination/kaminari_examples.rb +71 -0
  176. data/spec/chewy/search/pagination/kaminari_spec.rb +21 -0
  177. data/spec/chewy/search/pagination/will_paginate_examples.rb +63 -0
  178. data/spec/chewy/search/pagination/will_paginate_spec.rb +23 -0
  179. data/spec/chewy/search/parameters/aggs_spec.rb +5 -0
  180. data/spec/chewy/search/parameters/bool_storage_examples.rb +53 -0
  181. data/spec/chewy/search/parameters/docvalue_fields_spec.rb +5 -0
  182. data/spec/chewy/search/parameters/explain_spec.rb +5 -0
  183. data/spec/chewy/search/parameters/filter_spec.rb +5 -0
  184. data/spec/chewy/search/parameters/hash_storage_examples.rb +59 -0
  185. data/spec/chewy/search/parameters/highlight_spec.rb +5 -0
  186. data/spec/chewy/search/parameters/indices_spec.rb +191 -0
  187. data/spec/chewy/search/parameters/integer_storage_examples.rb +32 -0
  188. data/spec/chewy/search/parameters/limit_spec.rb +5 -0
  189. data/spec/chewy/search/parameters/load_spec.rb +60 -0
  190. data/spec/chewy/search/parameters/min_score_spec.rb +32 -0
  191. data/spec/chewy/search/parameters/none_spec.rb +5 -0
  192. data/spec/chewy/search/parameters/offset_spec.rb +5 -0
  193. data/spec/chewy/search/parameters/order_spec.rb +65 -0
  194. data/spec/chewy/search/parameters/post_filter_spec.rb +5 -0
  195. data/spec/chewy/search/parameters/preference_spec.rb +5 -0
  196. data/spec/chewy/search/parameters/profile_spec.rb +5 -0
  197. data/spec/chewy/search/parameters/query_spec.rb +5 -0
  198. data/spec/chewy/search/parameters/query_storage_examples.rb +388 -0
  199. data/spec/chewy/search/parameters/request_cache_spec.rb +67 -0
  200. data/spec/chewy/search/parameters/rescore_spec.rb +62 -0
  201. data/spec/chewy/search/parameters/script_fields_spec.rb +5 -0
  202. data/spec/chewy/search/parameters/search_after_spec.rb +32 -0
  203. data/spec/chewy/search/parameters/search_type_spec.rb +5 -0
  204. data/spec/chewy/search/parameters/source_spec.rb +156 -0
  205. data/spec/chewy/search/parameters/storage_spec.rb +60 -0
  206. data/spec/chewy/search/parameters/stored_fields_spec.rb +126 -0
  207. data/spec/chewy/search/parameters/string_array_storage_examples.rb +63 -0
  208. data/spec/chewy/search/parameters/string_storage_examples.rb +32 -0
  209. data/spec/chewy/search/parameters/suggest_spec.rb +5 -0
  210. data/spec/chewy/search/parameters/terminate_after_spec.rb +5 -0
  211. data/spec/chewy/search/parameters/timeout_spec.rb +5 -0
  212. data/spec/chewy/search/parameters/track_scores_spec.rb +5 -0
  213. data/spec/chewy/search/parameters/types_spec.rb +5 -0
  214. data/spec/chewy/search/parameters/version_spec.rb +5 -0
  215. data/spec/chewy/search/parameters_spec.rb +147 -0
  216. data/spec/chewy/search/query_proxy_spec.rb +68 -0
  217. data/spec/chewy/search/request_spec.rb +685 -0
  218. data/spec/chewy/search/response_spec.rb +198 -0
  219. data/spec/chewy/search/scrolling_spec.rb +169 -0
  220. data/spec/chewy/search_spec.rb +33 -16
  221. data/spec/chewy/stash_spec.rb +95 -0
  222. data/spec/chewy/strategy/active_job_spec.rb +21 -2
  223. data/spec/chewy/strategy/resque_spec.rb +6 -0
  224. data/spec/chewy/strategy/shoryuken_spec.rb +70 -0
  225. data/spec/chewy/strategy/sidekiq_spec.rb +13 -1
  226. data/spec/chewy/strategy_spec.rb +6 -6
  227. data/spec/chewy/type/actions_spec.rb +29 -10
  228. data/spec/chewy/type/adapter/active_record_spec.rb +203 -91
  229. data/spec/chewy/type/adapter/mongoid_spec.rb +112 -54
  230. data/spec/chewy/type/adapter/object_spec.rb +101 -28
  231. data/spec/chewy/type/adapter/sequel_spec.rb +149 -82
  232. data/spec/chewy/type/import/bulk_builder_spec.rb +279 -0
  233. data/spec/chewy/type/import/bulk_request_spec.rb +102 -0
  234. data/spec/chewy/type/import/journal_builder_spec.rb +95 -0
  235. data/spec/chewy/type/import/routine_spec.rb +110 -0
  236. data/spec/chewy/type/import_spec.rb +356 -271
  237. data/spec/chewy/type/mapping_spec.rb +96 -29
  238. data/spec/chewy/type/observe_spec.rb +9 -5
  239. data/spec/chewy/type/syncer_spec.rb +123 -0
  240. data/spec/chewy/type/witchcraft_spec.rb +61 -29
  241. data/spec/chewy/type/wrapper_spec.rb +63 -23
  242. data/spec/chewy/type_spec.rb +28 -7
  243. data/spec/chewy_spec.rb +75 -7
  244. data/spec/spec_helper.rb +17 -3
  245. data/spec/support/active_record.rb +5 -1
  246. data/spec/support/class_helpers.rb +0 -14
  247. data/spec/support/mongoid.rb +15 -3
  248. data/spec/support/sequel.rb +6 -1
  249. metadata +219 -58
  250. data/.travis.yml +0 -36
  251. data/gemfiles/rails.3.2.activerecord.gemfile +0 -16
  252. data/gemfiles/rails.3.2.activerecord.kaminari.gemfile +0 -15
  253. data/gemfiles/rails.3.2.activerecord.will_paginate.gemfile +0 -15
  254. data/gemfiles/rails.4.2.activerecord.gemfile +0 -17
  255. data/gemfiles/rails.4.2.activerecord.kaminari.gemfile +0 -16
  256. data/gemfiles/rails.4.2.activerecord.will_paginate.gemfile +0 -16
  257. data/gemfiles/rails.4.2.mongoid.4.0.gemfile +0 -16
  258. data/gemfiles/rails.4.2.mongoid.4.0.kaminari.gemfile +0 -15
  259. data/gemfiles/rails.4.2.mongoid.4.0.will_paginate.gemfile +0 -15
  260. data/gemfiles/rails.4.2.mongoid.5.1.gemfile +0 -16
  261. data/gemfiles/rails.4.2.mongoid.5.1.kaminari.gemfile +0 -15
  262. data/gemfiles/rails.4.2.mongoid.5.1.will_paginate.gemfile +0 -15
  263. data/gemfiles/rails.5.0.activerecord.gemfile +0 -17
  264. data/gemfiles/rails.5.0.activerecord.kaminari.gemfile +0 -16
  265. data/gemfiles/rails.5.0.activerecord.will_paginate.gemfile +0 -16
  266. data/gemfiles/sequel.4.38.gemfile +0 -14
  267. data/lib/chewy/journal/apply.rb +0 -31
  268. data/lib/chewy/journal/clean.rb +0 -24
  269. data/lib/chewy/journal/entry.rb +0 -83
  270. data/lib/chewy/journal/query.rb +0 -87
  271. data/lib/chewy/query/pagination/will_paginate.rb +0 -27
  272. data/lib/chewy/query/scoping.rb +0 -20
  273. data/spec/chewy/journal/apply_spec.rb +0 -120
  274. data/spec/chewy/journal/entry_spec.rb +0 -237
  275. data/spec/chewy/query/pagination/will_paginage_spec.rb +0 -59
@@ -1,4 +1,4 @@
1
- Copyright (c) 2013 pyromaniac
1
+ Copyright (c) 2013-2021 Toptal, LLC
2
2
 
3
3
  MIT License
4
4
 
data/README.md CHANGED
@@ -1,53 +1,61 @@
1
1
  [![Gem Version](https://badge.fury.io/rb/chewy.svg)](http://badge.fury.io/rb/chewy)
2
- [![Build Status](https://travis-ci.org/toptal/chewy.svg)](https://travis-ci.org/toptal/chewy)
2
+ [![CircleCI](https://circleci.com/gh/toptal/chewy/tree/master.svg?style=svg)](https://circleci.com/gh/toptal/chewy/tree/master)
3
3
  [![Code Climate](https://codeclimate.com/github/toptal/chewy.svg)](https://codeclimate.com/github/toptal/chewy)
4
4
  [![Inline docs](http://inch-ci.org/github/toptal/chewy.svg?branch=master)](http://inch-ci.org/github/toptal/chewy)
5
5
 
6
- <p align="right">Sponsored by</p>
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
-
9
6
  # Chewy
10
7
 
11
- Chewy is an ODM and wrapper for [the official Elasticsearch client](https://github.com/elastic/elasticsearch-ruby).
8
+ Chewy is an ODM (Object Document Mapper), built on top of the [the official Elasticsearch client](https://github.com/elastic/elasticsearch-ruby).
12
9
 
13
10
  ## Table of Contents
14
11
 
15
- * [Why Chewy?] (#why-chewy)
16
- * [Usage] (#usage)
17
- * [Client settings] (#client-settings)
18
- * [Index definition] (#index-definition)
19
- * [Type default import options] (#type-default-import-options)
20
- * [Multi (nested) and object field types] (#multi-nested-and-object-field-types)
21
- * [Geo Point fields] (#geo-point-fields)
22
- * [Crutches™ technology] (#crutches-technology)
23
- * [Witchcraft™ technology] (#witchcraft-technology)
24
- * [Raw Import] (#raw-import)
25
- * [Journaling] (#journaling)
26
- * [Types access] (#types-access)
27
- * [Index manipulation] (#index-manipulation)
28
- * [Index update strategies] (#index-update-strategies)
29
- * [Nesting] (#nesting)
30
- * [Non-block notation] (#non-block-notation)
31
- * [Designing your own strategies] (#designing-your-own-strategies)
32
- * [Rails application strategies integration] (#rails-application-strategies-integration)
33
- * [Index querying] (#index-querying)
34
- * [Additional query action.] (#additional-query-action)
35
- * [Filters query DSL] (#filters-query-dsl)
36
- * [Faceting] (#faceting)
37
- * [Aggregations] (#aggregations)
38
- * [Script fields] (#script-fields)
39
- * [Script scoring] (#script-scoring)
40
- * [Boost Factor] (#boost-factor)
41
- * [Objects loading] (#objects-loading)
42
- * [NewRelic integration] (#newrelic-integration)
43
- * [Rake tasks] (#rake-tasks)
44
- * [Rspec integration] (#rspec-integration)
45
- * [Minitest integration] (#minitest-integration)
46
- * [TODO a.k.a coming soon:] (#todo-aka-coming-soon)
47
- * [Contributing] (#contributing)
12
+ * [Why Chewy?](#why-chewy)
13
+ * [Installation](#installation)
14
+ * [Usage](#usage)
15
+ * [Client settings](#client-settings)
16
+ * [AWS ElasticSearch configuration](#aws-elastic-search)
17
+ * [Index definition](#index-definition)
18
+ * [Type default import options](#type-default-import-options)
19
+ * [Multi (nested) and object field types](#multi-nested-and-object-field-types)
20
+ * [Parent and children types](#parent-and-children-types)
21
+ * [Geo Point fields](#geo-point-fields)
22
+ * [Crutches™ technology](#crutches-technology)
23
+ * [Witchcraft™ technology](#witchcraft-technology)
24
+ * [Raw Import](#raw-import)
25
+ * [Index creation during import](#index-creation-during-import)
26
+ * [Journaling](#journaling)
27
+ * [Types access](#types-access)
28
+ * [Index manipulation](#index-manipulation)
29
+ * [Index update strategies](#index-update-strategies)
30
+ * [Nesting](#nesting)
31
+ * [Non-block notation](#non-block-notation)
32
+ * [Designing your own strategies](#designing-your-own-strategies)
33
+ * [Rails application strategies integration](#rails-application-strategies-integration)
34
+ * [ActiveSupport::Notifications support](#activesupportnotifications-support)
35
+ * [NewRelic integration](#newrelic-integration)
36
+ * [Search requests](#search-requests)
37
+ * [Composing requests](#composing-requests)
38
+ * [Pagination](#pagination)
39
+ * [Named scopes](#named-scopes)
40
+ * [Scroll API](#scroll-api)
41
+ * [Loading objects](#loading-objects)
42
+ * [Legacy DSL incompatibilities](#legacy-dsl-incompatibilities)
43
+ * [Rake tasks](#rake-tasks)
44
+ * [chewy:reset](#chewyreset)
45
+ * [chewy:upgrade](#chewyupgrade)
46
+ * [chewy:update](#chewyupdate)
47
+ * [chewy:sync](#chewysync)
48
+ * [chewy:deploy](#chewydeploy)
49
+ * [Parallelizing rake tasks](#parallelizing-rake-tasks)
50
+ * [chewy:journal](#chewyjournal)
51
+ * [RSpec integration](#rspec-integration)
52
+ * [Minitest integration](#minitest-integration)
53
+ * [Contributing](#contributing)
48
54
 
49
55
  ## Why Chewy?
50
56
 
57
+ In this section we'll cover why you might want to use Chewy instead of the official `elasticsearch-ruby` client gem.
58
+
51
59
  * Multi-model indices.
52
60
 
53
61
  Index classes are independent from ORM/ODM models. Now, implementing e.g. cross-model autocomplete is much easier. You can just define the index and work with it in an object-oriented style. You can define several types for index - one per indexed model.
@@ -66,10 +74,9 @@ Chewy is an ODM and wrapper for [the official Elasticsearch client](https://gith
66
74
 
67
75
  * Support for ActiveRecord, [Mongoid](https://github.com/mongoid/mongoid) and [Sequel](https://github.com/jeremyevans/sequel).
68
76
 
69
-
70
77
  ## Installation
71
78
 
72
- Add this line to your application's Gemfile:
79
+ Add this line to your application's `Gemfile`:
73
80
 
74
81
  gem 'chewy'
75
82
 
@@ -81,13 +88,29 @@ Or install it yourself as:
81
88
 
82
89
  $ gem install chewy
83
90
 
91
+ ## Compatibility
92
+
93
+ ### Ruby
94
+
95
+ Chewy is compatible with MRI 2.5-3.0¹.
96
+
97
+ > ¹ Ruby 3 is only supported with Rails 6.1
98
+
99
+ ### Elasticsearch
100
+
101
+ Chewy 5 is compatible with Elasticsearch 5. Future versions of Chewy will support Elasticsearch 6 and Elasticsearch 7.
102
+
84
103
  ## Usage
85
104
 
86
105
  ### Client settings
87
106
 
88
- There are two ways to configure the Chewy client: the `Chewy.settings` hash and `chewy.yml`
107
+ There are two ways to configure the Chewy client:
89
108
 
90
- You can create this file manually or run `rails g chewy:install`.
109
+ * via the hash `Chewy.settings`
110
+ * via the configuration file `chewy.yml`
111
+
112
+ You can create `chewy.yml` manually or run `rails g chewy:install` to
113
+ generate it.
91
114
 
92
115
  ```ruby
93
116
  # config/initializers/chewy.rb
@@ -119,6 +142,30 @@ Chewy.logger = Logger.new(STDOUT)
119
142
 
120
143
  See [config.rb](lib/chewy/config.rb) for more details.
121
144
 
145
+ #### AWS Elasticsearch
146
+
147
+ 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`.
148
+ You'll need an additional gem for Faraday middleware: add `gem 'faraday_middleware-aws-sigv4'` to your Gemfile.
149
+
150
+ ```ruby
151
+ require 'faraday_middleware/aws_sigv4'
152
+
153
+ Chewy.settings = {
154
+ host: 'http://my-es-instance-on-aws.us-east-1.es.amazonaws.com:80',
155
+ port: 80, # 443 for https host
156
+ transport_options: {
157
+ headers: { content_type: 'application/json' },
158
+ proc: -> (f) do
159
+ f.request :aws_sigv4,
160
+ service: 'es',
161
+ region: 'us-east-1',
162
+ access_key_id: ENV['AWS_ACCESS_KEY'],
163
+ secret_access_key: ENV['AWS_SECRET_ACCESS_KEY']
164
+ end
165
+ }
166
+ }
167
+ ```
168
+
122
169
  ### Index definition
123
170
 
124
171
  1. Create `/app/chewy/users_index.rb`
@@ -178,7 +225,7 @@ See [config.rb](lib/chewy/config.rb) for more details.
178
225
 
179
226
  define_type User.active.includes(:country, :badges, :projects) do
180
227
  root date_detection: false do
181
- template 'about_translations.*', type: 'string', analyzer: 'standard'
228
+ template 'about_translations.*', type: 'text', analyzer: 'standard'
182
229
 
183
230
  field :first_name, :last_name
184
231
  field :email, analyzer: 'email'
@@ -198,7 +245,7 @@ See [config.rb](lib/chewy/config.rb) for more details.
198
245
  ```
199
246
 
200
247
  [See index settings here](https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-update-settings.html).
201
- [See root object settings here](https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-root-object-type.html).
248
+ [See root object settings here](https://www.elastic.co/guide/en/elasticsearch/reference/current/dynamic-field-mapping.html).
202
249
 
203
250
  See [mapping.rb](lib/chewy/type/mapping.rb) for more details.
204
251
 
@@ -305,17 +352,29 @@ This will automatically set the type or root field to `object`. You may also spe
305
352
  To define a multi field you have to specify any type except for `object` or `nested` in the root field:
306
353
 
307
354
  ```ruby
308
- field :full_name, type: 'string', value: ->{ full_name.strip } do
355
+ field :full_name, type: 'text', value: ->{ full_name.strip } do
309
356
  field :ordered, analyzer: 'ordered'
310
357
  field :untouched, index: 'not_analyzed'
311
358
  end
312
359
  ```
313
360
 
314
- The `value:` option for internal fields would no longer be effective.
361
+ The `value:` option for internal fields will no longer be effective.
362
+
363
+ ### Parent and children types
364
+
365
+ 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
315
366
 
367
+ ```ruby
368
+ define_type User.includes(:account) do
369
+ root parent: 'account', parent_id: ->{ account_id } do
370
+ field :created_at, type: 'date'
371
+ field :task_id, type: 'integer'
372
+ end
373
+ end
374
+ ```
316
375
  ### Geo Point fields
317
376
 
318
- You can use [Elasticsearch's geo mapping](https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-geo-point-type.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:
377
+ 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:
319
378
 
320
379
  ```ruby
321
380
  field :coordinates, type: 'geo_point', value: ->{ {lat: latitude, lon: longitude} }
@@ -345,7 +404,7 @@ class ProductsIndex < Chewy::Index
345
404
  end
346
405
  ```
347
406
 
348
- Then the Chewy reindexing flow would look like the following pseudo-code (even in Mongoid):
407
+ Then the Chewy reindexing flow will look like the following pseudo-code (even in Mongoid):
349
408
 
350
409
  ```ruby
351
410
  Product.includes(:categories).find_in_batches(1000) do |batch|
@@ -380,7 +439,7 @@ class ProductsIndex < Chewy::Index
380
439
  end
381
440
  ```
382
441
 
383
- An example flow would look like this:
442
+ An example flow will look like this:
384
443
 
385
444
  ```ruby
386
445
  Product.includes(:categories).find_in_batches(1000) do |batch|
@@ -481,12 +540,18 @@ end
481
540
 
482
541
  Also, you can pass `:raw_import` option to the `import` method explicitly.
483
542
 
543
+ ### Index creation during import
544
+
545
+ By default, when you perform import Chewy checks whether an index exists and creates it if it's absent.
546
+ You can turn off this feature to decrease Elasticsearch hits count.
547
+ To do so you need to set `skip_index_creation_on_import` parameter to `false` in your `config/chewy.yml`
548
+
484
549
 
485
550
  ### Journaling
486
551
 
487
552
  You can record all actions that were made to the separate journal index in ElasticSearch.
488
- When you create/update/destroy your records, it will be saved in this special index.
489
- If you make something with a batch of records (e.g. during index reset) it will be saved as a one record, including primary keys of each document that was affected.
553
+ When you create/update/destroy your documents, it will be saved in this special index.
554
+ 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.
490
555
  Common journal record looks like this:
491
556
 
492
557
  ```json
@@ -506,7 +571,7 @@ Also, you can specify journal index name. For example:
506
571
  ```yaml
507
572
  # config/chewy.yml
508
573
  production:
509
- journal: true,
574
+ journal: true
510
575
  journal_name: my_super_journal
511
576
  ```
512
577
 
@@ -526,12 +591,9 @@ class CityIndex
526
591
  end
527
592
  ```
528
593
 
529
- You may be wondering why do you need it? The answer is simple: Not to lose the data.
530
- Imagine that:
531
- You reset your index in Zero Downtime manner (to separate index), and 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 with `Chewy::Journal::Apply.since(1.hour.ago.to_i)`.
594
+ You may be wondering why do you need it? The answer is simple: not to lose the data.
532
595
 
533
- For index reset journaling is turned off even if you set `journal: true` in `config/chewy.yml` or in `default_import_options`.
534
- You can change it only if you pass `journal: true` parameter explicitly to `#import`.
596
+ 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.
535
597
 
536
598
  ### Types access
537
599
 
@@ -563,6 +625,7 @@ UsersIndex::User.import # import with 0 arguments process all the data specified
563
625
  UsersIndex::User.import User.where('rating > 100') # or import specified users scope
564
626
  UsersIndex::User.import User.where('rating > 100').to_a # or import specified users array
565
627
  UsersIndex::User.import [1, 2, 42] # pass even ids for import, it will be handled in the most effective way
628
+ 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.
566
629
 
567
630
  UsersIndex.import # import every defined type
568
631
  UsersIndex.import user: User.where('rating > 100') # import only active users to `user` type.
@@ -632,6 +695,11 @@ Chewy.strategy(:sidekiq) do
632
695
  end
633
696
  ```
634
697
 
698
+ The default queue name is `chewy`, you can customize it in settings: `sidekiq.queue_name`
699
+ ```
700
+ Chewy.settings[:sidekiq] = {queue: :low}
701
+ ```
702
+
635
703
  #### `:active_job`
636
704
 
637
705
  This does the same thing as `:atomic`, but using ActiveJob. This will inherit the ActiveJob configuration settings including the `active_job.queue_adapter` setting for the environment. Patch `Chewy::Strategy::ActiveJob::Worker` for index updates improving.
@@ -642,6 +710,21 @@ Chewy.strategy(:active_job) do
642
710
  end
643
711
  ```
644
712
 
713
+ The default queue name is `chewy`, you can customize it in settings: `active_job.queue_name`
714
+ ```
715
+ Chewy.settings[:active_job] = {queue: :low}
716
+ ```
717
+
718
+ #### `:shoryuken`
719
+
720
+ This does the same thing as `:atomic`, but asynchronously using shoryuken. Patch `Chewy::Strategy::Shoryuken::Worker` for index updates improving.
721
+
722
+ ```ruby
723
+ Chewy.strategy(:shoryuken) do
724
+ City.popular.map(&:do_some_update_action!)
725
+ end
726
+ ```
727
+
645
728
  #### `:urgent`
646
729
 
647
730
  The following strategy is convenient if you are going to update documents in your index one by one.
@@ -652,7 +735,7 @@ Chewy.strategy(:urgent) do
652
735
  end
653
736
  ```
654
737
 
655
- This code would perform `City.popular.count` requests for ES documents update.
738
+ This code will perform `City.popular.count` requests for ES documents update.
656
739
 
657
740
  It is convenient for use in e.g. the Rails console with non-block notation:
658
741
 
@@ -717,570 +800,295 @@ RSpec.configure do |config|
717
800
  end
718
801
  ```
719
802
 
720
- ### Index querying
721
-
722
- ```ruby
723
- scope = UsersIndex.query(term: {name: 'foo'})
724
- .filter(range: {rating: {gte: 100}})
725
- .order(created: :desc)
726
- .limit(20).offset(100)
727
-
728
- scope.to_a # => will produce array of UserIndex::User or other types instances
729
- scope.map { |user| user.email }
730
- scope.total_count # => will return total objects count
731
-
732
- scope.per(10).page(3) # supports kaminari pagination
733
- scope.explain.map { |user| user._explanation }
734
- scope.only(:id, :email) # returns ids and emails only
735
-
736
- scope.merge(other_scope) # queries could be merged
737
- ```
803
+ ### `ActiveSupport::Notifications` support
738
804
 
739
- Also, queries can be performed on a type individually:
805
+ Chewy has notifying the following events:
740
806
 
741
- ```ruby
742
- UsersIndex::User.filter(term: {name: 'foo'}) # will return UserIndex::User collection only
743
- ```
807
+ #### `search_query.chewy` payload
744
808
 
745
- If you are performing more than one `filter` or `query` in the chain, all the filters and queries will be concatenated in the way specified by
746
- `filter_mode` and `query_mode` respectively.
809
+ * `payload[:index]`: requested index class
810
+ * `payload[:request]`: request hash
747
811
 
748
- The default `filter_mode` is `:and` and the default `query_mode` is `bool`.
812
+ #### `import_objects.chewy` payload
749
813
 
750
- Available filter modes are: `:and`, `:or`, `:must`, `:should` and any minimum_should_match-acceptable value
814
+ * `payload[:type]`: currently imported type
815
+ * `payload[:import]`: imports stats, total imported and deleted objects count:
751
816
 
752
- Available query modes are: `:must`, `:should`, `:dis_max`, any minimum_should_match-acceptable value or float value for dis_max query with tie_breaker specified.
817
+ ```ruby
818
+ {index: 30, delete: 5}
819
+ ```
753
820
 
754
- ```ruby
755
- UsersIndex::User.filter{ name == 'Fred' }.filter{ age < 42 } # will be wrapped with `and` filter
756
- UsersIndex::User.filter{ name == 'Fred' }.filter{ age < 42 }.filter_mode(:should) # will be wrapped with bool `should` filter
757
- UsersIndex::User.filter{ name == 'Fred' }.filter{ age < 42 }.filter_mode('75%') # will be wrapped with bool `should` filter with `minimum_should_match: '75%'`
758
- ```
821
+ * `payload[:errors]`: might not exists. Contains grouped errors with objects ids list:
759
822
 
760
- See [query.rb](lib/chewy/query.rb) for more details.
823
+ ```ruby
824
+ {index: {
825
+ 'error 1 text' => ['1', '2', '3'],
826
+ 'error 2 text' => ['4']
827
+ }, delete: {
828
+ 'delete error text' => ['10', '12']
829
+ }}
830
+ ```
761
831
 
762
- ### Additional query action.
832
+ ### NewRelic integration
763
833
 
764
- You may also perform additional actions on the query scope, such as deleting of all the scope documents:
834
+ To integrate with NewRelic you may use the following example source (config/initializers/chewy.rb):
765
835
 
766
836
  ```ruby
767
- UsersIndex.delete_all
768
- UsersIndex::User.delete_all
769
- UsersIndex.filter{ age < 42 }.delete_all
770
- UsersIndex::User.filter{ age < 42 }.delete_all
771
- ```
837
+ require 'new_relic/agent/instrumentation/evented_subscriber'
772
838
 
773
- ### Filters query DSL
774
-
775
- There is a test version of the filter-creating DSL:
839
+ class ChewySubscriber < NewRelic::Agent::Instrumentation::EventedSubscriber
840
+ def start(name, id, payload)
841
+ event = ChewyEvent.new(name, Time.current, nil, id, payload)
842
+ push_event(event)
843
+ end
776
844
 
777
- ```ruby
778
- UsersIndex.filter{ name == 'Fred' } # will produce `term` filter.
779
- UsersIndex.filter{ age <= 42 } # will produce `range` filter.
780
- ```
845
+ def finish(_name, id, _payload)
846
+ pop_event(id).finish
847
+ end
781
848
 
782
- The basis of the DSL is the expression. There are 2 types of expressions:
849
+ class ChewyEvent < NewRelic::Agent::Instrumentation::Event
850
+ OPERATIONS = {
851
+ 'import_objects.chewy' => 'import',
852
+ 'search_query.chewy' => 'search',
853
+ 'delete_query.chewy' => 'delete'
854
+ }.freeze
783
855
 
784
- * Simple function
856
+ def initialize(*args)
857
+ super
858
+ @segment = start_segment
859
+ end
785
860
 
786
- ```ruby
787
- UsersIndex.filter{ s('doc["num"] > 1') } # script expression
788
- UsersIndex.filter{ q(query_string: {query: 'lazy fox'}) } # query expression
789
- ```
861
+ def start_segment
862
+ segment = NewRelic::Agent::Transaction::DatastoreSegment.new product, operation, collection, host, port
863
+ if (txn = state.current_transaction)
864
+ segment.transaction = txn
865
+ end
866
+ segment.notice_sql @payload[:request].to_s
867
+ segment.start
868
+ segment
869
+ end
790
870
 
791
- * Field-dependent composite expression
792
- 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.
871
+ def finish
872
+ if (txn = state.current_transaction)
873
+ txn.add_segment @segment
874
+ end
875
+ @segment.finish
876
+ end
793
877
 
794
- ```ruby
795
- UsersIndex.filter{ name == 'Name' } # simple field term filter
796
- UsersIndex.filter{ name(:bool) == ['Name1', 'Name2'] } # terms query with `execution: :bool` option passed
797
- UsersIndex.filter{ answers.title =~ /regexp/ } # regexp filter for `answers.title` field
798
- ```
878
+ private
799
879
 
800
- You can combine expressions as you wish with the help of combination operators.
880
+ def state
881
+ @state ||= NewRelic::Agent::TransactionState.tl_get
882
+ end
801
883
 
802
- ```ruby
803
- UsersIndex.filter{ (name == 'Name') & (email == 'Email') } # combination produces `and` filter
804
- UsersIndex.filter{
805
- must(
806
- should(name =~ 'Fr').should_not(name == 'Fred') & (age == 42), email =~ /gmail\.com/
807
- ) | ((roles.admin == true) & name?)
808
- } # many of the combination possibilities
809
- ```
884
+ def product
885
+ 'Elasticsearch'
886
+ end
810
887
 
811
- There is also a special syntax for cache enabling:
888
+ def operation
889
+ OPERATIONS[name]
890
+ end
812
891
 
813
- ```ruby
814
- UsersIndex.filter{ ~name == 'Name' } # you can apply tilde to the field name
815
- UsersIndex.filter{ ~(name == 'Name') } # or to the whole expression
892
+ def collection
893
+ payload.values_at(:type, :index)
894
+ .reject { |value| value.try(:empty?) }
895
+ .first
896
+ .to_s
897
+ end
816
898
 
817
- # if you are applying cache to the one part of range filter
818
- # the whole filter will be cached:
819
- UsersIndex.filter{ ~(age > 42) & (age <= 50) }
899
+ def host
900
+ Chewy.client.transport.hosts.first[:host]
901
+ end
820
902
 
821
- # You can pass cache options as a field option also.
822
- UsersIndex.filter{ name(cache: true) == 'Name' }
823
- UsersIndex.filter{ name(cache: false) == 'Name' }
903
+ def port
904
+ Chewy.client.transport.hosts.first[:port]
905
+ end
906
+ end
907
+ end
824
908
 
825
- # With regexp filter you can pass _cache_key
826
- UsersIndex.filter{ name(cache: 'name_regexp') =~ /Name/ }
827
- # Or not
828
- UsersIndex.filter{ name(cache: true) =~ /Name/ }
909
+ ActiveSupport::Notifications.subscribe(/.chewy$/, ChewySubscriber.new)
829
910
  ```
830
911
 
831
- Compliance cheatsheet for filters and DSL expressions:
832
-
833
- * Term filter
834
-
835
- ```json
836
- {"term": {"name": "Fred"}}
837
- {"not": {"term": {"name": "Johny"}}}
838
- ```
839
-
840
- ```ruby
841
- UsersIndex.filter{ name == 'Fred' }
842
- UsersIndex.filter{ name != 'Johny' }
843
- ```
844
-
845
- * Terms filter
846
-
847
- ```json
848
- {"terms": {"name": ["Fred", "Johny"]}}
849
- {"not": {"terms": {"name": ["Fred", "Johny"]}}}
850
-
851
- {"terms": {"name": ["Fred", "Johny"], "execution": "or"}}
852
-
853
- {"terms": {"name": ["Fred", "Johny"], "execution": "and"}}
854
-
855
- {"terms": {"name": ["Fred", "Johny"], "execution": "bool"}}
856
-
857
- {"terms": {"name": ["Fred", "Johny"], "execution": "fielddata"}}
858
- ```
859
-
860
- ```ruby
861
- UsersIndex.filter{ name == ['Fred', 'Johny'] }
862
- UsersIndex.filter{ name != ['Fred', 'Johny'] }
863
-
864
- UsersIndex.filter{ name(:|) == ['Fred', 'Johny'] }
865
- UsersIndex.filter{ name(:or) == ['Fred', 'Johny'] }
866
- UsersIndex.filter{ name(execution: :or) == ['Fred', 'Johny'] }
867
-
868
- UsersIndex.filter{ name(:&) == ['Fred', 'Johny'] }
869
- UsersIndex.filter{ name(:and) == ['Fred', 'Johny'] }
870
- UsersIndex.filter{ name(execution: :and) == ['Fred', 'Johny'] }
871
-
872
- UsersIndex.filter{ name(:b) == ['Fred', 'Johny'] }
873
- UsersIndex.filter{ name(:bool) == ['Fred', 'Johny'] }
874
- UsersIndex.filter{ name(execution: :bool) == ['Fred', 'Johny'] }
875
-
876
- UsersIndex.filter{ name(:f) == ['Fred', 'Johny'] }
877
- UsersIndex.filter{ name(:fielddata) == ['Fred', 'Johny'] }
878
- UsersIndex.filter{ name(execution: :fielddata) == ['Fred', 'Johny'] }
879
- ```
880
-
881
- * Regexp filter (== and =~ are equivalent)
882
-
883
- ```json
884
- {"regexp": {"name.first": "s.*y"}}
885
-
886
- {"not": {"regexp": {"name.first": "s.*y"}}}
887
-
888
- {"regexp": {"name.first": {"value": "s.*y", "flags": "ANYSTRING|INTERSECTION"}}}
889
- ```
890
-
891
- ```ruby
892
- UsersIndex.filter{ name.first == /s.*y/ }
893
- UsersIndex.filter{ name.first =~ /s.*y/ }
894
-
895
- UsersIndex.filter{ name.first != /s.*y/ }
896
- UsersIndex.filter{ name.first !~ /s.*y/ }
897
-
898
- UsersIndex.filter{ name.first(:anystring, :intersection) == /s.*y/ }
899
- UsersIndex.filter{ name.first(flags: [:anystring, :intersection]) == /s.*y/ }
900
- ```
901
-
902
- * Prefix filter
903
-
904
- ```json
905
- {"prefix": {"name": "Fre"}}
906
- {"not": {"prefix": {"name": "Joh"}}}
907
- ```
908
-
909
- ```ruby
910
- UsersIndex.filter{ name =~ re' }
911
- UsersIndex.filter{ name !~ 'Joh' }
912
- ```
913
-
914
- * Exists filter
915
-
916
- ```json
917
- {"exists": {"field": "name"}}
918
- ```
919
-
920
- ```ruby
921
- UsersIndex.filter{ name? }
922
- UsersIndex.filter{ !!name }
923
- UsersIndex.filter{ !!name? }
924
- UsersIndex.filter{ name != nil }
925
- UsersIndex.filter{ !(name == nil) }
926
- ```
927
-
928
- * Missing filter
929
-
930
- ```json
931
- {"missing": {"field": "name", "existence": true, "null_value": false}}
932
- {"missing": {"field": "name", "existence": true, "null_value": true}}
933
- {"missing": {"field": "name", "existence": false, "null_value": true}}
934
- ```
935
-
936
- ```ruby
937
- UsersIndex.filter{ !name }
938
- UsersIndex.filter{ !name? }
939
- UsersIndex.filter{ name == nil }
940
- ```
941
-
942
- * Range
943
-
944
- ```json
945
- {"range": {"age": {"gt": 42}}}
946
- {"range": {"age": {"gte": 42}}}
947
- {"range": {"age": {"lt": 42}}}
948
- {"range": {"age": {"lte": 42}}}
949
-
950
- {"range": {"age": {"gt": 40, "lt": 50}}}
951
- {"range": {"age": {"gte": 40, "lte": 50}}}
952
-
953
- {"range": {"age": {"gt": 40, "lte": 50}}}
954
- {"range": {"age": {"gte": 40, "lt": 50}}}
955
- ```
956
-
957
- ```ruby
958
- UsersIndex.filter{ age > 42 }
959
- UsersIndex.filter{ age >= 42 }
960
- UsersIndex.filter{ age < 42 }
961
- UsersIndex.filter{ age <= 42 }
962
-
963
- UsersIndex.filter{ age == (40..50) }
964
- UsersIndex.filter{ (age > 40) & (age < 50) }
965
- UsersIndex.filter{ age == [40..50] }
966
- UsersIndex.filter{ (age >= 40) & (age <= 50) }
967
-
968
- UsersIndex.filter{ (age > 40) & (age <= 50) }
969
- UsersIndex.filter{ (age >= 40) & (age < 50) }
970
- ```
971
-
972
- * Bool filter
973
-
974
- ```json
975
- {"bool": {
976
- "must": [{"term": {"name": "Name"}}],
977
- "should": [{"term": {"age": 42}}, {"term": {"age": 45}}]
978
- }}
979
- ```
980
-
981
- ```ruby
982
- UsersIndex.filter{ must(name == 'Name').should(age == 42, age == 45) }
983
- ```
984
-
985
- * And filter
986
-
987
- ```json
988
- {"and": [{"term": {"name": "Name"}}, {"range": {"age": {"lt": 42}}}]}
989
- ```
990
-
991
- ```ruby
992
- UsersIndex.filter{ (name == 'Name') & (age < 42) }
993
- ```
994
-
995
- * Or filter
996
-
997
- ```json
998
- {"or": [{"term": {"name": "Name"}}, {"range": {"age": {"lt": 42}}}]}
999
- ```
1000
-
1001
- ```ruby
1002
- UsersIndex.filter{ (name == 'Name') | (age < 42) }
1003
- ```
1004
-
1005
- ```json
1006
- {"not": {"term": {"name": "Name"}}}
1007
- {"not": {"range": {"age": {"lt": 42}}}}
1008
- ```
912
+ ### Search requests
1009
913
 
1010
- ```ruby
1011
- UsersIndex.filter{ !(name == 'Name') } # or UsersIndex.filter{ name != 'Name' }
1012
- UsersIndex.filter{ !(age < 42) }
1013
- ```
914
+ 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).
1014
915
 
1015
- * Match all filter
916
+ If you want to use the old DSL - simply do `Chewy.search_class = Chewy::Query` somewhere before indices are initialized.
1016
917
 
1017
- ```json
1018
- {"match_all": {}}
1019
- ```
918
+ The new DSL is enabled by default, here is a quick introduction.
1020
919
 
1021
- ```ruby
1022
- UsersIndex.filter{ match_all }
1023
- ```
920
+ #### Composing requests
1024
921
 
1025
- * Has child filter
922
+ 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:
1026
923
 
1027
- ```json
1028
- {"has_child": {"type": "blog_tag", "query": {"term": {"tag": "something"}}}
1029
- {"has_child": {"type": "comment", "filter": {"term": {"user": "john"}}}
1030
- ```
1031
-
1032
- ```ruby
1033
- UsersIndex.filter{ has_child(:blog_tag).query(term: {tag: 'something'}) }
1034
- UsersIndex.filter{ has_child(:comment).filter{ user == 'john' } }
1035
- ```
1036
-
1037
- * Has parent filter
1038
-
1039
- ```json
1040
- {"has_parent": {"type": "blog", "query": {"term": {"tag": "something"}}}}
1041
- {"has_parent": {"type": "blog", "filter": {"term": {"text": "bonsai three"}}}}
1042
- ```
924
+ ```ruby
925
+ PlaceIndex.query(match: {name: 'London'}) # returns documents of any type
926
+ PlaceIndex::City.query(match: {name: 'London'}) # returns cities only.
927
+ ```
1043
928
 
1044
- ```ruby
1045
- UsersIndex.filter{ has_parent(:blog).query(term: {tag: 'something'}) }
1046
- UsersIndex.filter{ has_parent(:blog).filter{ text == 'bonsai three' } }
1047
- ```
929
+ 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
1048
930
 
1049
- See [filters.rb](lib/chewy/query/filters.rb) for more details.
931
+ ```ruby
932
+ PlaceIndex
933
+ .filter(term: {name: 'Bangkok'})
934
+ .query { match name: 'London' }
935
+ .query.not(range: {population: {gt: 1_000_000}})
936
+ ```
1050
937
 
1051
- ### Faceting
938
+ 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.
1052
939
 
1053
- Facets are an optional sidechannel you can request from Elasticsearch describing certain fields of the resulting collection. The most common use for facets is to allow the user to continue filtering specifically within the subset, as opposed to the global index.
940
+ 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.
1054
941
 
1055
- For instance, let's request the `country` field as a facet along with our users collection. We can do this with the #facets method like so:
942
+ Every other request part is covered by a bunch of additional methods, see [Chewy::Search::Request](lib/chewy/search/request.rb) for details:
1056
943
 
1057
944
  ```ruby
1058
- UsersIndex.filter{ [...] }.facets({countries: {terms: {field: 'country'}}})
945
+ PlaceIndex.limit(10).offset(30).order(:name, {population: {order: :desc}})
1059
946
  ```
1060
947
 
1061
- 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.
948
+ Request DSL also provides additional scope actions, like `delete_all`, `exists?`, `count`, `pluck`, etc.
1062
949
 
1063
- The response will include the `:facets` sidechannel:
950
+ #### Pagination
1064
951
 
1065
- ```
1066
- < { ... ,"facets":{"countries":{"_type":"terms","missing":?,"total":?,"other":?,"terms":[{"term":"USA","count":?},{"term":"Brazil","count":?}, ...}}
1067
- ```
952
+ 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.
1068
953
 
1069
- ### Aggregations
954
+ #### Named scopes
1070
955
 
1071
- Aggregations are part of the optional sidechannel that can be requested with a query.
956
+ Chewy supports named scopes functionality. There is no specialized DSL for named scopes definition, it is simply about defining class methods.
1072
957
 
1073
- You interact with aggregations using the composable #aggregations method (or its alias #aggs)
958
+ See [Chewy::Search::Scoping](lib/chewy/search/scoping.rb) for details.
1074
959
 
1075
- Let's look at an example.
960
+ #### Scroll API
1076
961
 
1077
- ```ruby
1078
- class UsersIndex < Chewy::Index
1079
- define_type User do
1080
- field :name
1081
- field :rating
1082
- end
1083
- end
1084
-
1085
- all_johns = UsersIndex::User.filter { name == 'john' }.aggs({ avg_rating: { avg: { field: 'rating' } } })
962
+ ElasticSearch scroll API is utilized by a bunch of methods: `scroll_batches`, `scroll_hits`, `scroll_wrappers` and `scroll_objects`.
1086
963
 
1087
- avg_johns_rating = all_johns.aggs
1088
- # => {"avg_rating"=>{"value"=>3.5}}
1089
- ```
964
+ See [Chewy::Search::Scrolling](lib/chewy/search/scrolling.rb) for details.
1090
965
 
1091
- It is convenient to name aggregations that you intend to reuse regularly. This is achieve with the .aggregation method,
1092
- which is also available under the .agg alias method.
966
+ #### Loading objects
1093
967
 
1094
- Here's the same example from before
968
+ It is possible to load ORM/ODM source objects with the `objects` method. To provide additional loading options use `load` method:
1095
969
 
1096
970
  ```ruby
1097
- class UsersIndex < Chewy::Index
1098
- define_type User do
1099
- field :name
1100
- field :rating, type: "long"
1101
- agg :avg_rating do
1102
- { avg: { field: 'rating' } }
1103
- end
1104
- end
1105
- end
1106
-
1107
- all_johns = UsersIndex::User.filter { name == 'john' }.aggs(:avg_rating)
1108
-
1109
- avg_johns_rating = all_johns.aggs
1110
- # => {"avg_rating"=>{"value"=>3.5}}
971
+ PlacesIndex.load(scope: -> { active }).to_a # to_a returns `Chewy::Type` wrappers.
972
+ PlacesIndex.load(scope: -> { active }).objects # An array of AR source objects.
1111
973
  ```
1112
974
 
1113
- It is possible to run into collisions between named aggregations. This occurs when there is more than one aggregation
1114
- with the same name. To explicitly reference an aggregation you provide a string to the #aggs method of the form:
1115
- `index_name#document_type.aggregation_name`
975
+ See [Chewy::Search::Loader](lib/chewy/search/loader.rb) for more details.
1116
976
 
1117
- Consider this example where there are two separate aggregations named `avg_rating`
977
+ In case when it is necessary to iterate through both of the wrappers and objects simultaneously, `object_hash` method helps a lot:
1118
978
 
1119
979
  ```ruby
1120
- class UsersIndex < Chewy::Index
1121
- define_type User do
1122
- field :name
1123
- field :rating, type: "long"
1124
- agg :avg_rating do
1125
- { avg: { field: 'rating' } }
1126
- end
1127
- end
1128
- define_type Post do
1129
- field :title
1130
- field :body
1131
- field :comments do
1132
- field :message
1133
- field :rating, type: "long"
1134
- end
1135
- agg :avg_rating do
1136
- { avg: { field: 'comments.rating' } }
1137
- end
1138
- end
980
+ scope = PlacesIndex.load(scope: -> { active })
981
+ scope.each do |wrapper|
982
+ scope.object_hash[wrapper]
1139
983
  end
1140
-
1141
- all_docs = UsersIndex.filter {match_all}.aggs("users#user.avg_rating")
1142
- all_docs.aggs
1143
- # => {"users#user.avg_rating"=>{"value"=>3.5}}
1144
984
  ```
1145
985
 
1146
- ### Script fields
986
+ #### Legacy DSL incompatibilities
1147
987
 
1148
- Script fields allow you to execute Elasticsearch's scripting languages such as groovy and javascript. More about supported languages and what scripting is [here](https://www.elastic.co/guide/en/elasticsearch/reference/0.90/modules-scripting.html). This feature allows you to calculate the distance between geo points, for example. This is how to use the DSL:
988
+ * Filters advanced block DSL is not supported anymore, `elasticsearch-dsl` is used instead.
989
+ * 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.
990
+ * `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.
991
+ * 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`.
992
+ * `types!` method is no more, use `except(:types).types(...)`
993
+ * Named aggregations are not supported, use named scopes instead.
994
+ * A lot of query-level methods were not ported: everything that is related to boost and scoring. Use `query` manipulation to provide them.
995
+ * `Chewy::Type#_object` returns nil always. Use `Chewy::Search::Response#object_hash` instead.
1149
996
 
1150
- ```ruby
1151
- UsersIndex.script_fields(
1152
- distance: {
1153
- params: {
1154
- lat: 37.569976,
1155
- lon: -122.351591
1156
- },
1157
- script: "doc['coordinates'].distanceInMiles(lat, lon)"
1158
- }
1159
- )
1160
- ```
1161
- Here, `coordinates` is a field with type `geo_point`. There will be a `distance` field for the index's model in the search result.
997
+ ### Rake tasks
1162
998
 
1163
- ### Script scoring
999
+ For a Rails application, some index-maintaining rake tasks are defined.
1164
1000
 
1165
- 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:
1001
+ #### `chewy:reset`
1166
1002
 
1167
- ```ruby
1168
- UsersIndex.script_score("_score * doc['my_numeric_field'].value")
1003
+ 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).
1004
+
1005
+ ```bash
1006
+ rake chewy:reset # resets all the existing indices
1007
+ rake chewy:reset[users] # resets UsersIndex only
1008
+ rake chewy:reset[users,places] # resets UsersIndex and PlacesIndex
1009
+ rake chewy:reset[-users,places] # resets every index in the application except specified ones
1169
1010
  ```
1170
1011
 
1171
- ### Boost Factor
1012
+ #### `chewy:upgrade`
1172
1013
 
1173
- Boost factors are a way to add a boost to a query where documents match the filter. If you have some users who are experts and some who are regular users, you might want to give the experts a higher score and boost to the top of the search results. You can accomplish this by using the #boost_factor method and adding a boost score of 5 for an expert user:
1014
+ Performs reset exactly the same way as `chewy:reset` does, but only when the index specification (setting or mapping) was changed.
1174
1015
 
1175
- ```ruby
1176
- UsersIndex.boost_factor(5, filter: {term: {type: 'Expert'}})
1177
- ```
1016
+ It works only when index specification is locked in `Chewy::Stash::Specification` index. The first run will reset all indexes and lock their specifications.
1178
1017
 
1179
- ### Objects loading
1018
+ See [Chewy::Stash::Specification](lib/chewy/stash.rb) and [Chewy::Index::Specification](lib/chewy/index/specification.rb) for more details.
1180
1019
 
1181
- It is possible to load source objects from the database for every search result:
1182
1020
 
1183
- ```ruby
1184
- scope = UsersIndex.filter(range: {rating: {gte: 100}})
1021
+ ```bash
1022
+ rake chewy:upgrade # upgrades all the existing indices
1023
+ rake chewy:upgrade[users] # upgrades UsersIndex only
1024
+ rake chewy:upgrade[users,places] # upgrades UsersIndex and PlacesIndex
1025
+ rake chewy:upgrade[-users,places] # upgrades every index in the application except specified ones
1026
+ ```
1185
1027
 
1186
- scope.load # => scope is marked to return User instances array
1187
- scope.load.query(...) # => since objects are loaded lazily you can complete scope
1188
- scope.load(user: { scope: ->{ includes(:country) }}) # you can also pass loading scopes for each
1189
- # possibly returned type
1190
- scope.load(user: { scope: User.includes(:country) }) # the second scope passing way.
1191
- scope.load(scope: ->{ includes(:country) }) # and more common scope applied to every loaded object type.
1028
+ #### `chewy:update`
1192
1029
 
1193
- scope.only(:id).load # it is optimal to request ids only if you are not planning to use type objects
1194
- ```
1030
+ It doesn't create indexes, it simply imports everything to the existing ones and fails if the index was not created before.
1195
1031
 
1196
- The `preload` method takes the same options as `load` and ORM/ODM objects will be loaded, but the scope will still return an array of Chewy wrappers. To access real objects use the `_object` wrapper method:
1032
+ 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.
1197
1033
 
1198
- ```ruby
1199
- UsersIndex.filter(range: {rating: {gte: 100}}).preload(...).query(...).map(&:_object)
1034
+ ```bash
1035
+ rake chewy:update # updates all the existing indices
1036
+ rake chewy:update[users] # updates UsersIndex only
1037
+ rake chewy:update[users,places#city] # updates the whole UsersIndex and PlacesIndex::City type
1038
+ 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
1200
1039
  ```
1201
1040
 
1202
- See [loading.rb](lib/chewy/query/loading.rb) for more details.
1041
+ #### `chewy:sync`
1203
1042
 
1204
- ### `ActiveSupport::Notifications` support
1043
+ Provides a way to synchronize outdated indexes with the source quickly and without doing a full reset.
1205
1044
 
1206
- Chewy has notifying the following events:
1045
+ Arguments are similar to the ones taken by `chewy:update` task. It is possible to specify a particular type or a whole index.
1207
1046
 
1208
- #### `search_query.chewy` payload
1047
+ See [Chewy::Type::Syncer](lib/chewy/type/syncer.rb) for more details.
1209
1048
 
1210
- * `payload[:index]`: requested index class
1211
- * `payload[:request]`: request hash
1049
+ ```bash
1050
+ rake chewy:sync # synchronizes all the existing indices
1051
+ rake chewy:sync[users] # synchronizes UsersIndex only
1052
+ rake chewy:sync[users,places#city] # synchronizes the whole UsersIndex and PlacesIndex::City type
1053
+ 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
1054
+ ```
1212
1055
 
1213
- #### `import_objects.chewy` payload
1056
+ #### `chewy:deploy`
1214
1057
 
1215
- * `payload[:type]`: currently imported type
1216
- * `payload[:import]`: imports stats, total imported and deleted objects count:
1058
+ 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.
1217
1059
 
1218
- ```ruby
1219
- {index: 30, delete: 5}
1220
- ```
1060
+ It is not possible to specify any particular types/indexes for this task as it doesn't make much sense.
1221
1061
 
1222
- * `payload[:errors]`: might not exists. Contains grouped errors with objects ids list:
1062
+ 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.
1223
1063
 
1224
- ```ruby
1225
- {index: {
1226
- 'error 1 text' => ['1', '2', '3'],
1227
- 'error 2 text' => ['4']
1228
- }, delete: {
1229
- 'delete error text' => ['10', '12']
1230
- }}
1231
- ```
1064
+ Also, there is always full reset alternative with `rake chewy:reset`.
1232
1065
 
1233
- #### NewRelic integration
1066
+ #### Parallelizing rake tasks
1234
1067
 
1235
- To integrate with NewRelic you may use the following example source (config/initializers/chewy.rb):
1068
+ 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.
1236
1069
 
1237
- ```ruby
1238
- ActiveSupport::Notifications.subscribe('import_objects.chewy') do |name, start, finish, id, payload|
1239
- metric_name = "Database/ElasticSearch/import"
1240
- duration = (finish - start).to_f
1241
- logged = "#{payload[:type]} #{payload[:import].to_a.map{ |i| i.join(':') }.join(', ')}"
1242
-
1243
- self.class.trace_execution_scoped([metric_name]) do
1244
- NewRelic::Agent.instance.transaction_sampler.notice_sql(logged, nil, duration)
1245
- NewRelic::Agent.instance.sql_sampler.notice_sql(logged, metric_name, nil, duration)
1246
- NewRelic::Agent.record_metric(metric_name, duration)
1247
- end
1248
- end
1070
+ [https://github.com/grosser/parallel](https://github.com/grosser/parallel) gem is required to use these tasks.
1249
1071
 
1250
- ActiveSupport::Notifications.subscribe('search_query.chewy') do |name, start, finish, id, payload|
1251
- metric_name = "Database/ElasticSearch/search"
1252
- duration = (finish - start).to_f
1253
- logged = "#{payload[:type].presence || payload[:index]} #{payload[:request]}"
1072
+ If the number of processes is not specified explicitly - `parallel` gem tries to automatically derive the number of processes to use.
1254
1073
 
1255
- self.class.trace_execution_scoped([metric_name]) do
1256
- NewRelic::Agent.instance.transaction_sampler.notice_sql(logged, nil, duration)
1257
- NewRelic::Agent.instance.sql_sampler.notice_sql(logged, metric_name, nil, duration)
1258
- NewRelic::Agent.record_metric(metric_name, duration)
1259
- end
1260
- end
1074
+ ```bash
1075
+ rake chewy:parallel:reset
1076
+ rake chewy:parallel:upgrade[4]
1077
+ rake chewy:parallel:update[4,places#city]
1078
+ rake chewy:parallel:sync[4,-users]
1079
+ rake chewy:parallel:deploy[4] # performs parallel upgrade and parallel sync afterwards
1261
1080
  ```
1262
1081
 
1263
- ### Rake tasks
1082
+ #### `chewy:journal`
1264
1083
 
1265
- Inside the Rails application, some index-maintaining rake tasks are defined.
1084
+ 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.
1266
1085
 
1267
1086
  ```bash
1268
- rake chewy:reset # resets all the existing indices, declared in app/chewy
1269
- rake chewy:reset[users] # resets UsersIndex only
1270
- rake chewy:reset[users,projects] # resets UsersIndex and ProjectsIndex
1271
- rake chewy:reset[-users,projects] # resets every index in application except specified ones
1272
-
1273
- rake chewy:update # updates all the existing indices, declared in app/chewy
1274
- rake chewy:update[users] # updates UsersIndex only
1275
- rake chewy:update[users,projects] # updates UsersIndex and ProjectsIndex
1276
- rake chewy:update[-users,projects] # updates every index in application except specified ones
1277
-
1087
+ rake chewy:journal:apply["$(date -v-1H -u +%FT%TZ)"] # apply journaled changes for the past hour
1088
+ rake chewy:journal:apply["$(date -v-1H -u +%FT%TZ)",users] # apply journaled changes for the past hour on UsersIndex only
1278
1089
  ```
1279
1090
 
1280
- `rake chewy:reset` performs zero-downtime reindexing as described [here](https://www.elastic.co/blog/changing-mapping-with-zero-downtime). So basically rake task creates a new index with uniq suffix and then simply aliases it to the common index name. The previous index is deleted afterwards (see `Chewy::Index.reset!` for more details).
1281
-
1282
-
1283
- ### Rspec integration
1091
+ ### RSpec integration
1284
1092
 
1285
1093
  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.
1286
1094
 
@@ -1288,22 +1096,19 @@ Just add `require 'chewy/rspec'` to your spec_helper.rb and you will get additio
1288
1096
 
1289
1097
  Add `require 'chewy/minitest'` to your test_helper.rb, and then for tests which you'd like indexing test hooks, `include Chewy::Minitest::Helpers`.
1290
1098
 
1099
+ 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
1100
+
1101
+ 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.
1102
+
1291
1103
  ### DatabaseCleaner
1292
1104
 
1293
- 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` indexes 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:
1105
+ 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:
1294
1106
 
1295
1107
  ```ruby
1296
1108
  #config/initializers/chewy.rb
1297
1109
  Chewy.use_after_commit_callbacks = !Rails.env.test?
1298
1110
  ```
1299
1111
 
1300
- ## TODO a.k.a coming soon:
1301
-
1302
- * Typecasting support
1303
- * Advanced (simplified) query DSL: `UsersIndex.query { email == 'my@gmail.com' }` will produce term query
1304
- * update_all support
1305
- * Maybe, closer ORM/ODM integration, creating index classes implicitly
1306
-
1307
1112
  ## Contributing
1308
1113
 
1309
1114
  1. Fork it (http://github.com/toptal/chewy/fork)
@@ -1319,3 +1124,8 @@ Use the following Rake tasks to control the Elasticsearch cluster while developi
1319
1124
  rake elasticsearch:start # start Elasticsearch cluster on 9250 port for tests
1320
1125
  rake elasticsearch:stop # stop Elasticsearch
1321
1126
  ```
1127
+
1128
+ ## Copyright
1129
+
1130
+ Copyright (c) 2013-2021 Toptal, LLC. See [LICENSE.txt](LICENSE.txt) for
1131
+ further details.