chewy 0.8.4 → 5.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (303) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +1 -0
  3. data/.rubocop.yml +56 -0
  4. data/.rubocop_todo.yml +44 -0
  5. data/.travis.yml +36 -67
  6. data/.yardopts +5 -0
  7. data/Appraisals +63 -58
  8. data/CHANGELOG.md +168 -11
  9. data/Gemfile +16 -9
  10. data/Guardfile +5 -5
  11. data/LEGACY_DSL.md +497 -0
  12. data/README.md +403 -470
  13. data/Rakefile +11 -1
  14. data/chewy.gemspec +12 -15
  15. data/gemfiles/rails.4.0.activerecord.gemfile +9 -9
  16. data/gemfiles/rails.4.1.activerecord.gemfile +9 -9
  17. data/gemfiles/rails.4.2.activerecord.gemfile +8 -8
  18. data/gemfiles/rails.4.2.mongoid.5.2.gemfile +16 -0
  19. data/gemfiles/rails.5.0.activerecord.gemfile +16 -0
  20. data/gemfiles/rails.5.0.mongoid.6.1.gemfile +16 -0
  21. data/gemfiles/rails.5.1.activerecord.gemfile +16 -0
  22. data/gemfiles/rails.5.1.mongoid.6.3.gemfile +16 -0
  23. data/gemfiles/rails.5.2.activerecord.gemfile +16 -0
  24. data/gemfiles/sequel.4.45.gemfile +11 -0
  25. data/lib/chewy/backports/deep_dup.rb +1 -1
  26. data/lib/chewy/backports/duplicable.rb +1 -0
  27. data/lib/chewy/config.rb +53 -21
  28. data/lib/chewy/errors.rb +6 -6
  29. data/lib/chewy/fields/base.rb +59 -29
  30. data/lib/chewy/fields/root.rb +49 -14
  31. data/lib/chewy/index/actions.rb +95 -36
  32. data/lib/chewy/index/aliases.rb +2 -1
  33. data/lib/chewy/index/settings.rb +10 -5
  34. data/lib/chewy/index/specification.rb +60 -0
  35. data/lib/chewy/index.rb +239 -138
  36. data/lib/chewy/journal.rb +55 -0
  37. data/lib/chewy/log_subscriber.rb +8 -8
  38. data/lib/chewy/minitest/helpers.rb +77 -0
  39. data/lib/chewy/minitest/search_index_receiver.rb +80 -0
  40. data/lib/chewy/minitest.rb +1 -0
  41. data/lib/chewy/query/compose.rb +18 -19
  42. data/lib/chewy/query/criteria.rb +34 -24
  43. data/lib/chewy/query/filters.rb +28 -11
  44. data/lib/chewy/query/loading.rb +3 -4
  45. data/lib/chewy/query/nodes/and.rb +1 -1
  46. data/lib/chewy/query/nodes/base.rb +1 -1
  47. data/lib/chewy/query/nodes/bool.rb +6 -4
  48. data/lib/chewy/query/nodes/equal.rb +4 -4
  49. data/lib/chewy/query/nodes/exists.rb +1 -1
  50. data/lib/chewy/query/nodes/expr.rb +2 -2
  51. data/lib/chewy/query/nodes/field.rb +35 -31
  52. data/lib/chewy/query/nodes/has_child.rb +1 -0
  53. data/lib/chewy/query/nodes/has_parent.rb +1 -0
  54. data/lib/chewy/query/nodes/has_relation.rb +10 -12
  55. data/lib/chewy/query/nodes/missing.rb +1 -1
  56. data/lib/chewy/query/nodes/not.rb +1 -1
  57. data/lib/chewy/query/nodes/or.rb +1 -1
  58. data/lib/chewy/query/nodes/prefix.rb +3 -2
  59. data/lib/chewy/query/nodes/query.rb +1 -1
  60. data/lib/chewy/query/nodes/range.rb +9 -9
  61. data/lib/chewy/query/nodes/raw.rb +1 -1
  62. data/lib/chewy/query/nodes/regexp.rb +13 -9
  63. data/lib/chewy/query/nodes/script.rb +4 -4
  64. data/lib/chewy/query/pagination.rb +10 -1
  65. data/lib/chewy/query.rb +286 -170
  66. data/lib/chewy/railtie.rb +7 -6
  67. data/lib/chewy/rake_helper.rb +275 -37
  68. data/lib/chewy/repository.rb +2 -2
  69. data/lib/chewy/rspec/update_index.rb +70 -65
  70. data/lib/chewy/rspec.rb +1 -1
  71. data/lib/chewy/runtime/version.rb +4 -4
  72. data/lib/chewy/search/loader.rb +83 -0
  73. data/lib/chewy/{query → search}/pagination/kaminari.rb +13 -5
  74. data/lib/chewy/search/pagination/will_paginate.rb +43 -0
  75. data/lib/chewy/search/parameters/aggs.rb +16 -0
  76. data/lib/chewy/search/parameters/allow_partial_search_results.rb +27 -0
  77. data/lib/chewy/search/parameters/concerns/bool_storage.rb +24 -0
  78. data/lib/chewy/search/parameters/concerns/hash_storage.rb +23 -0
  79. data/lib/chewy/search/parameters/concerns/integer_storage.rb +14 -0
  80. data/lib/chewy/search/parameters/concerns/query_storage.rb +238 -0
  81. data/lib/chewy/search/parameters/concerns/string_array_storage.rb +23 -0
  82. data/lib/chewy/search/parameters/concerns/string_storage.rb +14 -0
  83. data/lib/chewy/search/parameters/docvalue_fields.rb +12 -0
  84. data/lib/chewy/search/parameters/explain.rb +16 -0
  85. data/lib/chewy/search/parameters/filter.rb +47 -0
  86. data/lib/chewy/search/parameters/highlight.rb +16 -0
  87. data/lib/chewy/search/parameters/indices.rb +123 -0
  88. data/lib/chewy/search/parameters/indices_boost.rb +52 -0
  89. data/lib/chewy/search/parameters/limit.rb +17 -0
  90. data/lib/chewy/search/parameters/load.rb +32 -0
  91. data/lib/chewy/search/parameters/min_score.rb +16 -0
  92. data/lib/chewy/search/parameters/none.rb +27 -0
  93. data/lib/chewy/search/parameters/offset.rb +17 -0
  94. data/lib/chewy/search/parameters/order.rb +64 -0
  95. data/lib/chewy/search/parameters/post_filter.rb +19 -0
  96. data/lib/chewy/search/parameters/preference.rb +16 -0
  97. data/lib/chewy/search/parameters/profile.rb +16 -0
  98. data/lib/chewy/search/parameters/query.rb +19 -0
  99. data/lib/chewy/search/parameters/request_cache.rb +27 -0
  100. data/lib/chewy/search/parameters/rescore.rb +29 -0
  101. data/lib/chewy/search/parameters/script_fields.rb +16 -0
  102. data/lib/chewy/search/parameters/search_after.rb +20 -0
  103. data/lib/chewy/search/parameters/search_type.rb +16 -0
  104. data/lib/chewy/search/parameters/source.rb +73 -0
  105. data/lib/chewy/search/parameters/storage.rb +95 -0
  106. data/lib/chewy/search/parameters/stored_fields.rb +63 -0
  107. data/lib/chewy/search/parameters/suggest.rb +16 -0
  108. data/lib/chewy/search/parameters/terminate_after.rb +16 -0
  109. data/lib/chewy/search/parameters/timeout.rb +16 -0
  110. data/lib/chewy/search/parameters/track_scores.rb +16 -0
  111. data/lib/chewy/search/parameters/types.rb +20 -0
  112. data/lib/chewy/search/parameters/version.rb +16 -0
  113. data/lib/chewy/search/parameters.rb +167 -0
  114. data/lib/chewy/search/query_proxy.rb +257 -0
  115. data/lib/chewy/search/request.rb +1045 -0
  116. data/lib/chewy/search/response.rb +119 -0
  117. data/lib/chewy/search/scoping.rb +50 -0
  118. data/lib/chewy/search/scrolling.rb +134 -0
  119. data/lib/chewy/search.rb +81 -26
  120. data/lib/chewy/stash.rb +79 -0
  121. data/lib/chewy/strategy/active_job.rb +1 -0
  122. data/lib/chewy/strategy/atomic.rb +2 -4
  123. data/lib/chewy/strategy/base.rb +4 -4
  124. data/lib/chewy/strategy/bypass.rb +1 -2
  125. data/lib/chewy/strategy/resque.rb +1 -0
  126. data/lib/chewy/strategy/shoryuken.rb +40 -0
  127. data/lib/chewy/strategy/sidekiq.rb +13 -1
  128. data/lib/chewy/strategy/urgent.rb +1 -1
  129. data/lib/chewy/strategy.rb +19 -10
  130. data/lib/chewy/type/actions.rb +26 -2
  131. data/lib/chewy/type/adapter/active_record.rb +50 -24
  132. data/lib/chewy/type/adapter/base.rb +29 -9
  133. data/lib/chewy/type/adapter/mongoid.rb +19 -10
  134. data/lib/chewy/type/adapter/object.rb +195 -31
  135. data/lib/chewy/type/adapter/orm.rb +69 -33
  136. data/lib/chewy/type/adapter/sequel.rb +37 -19
  137. data/lib/chewy/type/crutch.rb +5 -4
  138. data/lib/chewy/type/import/bulk_builder.rb +122 -0
  139. data/lib/chewy/type/import/bulk_request.rb +78 -0
  140. data/lib/chewy/type/import/journal_builder.rb +45 -0
  141. data/lib/chewy/type/import/routine.rb +138 -0
  142. data/lib/chewy/type/import.rb +150 -176
  143. data/lib/chewy/type/mapping.rb +58 -42
  144. data/lib/chewy/type/observe.rb +21 -15
  145. data/lib/chewy/type/syncer.rb +222 -0
  146. data/lib/chewy/type/witchcraft.rb +89 -34
  147. data/lib/chewy/type/wrapper.rb +48 -16
  148. data/lib/chewy/type.rb +77 -49
  149. data/lib/chewy/version.rb +1 -1
  150. data/lib/chewy.rb +95 -52
  151. data/lib/generators/chewy/install_generator.rb +3 -3
  152. data/lib/sequel/plugins/chewy_observe.rb +4 -19
  153. data/lib/tasks/chewy.rake +91 -28
  154. data/spec/chewy/config_spec.rb +130 -12
  155. data/spec/chewy/fields/base_spec.rb +194 -172
  156. data/spec/chewy/fields/root_spec.rb +123 -17
  157. data/spec/chewy/fields/time_fields_spec.rb +10 -9
  158. data/spec/chewy/index/actions_spec.rb +228 -43
  159. data/spec/chewy/index/aliases_spec.rb +2 -2
  160. data/spec/chewy/index/settings_spec.rb +100 -49
  161. data/spec/chewy/index/specification_spec.rb +169 -0
  162. data/spec/chewy/index_spec.rb +159 -63
  163. data/spec/chewy/journal_spec.rb +268 -0
  164. data/spec/chewy/minitest/helpers_spec.rb +90 -0
  165. data/spec/chewy/minitest/search_index_receiver_spec.rb +120 -0
  166. data/spec/chewy/query/criteria_spec.rb +503 -236
  167. data/spec/chewy/query/filters_spec.rb +96 -68
  168. data/spec/chewy/query/loading_spec.rb +80 -42
  169. data/spec/chewy/query/nodes/and_spec.rb +3 -7
  170. data/spec/chewy/query/nodes/bool_spec.rb +5 -13
  171. data/spec/chewy/query/nodes/equal_spec.rb +20 -20
  172. data/spec/chewy/query/nodes/exists_spec.rb +7 -7
  173. data/spec/chewy/query/nodes/has_child_spec.rb +42 -23
  174. data/spec/chewy/query/nodes/has_parent_spec.rb +42 -23
  175. data/spec/chewy/query/nodes/match_all_spec.rb +2 -2
  176. data/spec/chewy/query/nodes/missing_spec.rb +6 -5
  177. data/spec/chewy/query/nodes/not_spec.rb +5 -7
  178. data/spec/chewy/query/nodes/or_spec.rb +3 -7
  179. data/spec/chewy/query/nodes/prefix_spec.rb +6 -6
  180. data/spec/chewy/query/nodes/query_spec.rb +3 -3
  181. data/spec/chewy/query/nodes/range_spec.rb +19 -19
  182. data/spec/chewy/query/nodes/raw_spec.rb +2 -2
  183. data/spec/chewy/query/nodes/regexp_spec.rb +31 -19
  184. data/spec/chewy/query/nodes/script_spec.rb +5 -5
  185. data/spec/chewy/query/pagination/kaminari_spec.rb +3 -55
  186. data/spec/chewy/query/pagination/will_paginate_spec.rb +5 -0
  187. data/spec/chewy/query/pagination_spec.rb +25 -22
  188. data/spec/chewy/query_spec.rb +510 -505
  189. data/spec/chewy/rake_helper_spec.rb +381 -0
  190. data/spec/chewy/repository_spec.rb +8 -8
  191. data/spec/chewy/rspec/update_index_spec.rb +215 -113
  192. data/spec/chewy/runtime_spec.rb +2 -2
  193. data/spec/chewy/search/loader_spec.rb +117 -0
  194. data/spec/chewy/search/pagination/kaminari_examples.rb +71 -0
  195. data/spec/chewy/search/pagination/kaminari_spec.rb +21 -0
  196. data/spec/chewy/search/pagination/will_paginate_examples.rb +63 -0
  197. data/spec/chewy/search/pagination/will_paginate_spec.rb +23 -0
  198. data/spec/chewy/search/parameters/aggs_spec.rb +5 -0
  199. data/spec/chewy/search/parameters/bool_storage_examples.rb +53 -0
  200. data/spec/chewy/search/parameters/docvalue_fields_spec.rb +5 -0
  201. data/spec/chewy/search/parameters/explain_spec.rb +5 -0
  202. data/spec/chewy/search/parameters/filter_spec.rb +5 -0
  203. data/spec/chewy/search/parameters/hash_storage_examples.rb +59 -0
  204. data/spec/chewy/search/parameters/highlight_spec.rb +5 -0
  205. data/spec/chewy/search/parameters/indices_spec.rb +191 -0
  206. data/spec/chewy/search/parameters/integer_storage_examples.rb +32 -0
  207. data/spec/chewy/search/parameters/limit_spec.rb +5 -0
  208. data/spec/chewy/search/parameters/load_spec.rb +60 -0
  209. data/spec/chewy/search/parameters/min_score_spec.rb +32 -0
  210. data/spec/chewy/search/parameters/none_spec.rb +5 -0
  211. data/spec/chewy/search/parameters/offset_spec.rb +5 -0
  212. data/spec/chewy/search/parameters/order_spec.rb +65 -0
  213. data/spec/chewy/search/parameters/post_filter_spec.rb +5 -0
  214. data/spec/chewy/search/parameters/preference_spec.rb +5 -0
  215. data/spec/chewy/search/parameters/profile_spec.rb +5 -0
  216. data/spec/chewy/search/parameters/query_spec.rb +5 -0
  217. data/spec/chewy/search/parameters/query_storage_examples.rb +388 -0
  218. data/spec/chewy/search/parameters/request_cache_spec.rb +67 -0
  219. data/spec/chewy/search/parameters/rescore_spec.rb +62 -0
  220. data/spec/chewy/search/parameters/script_fields_spec.rb +5 -0
  221. data/spec/chewy/search/parameters/search_after_spec.rb +32 -0
  222. data/spec/chewy/search/parameters/search_type_spec.rb +5 -0
  223. data/spec/chewy/search/parameters/source_spec.rb +156 -0
  224. data/spec/chewy/search/parameters/storage_spec.rb +60 -0
  225. data/spec/chewy/search/parameters/stored_fields_spec.rb +126 -0
  226. data/spec/chewy/search/parameters/string_array_storage_examples.rb +63 -0
  227. data/spec/chewy/search/parameters/string_storage_examples.rb +32 -0
  228. data/spec/chewy/search/parameters/suggest_spec.rb +5 -0
  229. data/spec/chewy/search/parameters/terminate_after_spec.rb +5 -0
  230. data/spec/chewy/search/parameters/timeout_spec.rb +5 -0
  231. data/spec/chewy/search/parameters/track_scores_spec.rb +5 -0
  232. data/spec/chewy/search/parameters/types_spec.rb +5 -0
  233. data/spec/chewy/search/parameters/version_spec.rb +5 -0
  234. data/spec/chewy/search/parameters_spec.rb +145 -0
  235. data/spec/chewy/search/query_proxy_spec.rb +68 -0
  236. data/spec/chewy/search/request_spec.rb +685 -0
  237. data/spec/chewy/search/response_spec.rb +192 -0
  238. data/spec/chewy/search/scrolling_spec.rb +169 -0
  239. data/spec/chewy/search_spec.rb +37 -20
  240. data/spec/chewy/stash_spec.rb +95 -0
  241. data/spec/chewy/strategy/active_job_spec.rb +8 -2
  242. data/spec/chewy/strategy/atomic_spec.rb +4 -1
  243. data/spec/chewy/strategy/resque_spec.rb +8 -2
  244. data/spec/chewy/strategy/shoryuken_spec.rb +66 -0
  245. data/spec/chewy/strategy/sidekiq_spec.rb +10 -2
  246. data/spec/chewy/strategy_spec.rb +6 -6
  247. data/spec/chewy/type/actions_spec.rb +29 -10
  248. data/spec/chewy/type/adapter/active_record_spec.rb +357 -139
  249. data/spec/chewy/type/adapter/mongoid_spec.rb +220 -101
  250. data/spec/chewy/type/adapter/object_spec.rb +129 -40
  251. data/spec/chewy/type/adapter/sequel_spec.rb +304 -152
  252. data/spec/chewy/type/import/bulk_builder_spec.rb +279 -0
  253. data/spec/chewy/type/import/bulk_request_spec.rb +102 -0
  254. data/spec/chewy/type/import/journal_builder_spec.rb +95 -0
  255. data/spec/chewy/type/import/routine_spec.rb +110 -0
  256. data/spec/chewy/type/import_spec.rb +360 -244
  257. data/spec/chewy/type/mapping_spec.rb +96 -29
  258. data/spec/chewy/type/observe_spec.rb +25 -15
  259. data/spec/chewy/type/syncer_spec.rb +123 -0
  260. data/spec/chewy/type/witchcraft_spec.rb +122 -44
  261. data/spec/chewy/type/wrapper_spec.rb +63 -23
  262. data/spec/chewy/type_spec.rb +32 -10
  263. data/spec/chewy_spec.rb +82 -12
  264. data/spec/spec_helper.rb +16 -2
  265. data/spec/support/active_record.rb +6 -2
  266. data/spec/support/class_helpers.rb +4 -19
  267. data/spec/support/mongoid.rb +17 -5
  268. data/spec/support/sequel.rb +6 -1
  269. metadata +250 -57
  270. data/gemfiles/rails.3.2.activerecord.gemfile +0 -15
  271. data/gemfiles/rails.3.2.activerecord.kaminari.gemfile +0 -14
  272. data/gemfiles/rails.3.2.activerecord.will_paginate.gemfile +0 -14
  273. data/gemfiles/rails.4.0.activerecord.kaminari.gemfile +0 -14
  274. data/gemfiles/rails.4.0.activerecord.will_paginate.gemfile +0 -14
  275. data/gemfiles/rails.4.0.mongoid.4.0.0.gemfile +0 -15
  276. data/gemfiles/rails.4.0.mongoid.4.0.0.kaminari.gemfile +0 -14
  277. data/gemfiles/rails.4.0.mongoid.4.0.0.will_paginate.gemfile +0 -14
  278. data/gemfiles/rails.4.0.mongoid.5.1.0.gemfile +0 -15
  279. data/gemfiles/rails.4.0.mongoid.5.1.0.kaminari.gemfile +0 -14
  280. data/gemfiles/rails.4.0.mongoid.5.1.0.will_paginate.gemfile +0 -14
  281. data/gemfiles/rails.4.1.activerecord.kaminari.gemfile +0 -14
  282. data/gemfiles/rails.4.1.activerecord.will_paginate.gemfile +0 -14
  283. data/gemfiles/rails.4.1.mongoid.4.0.0.gemfile +0 -15
  284. data/gemfiles/rails.4.1.mongoid.4.0.0.kaminari.gemfile +0 -14
  285. data/gemfiles/rails.4.1.mongoid.4.0.0.will_paginate.gemfile +0 -14
  286. data/gemfiles/rails.4.1.mongoid.5.1.0.gemfile +0 -15
  287. data/gemfiles/rails.4.1.mongoid.5.1.0.kaminari.gemfile +0 -14
  288. data/gemfiles/rails.4.1.mongoid.5.1.0.will_paginate.gemfile +0 -14
  289. data/gemfiles/rails.4.2.activerecord.kaminari.gemfile +0 -15
  290. data/gemfiles/rails.4.2.activerecord.will_paginate.gemfile +0 -15
  291. data/gemfiles/rails.4.2.mongoid.4.0.0.gemfile +0 -15
  292. data/gemfiles/rails.4.2.mongoid.4.0.0.kaminari.gemfile +0 -14
  293. data/gemfiles/rails.4.2.mongoid.4.0.0.will_paginate.gemfile +0 -14
  294. data/gemfiles/rails.4.2.mongoid.5.1.0.gemfile +0 -15
  295. data/gemfiles/rails.4.2.mongoid.5.1.0.kaminari.gemfile +0 -14
  296. data/gemfiles/rails.4.2.mongoid.5.1.0.will_paginate.gemfile +0 -14
  297. data/gemfiles/rails.5.0.0.beta3.activerecord.gemfile +0 -16
  298. data/gemfiles/rails.5.0.0.beta3.activerecord.kaminari.gemfile +0 -16
  299. data/gemfiles/rails.5.0.0.beta3.activerecord.will_paginate.gemfile +0 -15
  300. data/gemfiles/sequel.4.31.gemfile +0 -13
  301. data/lib/chewy/query/pagination/will_paginate.rb +0 -27
  302. data/lib/chewy/query/scoping.rb +0 -20
  303. 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="http://www.toptal.com/"><img src="http://www.toptal.com/assets/public/blocks/logo/big.png" alt="Toptal" width="105" height="34"></a></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
8
 
9
9
  # Chewy
10
10
 
11
- Chewy is an ODM and wrapper for [the official Elasticsearch client](https://github.com/elasticsearch/elasticsearch-ruby).
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](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/mapping.html).
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: 'string', analyzer: 'standard'
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](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-update-settings.html).
165
- [See root object settings here](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/mapping-root-object-type.html).
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: 'string', value: ->{ full_name.strip } do
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 would no longer be effective.
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/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:
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 would look like the following pseudo-code (even in Mongoid):
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 would look like this:
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, so use reasonable formatting to make `method_source` be able to extract field value proc sources. Also value procs with splat arguments are not supported right now. 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.
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 would perform `City.popular.count` requests for ES documents update.
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
- ### Index querying
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
- Also, queries can be performed on a type individually:
778
+ Chewy has notifying the following events:
602
779
 
603
- ```ruby
604
- UsersIndex::User.filter(term: {name: 'foo'}) # will return UserIndex::User collection only
605
- ```
780
+ #### `search_query.chewy` payload
606
781
 
607
- 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
608
- `filter_mode` and `query_mode` respectively.
782
+ * `payload[:index]`: requested index class
783
+ * `payload[:request]`: request hash
609
784
 
610
- The default `filter_mode` is `:and` and the default `query_mode` is `bool`.
785
+ #### `import_objects.chewy` payload
611
786
 
612
- Available filter modes are: `:and`, `:or`, `:must`, `:should` and any minimum_should_match-acceptable value
787
+ * `payload[:type]`: currently imported type
788
+ * `payload[:import]`: imports stats, total imported and deleted objects count:
613
789
 
614
- 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.
790
+ ```ruby
791
+ {index: 30, delete: 5}
792
+ ```
615
793
 
616
- ```ruby
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
- See [query.rb](lib/chewy/query.rb) for more details.
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
- ### Additional query action.
805
+ ### NewRelic integration
625
806
 
626
- You may also perform additional actions on the query scope, such as deleting of all the scope documents:
807
+ To integrate with NewRelic you may use the following example source (config/initializers/chewy.rb):
627
808
 
628
809
  ```ruby
629
- UsersIndex.delete_all
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
- ### Filters query DSL
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
- There is a test version of the filter-creating DSL:
818
+ def finish(_name, id, _payload)
819
+ pop_event(id).finish
820
+ end
638
821
 
639
- ```ruby
640
- UsersIndex.filter{ name == 'Fred' } # will produce `term` filter.
641
- UsersIndex.filter{ age <= 42 } # will produce `range` filter.
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
- The basis of the DSL is the expression. There are 2 types of expressions:
829
+ def initialize(*args)
830
+ super
831
+ @segment = start_segment
832
+ end
645
833
 
646
- * Simple function
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
- ```ruby
649
- UsersIndex.filter{ s('doc["num"] > 1') } # script expression
650
- UsersIndex.filter{ q(query_string: {query: 'lazy fox'}) } # query expression
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
- * Field-dependent composite expression
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
- ```ruby
657
- UsersIndex.filter{ name == 'Name' } # simple field term filter
658
- UsersIndex.filter{ name(:bool) == ['Name1', 'Name2'] } # terms query with `execution: :bool` option passed
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
- ```ruby
665
- UsersIndex.filter{ (name == 'Name') & (email == 'Email') } # combination produces `and` filter
666
- UsersIndex.filter{
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
- There is also a special syntax for cache enabling:
861
+ def operation
862
+ OPERATIONS[name]
863
+ end
674
864
 
675
- ```ruby
676
- UsersIndex.filter{ ~name == 'Name' } # you can apply tilde to the field name
677
- UsersIndex.filter{ ~(name == 'Name') } # or to the whole expression
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
- # if you are applying cache to the one part of range filter
680
- # the whole filter will be cached:
681
- UsersIndex.filter{ ~(age > 42) & (age <= 50) }
872
+ def host
873
+ Chewy.client.transport.hosts.first[:host]
874
+ end
682
875
 
683
- # You can pass cache options as a field option also.
684
- UsersIndex.filter{ name(cache: true) == 'Name' }
685
- UsersIndex.filter{ name(cache: false) == 'Name' }
876
+ def port
877
+ Chewy.client.transport.hosts.first[:port]
878
+ end
879
+ end
880
+ end
686
881
 
687
- # With regexp filter you can pass _cache_key
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
- Compliance cheatsheet for filters and DSL expressions:
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
- UsersIndex.filter{ name(:b) == ['Fred', 'Johny'] }
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
- UsersIndex.filter{ name(:f) == ['Fred', 'Johny'] }
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
- * Regexp filter (== and =~ are equivalent)
891
+ The new DSL is enabled by default, here is a quick introduction.
744
892
 
745
- ```json
746
- {"regexp": {"name.first": "s.*y"}}
893
+ #### Composing requests
747
894
 
748
- {"not": {"regexp": {"name.first": "s.*y"}}}
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
- ```ruby
754
- UsersIndex.filter{ name.first == /s.*y/ }
755
- UsersIndex.filter{ name.first =~ /s.*y/ }
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
- ```json
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
- ```ruby
864
- UsersIndex.filter{ (name == 'Name') | (age < 42) }
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
- ```json
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
- ```ruby
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
- * Match all filter
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
- ```json
880
- {"match_all": {}}
881
- ```
917
+ ```ruby
918
+ PlaceIndex.limit(10).offset(30).order(:name, {population: {order: :desc}})
919
+ ```
882
920
 
883
- ```ruby
884
- UsersIndex.filter{ match_all }
885
- ```
921
+ Request DSL also provides additional scope actions, like `delete_all`, `exists?`, `count`, `pluck`, etc.
886
922
 
887
- * Has child filter
923
+ #### Pagination
888
924
 
889
- ```json
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
- ```ruby
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
- * Has parent filter
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
- ```json
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
- ```ruby
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
- See [filters.rb](lib/chewy/query/filters.rb) for more details.
935
+ ElasticSearch scroll API is utilized by a bunch of methods: `scroll_batches`, `scroll_hits`, `scroll_wrappers` and `scroll_objects`.
912
936
 
913
- ### Faceting
937
+ See [Chewy::Search::Scrolling](lib/chewy/search/scrolling.rb) for details.
914
938
 
915
- 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.
939
+ #### Loading objects
916
940
 
917
- 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:
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
- UsersIndex.filter{ [...] }.facets({countries: {terms: {field: 'country'}}})
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
- You interact with aggregations using the composable #aggregations method (or its alias #aggs)
948
+ See [Chewy::Search::Loader](lib/chewy/search/loader.rb) for more details.
936
949
 
937
- Let's look at an example.
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
- class UsersIndex < Chewy::Index
941
- define_type User do
942
- field :name
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
- It is convenient to name aggregations that you intend to reuse regularly. This is achieve with the .aggregation method,
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
- all_johns = UsersIndex::User.filter { name == 'john' }.aggs(:avg_rating)
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
- avg_johns_rating = all_johns.aggs
972
- # => {"avg_rating"=>{"value"=>3.5}}
973
- ```
970
+ ### Rake tasks
974
971
 
975
- It is possible to run into collisions between named aggregations. This occurs when there is more than one aggregation
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
- Consider this example where there are two separate aggregations named `avg_rating`
974
+ #### `chewy:reset`
980
975
 
981
- ```ruby
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
- all_docs = UsersIndex.filter {match_all}.aggs("users#user.avg_rating")
1004
- all_docs.aggs
1005
- # => {"users#user.avg_rating"=>{"value"=>3.5}}
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
- ### Script fields
985
+ #### `chewy:upgrade`
1009
986
 
1010
- 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:
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
- ```ruby
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
- ### Script scoring
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
- ```ruby
1030
- UsersIndex.script_score("_score * doc['my_numeric_field'].value")
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
- ### Boost Factor
1001
+ #### `chewy:update`
1034
1002
 
1035
- 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:
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
- ```ruby
1038
- UsersIndex.boost_factor(5, filter: {term: {type: 'Expert'}})
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
- ### Objects loading
1014
+ #### `chewy:sync`
1042
1015
 
1043
- It is possible to load source objects from the database for every search result:
1016
+ Provides a way to synchronize outdated indexes with the source quickly and without doing a full reset.
1044
1017
 
1045
- ```ruby
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
- scope.load # => scope is marked to return User instances array
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
- scope.only(:id).load # it is optimal to request ids only if you are not planning to use type objects
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
- 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:
1029
+ #### `chewy:deploy`
1059
1030
 
1060
- ```ruby
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
- See [loading.rb](lib/chewy/query/loading.rb) for more details.
1033
+ It is not possible to specify any particular types/indexes for this task as it doesn't make much sense.
1065
1034
 
1066
- ### `ActiveSupport::Notifications` support
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
- Chewy has notifying the following events:
1037
+ Also, there is always full reset alternative with `rake chewy:reset`.
1069
1038
 
1070
- #### `search_query.chewy` payload
1039
+ #### Parallelizing rake tasks
1071
1040
 
1072
- * `payload[:index]`: requested index class
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
- #### `import_objects.chewy` payload
1043
+ [https://github.com/grosser/parallel](https://github.com/grosser/parallel) gem is required to use these tasks.
1076
1044
 
1077
- * `payload[:type]`: currently imported type
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
- #### NewRelic integration
1096
-
1097
- To integrate with NewRelic you may use the following example source (config/initializers/chewy.rb):
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
- ```ruby
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
- ActiveSupport::Notifications.subscribe('search_query.chewy') do |name, start, finish, id, payload|
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
- self.class.trace_execution_scoped([metric_name]) do
1118
- NewRelic::Agent.instance.transaction_sampler.notice_sql(logged, nil, duration)
1119
- NewRelic::Agent.instance.sql_sampler.notice_sql(logged, metric_name, nil, duration)
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
- ### Rake tasks
1126
-
1127
- Inside the Rails application, some index-maintaining rake tasks are defined.
1064
+ ### Rspec integration
1128
1065
 
1129
- ```bash
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
- rake chewy:update # updates all the existing indices, declared in app/chewy
1134
- rake chewy:update[users] # updates UsersIndex only
1135
- ```
1068
+ ### Minitest integration
1136
1069
 
1137
- `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).
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
- ### Rspec integration
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
- 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.
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` 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:
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