chewy 0.8.1 → 0.8.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +10 -8
- data/Appraisals +8 -0
- data/CHANGELOG.md +33 -6
- data/Gemfile +6 -4
- data/README.md +240 -111
- data/gemfiles/rails.4.2.activerecord.gemfile +1 -0
- data/gemfiles/rails.4.2.activerecord.kaminari.gemfile +1 -0
- data/gemfiles/rails.4.2.activerecord.will_paginate.gemfile +1 -0
- data/gemfiles/sequel.4.23.gemfile +13 -0
- data/lib/chewy.rb +24 -11
- data/lib/chewy/config.rb +4 -4
- data/lib/chewy/index.rb +1 -1
- data/lib/chewy/index/settings.rb +1 -1
- data/lib/chewy/query.rb +43 -4
- data/lib/chewy/railtie.rb +2 -2
- data/lib/chewy/rake_helper.rb +62 -0
- data/lib/chewy/rspec/update_index.rb +3 -3
- data/lib/chewy/strategy.rb +6 -0
- data/lib/chewy/strategy/active_job.rb +28 -0
- data/lib/chewy/strategy/atomic.rb +1 -1
- data/lib/chewy/strategy/sidekiq.rb +3 -1
- data/lib/chewy/type.rb +2 -1
- data/lib/chewy/type/adapter/active_record.rb +9 -2
- data/lib/chewy/type/adapter/base.rb +6 -0
- data/lib/chewy/type/adapter/mongoid.rb +7 -1
- data/lib/chewy/type/adapter/orm.rb +1 -1
- data/lib/chewy/type/adapter/sequel.rb +125 -0
- data/lib/chewy/type/mapping.rb +26 -1
- data/lib/chewy/type/observe.rb +40 -17
- data/lib/chewy/version.rb +1 -1
- data/lib/sequel/plugins/chewy_observe.rb +71 -0
- data/lib/tasks/chewy.rake +19 -61
- data/spec/chewy/config_spec.rb +9 -5
- data/spec/chewy/fields/base_spec.rb +21 -7
- data/spec/chewy/index/actions_spec.rb +5 -5
- data/spec/chewy/query_spec.rb +69 -0
- data/spec/chewy/runtime_spec.rb +1 -1
- data/spec/chewy/strategy/active_job_spec.rb +49 -0
- data/spec/chewy/strategy_spec.rb +2 -2
- data/spec/chewy/type/adapter/sequel_spec.rb +46 -0
- data/spec/chewy/type/import_spec.rb +4 -2
- data/spec/chewy/type/mapping_spec.rb +19 -0
- data/spec/chewy/type/observe_spec.rb +43 -14
- data/spec/chewy_spec.rb +2 -3
- data/spec/spec_helper.rb +6 -3
- data/spec/support/active_record.rb +5 -8
- data/spec/support/mongoid.rb +5 -8
- data/spec/support/sequel.rb +69 -0
- metadata +14 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 465b8f0c2bff702e61235bbd9b6782f3f57296e6
|
4
|
+
data.tar.gz: 60827a551d9b4338ee87a91c346b84cfbcca6aa2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e0efb611f827fa291ea9f3765d14e50450e6787f0541e9c04f034d79e20189cdb8dd718e2c8c8074e7736ac3575018e13fe9317f880d7b6d0429ac1ab060e6b2
|
7
|
+
data.tar.gz: 0270d359d7831c3f1c0217369f32d5017c7b90e7871780a5e79f7945414c7a3aaadf39f1505ab85c7a3c61a1f2fbb28ae49c183034f43c12d1ed065cf66e9acf
|
data/.travis.yml
CHANGED
@@ -1,10 +1,11 @@
|
|
1
1
|
language: ruby
|
2
|
+
sudo: false
|
2
3
|
services:
|
3
4
|
- mongodb
|
4
5
|
rvm:
|
5
|
-
- 2.0
|
6
|
-
- 2.1
|
7
|
-
- 2.2
|
6
|
+
- 2.0
|
7
|
+
- 2.1
|
8
|
+
- 2.2
|
8
9
|
# - rbx
|
9
10
|
gemfile:
|
10
11
|
- gemfiles/rails.3.2.activerecord.gemfile
|
@@ -28,15 +29,16 @@ gemfile:
|
|
28
29
|
- gemfiles/rails.4.2.mongoid.gemfile
|
29
30
|
- gemfiles/rails.4.2.mongoid.kaminari.gemfile
|
30
31
|
- gemfiles/rails.4.2.mongoid.will_paginate.gemfile
|
32
|
+
- gemfiles/sequel.4.23.gemfile
|
31
33
|
matrix:
|
32
34
|
exclude:
|
33
|
-
- rvm: 2.2
|
35
|
+
- rvm: 2.2
|
34
36
|
gemfile: gemfiles/rails.3.2.activerecord.gemfile
|
35
|
-
- rvm: 2.2
|
37
|
+
- rvm: 2.2
|
36
38
|
gemfile: gemfiles/rails.3.2.activerecord.kaminari.gemfile
|
37
|
-
- rvm: 2.2
|
39
|
+
- rvm: 2.2
|
38
40
|
gemfile: gemfiles/rails.3.2.activerecord.will_paginate.gemfile
|
39
41
|
before_install:
|
40
|
-
- curl -# https://download.elasticsearch.org/elasticsearch/elasticsearch/elasticsearch-1.
|
42
|
+
- curl -# https://download.elasticsearch.org/elasticsearch/elasticsearch/elasticsearch-1.7.2.tar.gz | tar xz -C /tmp
|
41
43
|
before_script:
|
42
|
-
- TEST_CLUSTER_COMMAND="/tmp/elasticsearch-1.
|
44
|
+
- TEST_CLUSTER_COMMAND="/tmp/elasticsearch-1.7.2/bin/elasticsearch" rake elasticsearch:start
|
data/Appraisals
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
appraise "rails.#{version}.activerecord" do
|
3
3
|
gem 'activerecord', "~> #{version}.0"
|
4
4
|
gem 'activesupport', "~> #{version}.0"
|
5
|
+
gem 'activejob', "~> #{version}.0" if version >= '4.2'
|
5
6
|
gem 'resque', require: false
|
6
7
|
gem 'sidekiq', require: false
|
7
8
|
end
|
@@ -9,12 +10,14 @@
|
|
9
10
|
appraise "rails.#{version}.activerecord.kaminari" do
|
10
11
|
gem 'activerecord', "~> #{version}.0"
|
11
12
|
gem 'activesupport', "~> #{version}.0"
|
13
|
+
gem 'activejob', "~> #{version}.0" if version >= '4.2'
|
12
14
|
gem 'kaminari', '0.16.3', require: false
|
13
15
|
end
|
14
16
|
|
15
17
|
appraise "rails.#{version}.activerecord.will_paginate" do
|
16
18
|
gem 'activerecord', "~> #{version}.0"
|
17
19
|
gem 'activesupport', "~> #{version}.0"
|
20
|
+
gem 'activejob', "~> #{version}.0" if version >= '4.2'
|
18
21
|
gem 'will_paginate', require: false
|
19
22
|
end
|
20
23
|
end
|
@@ -39,3 +42,8 @@ end
|
|
39
42
|
gem 'will_paginate', require: false
|
40
43
|
end
|
41
44
|
end
|
45
|
+
|
46
|
+
appraise "sequel.4.23" do
|
47
|
+
gem 'sequel', "~> 4.23.0"
|
48
|
+
gem 'activesupport', '~> 4.2.0'
|
49
|
+
end
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,32 @@
|
|
1
1
|
# master
|
2
2
|
|
3
|
+
# Version 0.8.2
|
4
|
+
|
5
|
+
## Changes
|
6
|
+
|
7
|
+
* ActiveJob strategy by @mkcode
|
8
|
+
|
9
|
+
* Async strategies tweak (@AndreySavelyev)
|
10
|
+
|
11
|
+
* GeoPoint readme (@joonty)
|
12
|
+
|
13
|
+
* Multiple grammar fixes and code improvements (@biow0lf)
|
14
|
+
|
15
|
+
* Named aggregations by @caldwecr
|
16
|
+
|
17
|
+
* Sequel adapter by @jirutka
|
18
|
+
|
19
|
+
* Rake helper methods extracted (@caldwecr, @jirutka)
|
20
|
+
|
21
|
+
* Multiple grammar fixes (@henrebotha)
|
22
|
+
|
23
|
+
* Ability to pass a proc to `update_index` to define updating index dynamically (@SeTeM)
|
24
|
+
|
25
|
+
|
26
|
+
## Bugfixes
|
27
|
+
|
28
|
+
* Fixed transport logger and tracer configuration
|
29
|
+
|
3
30
|
# Version 0.8.1
|
4
31
|
|
5
32
|
## Bugfixes
|
@@ -18,7 +45,7 @@
|
|
18
45
|
|
19
46
|
* Added `.script_fields` chainable method to query (@ka8725)
|
20
47
|
|
21
|
-
* `update_index` mocha support (@lardawge)
|
48
|
+
* `update_index` matcher mocha support (@lardawge)
|
22
49
|
|
23
50
|
* `:resque` async strategy
|
24
51
|
|
@@ -90,7 +117,7 @@
|
|
90
117
|
|
91
118
|
* Multiple enhancements by @DNNX
|
92
119
|
|
93
|
-
* Added `script_fields` to search
|
120
|
+
* Added `script_fields` to search criteria (@ka8725)
|
94
121
|
|
95
122
|
* ORM adapters now completely relies on the default scope. This means every scope or objects passed to import are merged with default scope so basically there is no need to define `delete_if` block. Default scope strongly restricts objects which may land in the current index.
|
96
123
|
|
@@ -269,13 +296,13 @@
|
|
269
296
|
|
270
297
|
# Version 0.4.0
|
271
298
|
|
272
|
-
* Changed `update_index` matcher behavior. Now it compare array attributes position-
|
299
|
+
* Changed `update_index` matcher behavior. Now it compare array attributes position-independently.
|
273
300
|
|
274
301
|
* Search aggregations API support (@arion).
|
275
302
|
|
276
303
|
* Chewy::Query#facets called without params performs the request and returns facets.
|
277
304
|
|
278
|
-
* Added `Type.template`
|
305
|
+
* Added `Type.template` DSL method for root objects dynamic templates definition. See [mapping.rb](lib/chewy/type/mapping.rb) for more details.
|
279
306
|
|
280
307
|
* ActiveRecord adapter custom `primary_key` support (@matthee).
|
281
308
|
|
@@ -414,8 +441,8 @@
|
|
414
441
|
|
415
442
|
# Version 0.0.1
|
416
443
|
|
417
|
-
* Query
|
444
|
+
* Query DSL
|
418
445
|
|
419
|
-
* Basic index
|
446
|
+
* Basic index handling
|
420
447
|
|
421
448
|
* Initial version
|
data/Gemfile
CHANGED
@@ -2,14 +2,16 @@ source 'https://rubygems.org'
|
|
2
2
|
|
3
3
|
gemspec
|
4
4
|
|
5
|
-
gem 'activerecord'
|
5
|
+
# gem 'activerecord'
|
6
6
|
# gem 'mongoid'
|
7
|
+
# gem 'sequel'
|
7
8
|
|
8
9
|
# gem 'kaminari', require: false
|
9
|
-
# gem '
|
10
|
+
# gem 'will_paginate', require: false
|
10
11
|
|
11
|
-
gem 'resque', require: false
|
12
|
-
gem 'sidekiq', require: false
|
12
|
+
# gem 'resque', require: false
|
13
|
+
# gem 'sidekiq', require: false
|
14
|
+
# gem 'activejob', require: false
|
13
15
|
|
14
16
|
group :test do
|
15
17
|
gem 'guard'
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
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.
|
3
|
-
[![Code Climate](https://codeclimate.com/github/toptal/chewy.
|
2
|
+
[![Build Status](https://travis-ci.org/toptal/chewy.svg)](https://travis-ci.org/toptal/chewy)
|
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
6
|
<p align="right">Sponsored by</p>
|
@@ -8,25 +8,28 @@
|
|
8
8
|
|
9
9
|
# Chewy
|
10
10
|
|
11
|
-
Chewy is ODM and wrapper for official
|
11
|
+
Chewy is an ODM and wrapper for [the official Elasticsearch client](https://github.com/elasticsearch/elasticsearch-ruby).
|
12
12
|
|
13
|
-
## Why
|
13
|
+
## Why Chewy?
|
14
14
|
|
15
|
-
* Multi-model
|
15
|
+
* Multi-model indices.
|
16
16
|
|
17
|
-
Index classes are independent from ORM/ODM models. Now implementing
|
17
|
+
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.
|
18
18
|
|
19
19
|
* Every index is observable by all the related models.
|
20
20
|
|
21
|
-
Most of the indexed models are related to other and sometimes it is
|
21
|
+
Most of the indexed models are related to other and sometimes it is necessary to denormalize this related data and put at the same object. For example, you need to index an array of tags together with an article. Chewy allows you to specify an updateable index for every model separately - so corresponding articles will be reindexed on any tag update.
|
22
22
|
|
23
23
|
* Bulk import everywhere.
|
24
24
|
|
25
|
-
Chewy utilizes bulk ES API for full reindexing or index updates.
|
25
|
+
Chewy utilizes the bulk ES API for full reindexing or index updates. It also uses atomic updates. All the changed objects are collected inside the atomic block and the index is updated once at the end with all the collected objects. See `Chewy.strategy(:atomic)` for more details.
|
26
26
|
|
27
27
|
* Powerful querying DSL.
|
28
28
|
|
29
|
-
Chewy has
|
29
|
+
Chewy has an ActiveRecord-style query DSL. It is chainable, mergeable and lazy, so you can produce queries in the most efficient way. It also has object-oriented query and filter builders.
|
30
|
+
|
31
|
+
* Support for ActiveRecord, [Mongoid](https://github.com/mongoid/mongoid) and [Sequel](https://github.com/jeremyevans/sequel).
|
32
|
+
|
30
33
|
|
31
34
|
## Installation
|
32
35
|
|
@@ -46,9 +49,9 @@ Or install it yourself as:
|
|
46
49
|
|
47
50
|
### Client settings
|
48
51
|
|
49
|
-
There are
|
52
|
+
There are two ways to configure the Chewy client: the `Chewy.settings` hash and `chewy.yml`
|
50
53
|
|
51
|
-
You can create this file manually or run `rails g chewy:install
|
54
|
+
You can create this file manually or run `rails g chewy:install`.
|
52
55
|
|
53
56
|
```ruby
|
54
57
|
# config/initializers/chewy.rb
|
@@ -65,17 +68,17 @@ development:
|
|
65
68
|
host: 'localhost:9200'
|
66
69
|
```
|
67
70
|
|
68
|
-
The
|
71
|
+
The resulting config merges both hashes. Client options are passed as is to `Elasticsearch::Transport::Client` except for the `:prefix`, which is used internally by Chewy to create prefixed index names:
|
69
72
|
|
70
73
|
```ruby
|
71
74
|
Chewy.settings = {prefix: 'test'}
|
72
75
|
UsersIndex.index_name # => 'test_users'
|
73
76
|
```
|
74
77
|
|
75
|
-
|
78
|
+
The logger may be set explicitly:
|
76
79
|
|
77
80
|
```ruby
|
78
|
-
Chewy.logger = Logger.new
|
81
|
+
Chewy.logger = Logger.new(STDOUT)
|
79
82
|
```
|
80
83
|
|
81
84
|
See [config.rb](lib/chewy/config.rb) for more details.
|
@@ -106,7 +109,7 @@ See [config.rb](lib/chewy/config.rb) for more details.
|
|
106
109
|
class UsersIndex < Chewy::Index
|
107
110
|
define_type User.active.includes(:country, :badges, :projects) do
|
108
111
|
field :first_name, :last_name # multiple fields without additional options
|
109
|
-
field :email, analyzer: 'email' #
|
112
|
+
field :email, analyzer: 'email' # Elasticsearch-related options
|
110
113
|
field :country, value: ->(user) { user.country.name } # custom value proc
|
111
114
|
field :badges, value: ->(user) { user.badges.map(&:name) } # passing array values to index
|
112
115
|
field :projects do # the same block syntax for multi_field, if `:type` is specified
|
@@ -122,9 +125,9 @@ See [config.rb](lib/chewy/config.rb) for more details.
|
|
122
125
|
end
|
123
126
|
```
|
124
127
|
|
125
|
-
|
128
|
+
[See here for mapping definitions](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/mapping.html).
|
126
129
|
|
127
|
-
4. Add some index- and type-related settings.
|
130
|
+
4. Add some index- and type-related settings. Analyzer repositories might be used as well. See `Chewy::Index.settings` docs for details:
|
128
131
|
|
129
132
|
```ruby
|
130
133
|
class UsersIndex < Chewy::Index
|
@@ -149,7 +152,7 @@ See [config.rb](lib/chewy/config.rb) for more details.
|
|
149
152
|
field :title
|
150
153
|
field :description
|
151
154
|
end
|
152
|
-
field :about_translations, type: 'object' # pass object type
|
155
|
+
field :about_translations, type: 'object' # pass object type explicitly if necessary
|
153
156
|
field :rating, type: 'integer'
|
154
157
|
field :created, type: 'date', include_in_all: false,
|
155
158
|
value: ->{ created_at }
|
@@ -158,16 +161,16 @@ See [config.rb](lib/chewy/config.rb) for more details.
|
|
158
161
|
end
|
159
162
|
```
|
160
163
|
|
161
|
-
|
162
|
-
|
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).
|
163
166
|
|
164
167
|
See [mapping.rb](lib/chewy/type/mapping.rb) for more details.
|
165
168
|
|
166
|
-
5. Add model
|
169
|
+
5. Add model-observing code
|
167
170
|
|
168
171
|
```ruby
|
169
172
|
class User < ActiveRecord::Base
|
170
|
-
update_index('users#user') { self } # specifying index, type and
|
173
|
+
update_index('users#user') { self } # specifying index, type and back-reference
|
171
174
|
# for updating after user save or destroy
|
172
175
|
end
|
173
176
|
|
@@ -178,7 +181,7 @@ See [config.rb](lib/chewy/config.rb) for more details.
|
|
178
181
|
end
|
179
182
|
|
180
183
|
class Project < ActiveRecord::Base
|
181
|
-
update_index('users#user') { user if user.active? } # you can return even `nil` from the
|
184
|
+
update_index('users#user') { user if user.active? } # you can return even `nil` from the back-reference
|
182
185
|
end
|
183
186
|
|
184
187
|
class Badge < ActiveRecord::Base
|
@@ -187,16 +190,22 @@ See [config.rb](lib/chewy/config.rb) for more details.
|
|
187
190
|
update_index('users') { users } # if index has only one type
|
188
191
|
# there is no need to specify updated type
|
189
192
|
end
|
193
|
+
|
194
|
+
class Book < ActiveRecord::Base
|
195
|
+
update_index(->(book) {"books#book_#{book.language}"}) { self } # dynamic index and type with proc.
|
196
|
+
# For book with language == "en"
|
197
|
+
# this code will generate `books#book_en`
|
198
|
+
end
|
190
199
|
```
|
191
200
|
|
192
|
-
Also, you can use second argument for method name passing:
|
201
|
+
Also, you can use the second argument for method name passing:
|
193
202
|
|
194
203
|
```ruby
|
195
204
|
update_index('users#user', :self)
|
196
205
|
update_index('users#user', :users)
|
197
206
|
```
|
198
207
|
|
199
|
-
In case of belongs_to association you may need to update both associated objects, previous and current:
|
208
|
+
In the case of a belongs_to association you may need to update both associated objects, previous and current:
|
200
209
|
|
201
210
|
```ruby
|
202
211
|
class City < ActiveRecord::Base
|
@@ -212,9 +221,67 @@ See [config.rb](lib/chewy/config.rb) for more details.
|
|
212
221
|
end
|
213
222
|
```
|
214
223
|
|
224
|
+
You can observe Sequel models in the same way as ActiveRecord:
|
225
|
+
|
226
|
+
```ruby
|
227
|
+
class User < Sequel::Model
|
228
|
+
update_index('users#user') { self }
|
229
|
+
end
|
230
|
+
```
|
231
|
+
|
232
|
+
However, to make it work, you must load the chewy plugin into Sequel model:
|
233
|
+
|
234
|
+
```ruby
|
235
|
+
Sequel::Model.plugin :chewy_observe # for all models, or...
|
236
|
+
User.plugin :chewy_observe # just for User
|
237
|
+
```
|
238
|
+
|
239
|
+
### Multi (nested) and object field types
|
240
|
+
|
241
|
+
To define an objects field you can simply nest fields in the DSL:
|
242
|
+
|
243
|
+
```ruby
|
244
|
+
field :projects do
|
245
|
+
field :title
|
246
|
+
field :description
|
247
|
+
end
|
248
|
+
```
|
249
|
+
|
250
|
+
This will automatically set the type or root field to `object`. You may also specify `type: 'objects'` explicitly.
|
251
|
+
|
252
|
+
To define a multi field you have to specify any type except for `object` or `nested` in the root field:
|
253
|
+
|
254
|
+
```ruby
|
255
|
+
field :full_name, type: 'string', value: ->{ full_name.strip } do
|
256
|
+
field :ordered, analyzer: `ordered`
|
257
|
+
field :untouched, index: 'not_analyzed'
|
258
|
+
end
|
259
|
+
```
|
260
|
+
|
261
|
+
The `value:` option for internal fields would no longer be effective.
|
262
|
+
|
263
|
+
### Geo Point fields
|
264
|
+
|
265
|
+
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:
|
266
|
+
|
267
|
+
```ruby
|
268
|
+
field :coordinates, type: 'geo_point', value: ->{ {lat: latitude, lon: longitude} }
|
269
|
+
```
|
270
|
+
|
271
|
+
or by using nested fields:
|
272
|
+
|
273
|
+
```ruby
|
274
|
+
field :coordinates, type: 'geo_point' do
|
275
|
+
field :lat, value: ->{ latitude }
|
276
|
+
field :long, value: ->{ longitude }
|
277
|
+
end
|
278
|
+
```
|
279
|
+
|
280
|
+
See the section on *Script fields* for details on calculating distance in a search.
|
281
|
+
|
215
282
|
### Crutches™ technology
|
216
283
|
|
217
|
-
Assume you are defining index like this (product has_many categories through product_categories):
|
284
|
+
Assume you are defining your index like this (product has_many categories through product_categories):
|
218
285
|
|
219
286
|
```ruby
|
220
287
|
class ProductsIndex < Chewy::Index
|
@@ -225,7 +292,7 @@ class ProductsIndex < Chewy::Index
|
|
225
292
|
end
|
226
293
|
```
|
227
294
|
|
228
|
-
Then
|
295
|
+
Then the Chewy reindexing flow would look like the following pseudo-code (even in Mongoid):
|
229
296
|
|
230
297
|
```ruby
|
231
298
|
Product.includes(:categories).find_in_batches(1000) do |batch|
|
@@ -237,9 +304,9 @@ Product.includes(:categories).find_in_batches(1000) do |batch|
|
|
237
304
|
end
|
238
305
|
```
|
239
306
|
|
240
|
-
But in
|
307
|
+
But in Rails 4.1 and 4.2 you may face a problem with slow associations (take a look at https://github.com/rails/rails/pull/19423). Also, there might be really complicated cases when associations are not applicable.
|
241
308
|
|
242
|
-
Then you
|
309
|
+
Then you can replace Rails associations with Chewy Crutches™ technology:
|
243
310
|
|
244
311
|
```ruby
|
245
312
|
class ProductsIndex < Chewy::Index
|
@@ -249,7 +316,7 @@ class ProductsIndex < Chewy::Index
|
|
249
316
|
data = ProductCategory.joins(:category).where(product_id: collection.map(&:id)).pluck(:product_id, 'categories.name')
|
250
317
|
# then we have to convert fetched data to appropriate format
|
251
318
|
# this will return our data in structure like:
|
252
|
-
# {123 => ['
|
319
|
+
# {123 => ['sweets', 'juices'], 456 => ['meat']}
|
253
320
|
data.each.with_object({}) { |(id, name), result| (result[id] ||= []).push(name) }
|
254
321
|
end
|
255
322
|
|
@@ -260,7 +327,7 @@ class ProductsIndex < Chewy::Index
|
|
260
327
|
end
|
261
328
|
```
|
262
329
|
|
263
|
-
|
330
|
+
An example flow would look like this:
|
264
331
|
|
265
332
|
```ruby
|
266
333
|
Product.includes(:categories).find_in_batches(1000) do |batch|
|
@@ -274,11 +341,11 @@ Product.includes(:categories).find_in_batches(1000) do |batch|
|
|
274
341
|
end
|
275
342
|
```
|
276
343
|
|
277
|
-
So Chewy Crutches™ technology is able to increase your indexing performance in some cases up to
|
344
|
+
So Chewy Crutches™ technology is able to increase your indexing performance in some cases up to a hundredfold or even more depending on your associations complexity.
|
278
345
|
|
279
346
|
### Types access
|
280
347
|
|
281
|
-
You
|
348
|
+
You can access index-defined types with the following API:
|
282
349
|
|
283
350
|
```ruby
|
284
351
|
UsersIndex::User # => UsersIndex::User
|
@@ -291,7 +358,7 @@ UsersIndex.type_names # => ['user']
|
|
291
358
|
### Index manipulation
|
292
359
|
|
293
360
|
```ruby
|
294
|
-
UsersIndex.delete # destroy index if exists
|
361
|
+
UsersIndex.delete # destroy index if it exists
|
295
362
|
UsersIndex.delete!
|
296
363
|
|
297
364
|
UsersIndex.create
|
@@ -312,7 +379,7 @@ UsersIndex.import user: User.where('rating > 100') # import only active users to
|
|
312
379
|
UsersIndex.reset! # purges index and imports default data for all types
|
313
380
|
```
|
314
381
|
|
315
|
-
|
382
|
+
If the passed user is `#destroyed?`, or satisfies a `delete_if` type option, or the specified id does not exist in the database, import will perform delete from index action for this object.
|
316
383
|
|
317
384
|
```ruby
|
318
385
|
define_type User, delete_if: :deleted_at
|
@@ -338,18 +405,13 @@ class CitiesIndex < Chewy::Index
|
|
338
405
|
end
|
339
406
|
```
|
340
407
|
|
341
|
-
If you
|
342
|
-
UndefinedUpdateStrategy exception instead of normal object saving
|
343
|
-
and index update. This exception forces you to choose appropriate
|
344
|
-
update strategy for current context.
|
408
|
+
If you do something like `City.first.save!` you'll get an UndefinedUpdateStrategy exception instead of the object saving and index updating. This exception forces you to choose an appropriate update strategy for the current context.
|
345
409
|
|
346
|
-
If you want to return
|
347
|
-
`Chewy.root_strategy = :bypass`.
|
410
|
+
If you want to return to the pre-0.7.0 behavior - just set `Chewy.root_strategy = :bypass`.
|
348
411
|
|
349
412
|
#### `:atomic`
|
350
413
|
|
351
|
-
The main strategy here is `:atomic`. Assume you have to update a
|
352
|
-
lot of records in db.
|
414
|
+
The main strategy here is `:atomic`. Assume you have to update a lot of records in the db.
|
353
415
|
|
354
416
|
```ruby
|
355
417
|
Chewy.strategy(:atomic) do
|
@@ -357,15 +419,11 @@ Chewy.strategy(:atomic) do
|
|
357
419
|
end
|
358
420
|
```
|
359
421
|
|
360
|
-
Using this strategy delays index update request until the end of
|
361
|
-
block. Updated records are aggregated and index update happens with
|
362
|
-
bulk API. So this strategy is highly optimized.
|
422
|
+
Using this strategy delays the index update request until the end of the block. Updated records are aggregated and the index update happens with the bulk API. So this strategy is highly optimized.
|
363
423
|
|
364
424
|
#### `:resque`
|
365
425
|
|
366
|
-
|
367
|
-
Default queue name is `chewy`.
|
368
|
-
Patch `Chewy::Strategy::Resque::Worker` for index updates improving.
|
426
|
+
This does the same thing as `:atomic`, but asynchronously using resque. The default queue name is `chewy`. Patch `Chewy::Strategy::Resque::Worker` for index updates improving.
|
369
427
|
|
370
428
|
```ruby
|
371
429
|
Chewy.strategy(:resque) do
|
@@ -375,8 +433,7 @@ end
|
|
375
433
|
|
376
434
|
#### `:sidekiq`
|
377
435
|
|
378
|
-
|
379
|
-
Patch `Chewy::Strategy::Sidekiq::Worker` for index updates improving.
|
436
|
+
This does the same thing as `:atomic`, but asynchronously using sidekiq. Patch `Chewy::Strategy::Sidekiq::Worker` for index updates improving.
|
380
437
|
|
381
438
|
```ruby
|
382
439
|
Chewy.strategy(:sidekiq) do
|
@@ -384,10 +441,19 @@ Chewy.strategy(:sidekiq) do
|
|
384
441
|
end
|
385
442
|
```
|
386
443
|
|
444
|
+
#### `:active_job`
|
445
|
+
|
446
|
+
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.
|
447
|
+
|
448
|
+
```ruby
|
449
|
+
Chewy.strategy(:active_job) do
|
450
|
+
City.popular.map(&:do_some_update_action!)
|
451
|
+
end
|
452
|
+
```
|
453
|
+
|
387
454
|
#### `:urgent`
|
388
455
|
|
389
|
-
|
390
|
-
index one-by-one.
|
456
|
+
The following strategy is convenient if you are going to update documents in your index one by one.
|
391
457
|
|
392
458
|
```ruby
|
393
459
|
Chewy.strategy(:urgent) do
|
@@ -395,11 +461,9 @@ Chewy.strategy(:urgent) do
|
|
395
461
|
end
|
396
462
|
```
|
397
463
|
|
398
|
-
This code would perform `City.popular.count` requests for ES
|
399
|
-
documents update.
|
464
|
+
This code would perform `City.popular.count` requests for ES documents update.
|
400
465
|
|
401
|
-
|
402
|
-
non-block notation:
|
466
|
+
It is convenient for use in e.g. the Rails console with non-block notation:
|
403
467
|
|
404
468
|
```ruby
|
405
469
|
> Chewy.strategy(:urgent)
|
@@ -408,12 +472,11 @@ non-block notation:
|
|
408
472
|
|
409
473
|
#### `:bypass`
|
410
474
|
|
411
|
-
|
475
|
+
The bypass strategy simply silences index updates.
|
412
476
|
|
413
477
|
#### Nesting
|
414
478
|
|
415
|
-
Strategies are designed to allow nesting, so it is possible
|
416
|
-
to redefine it for nested contexts.
|
479
|
+
Strategies are designed to allow nesting, so it is possible to redefine it for nested contexts.
|
417
480
|
|
418
481
|
```ruby
|
419
482
|
Chewy.strategy(:atomic) do
|
@@ -441,22 +504,19 @@ Chewy.strategy.pop
|
|
441
504
|
city3.do_update! # index updated again
|
442
505
|
```
|
443
506
|
|
444
|
-
#### Designing own strategies
|
507
|
+
#### Designing your own strategies
|
445
508
|
|
446
|
-
See [strategy/base.rb](lib/chewy/strategy/base.rb) for more details.
|
447
|
-
See [strategy/atomic.rb](lib/chewy/strategy/atomic.rb) for example.
|
509
|
+
See [strategy/base.rb](lib/chewy/strategy/base.rb) for more details. See [strategy/atomic.rb](lib/chewy/strategy/atomic.rb) for an example.
|
448
510
|
|
449
511
|
### Rails application strategies integration
|
450
512
|
|
451
|
-
There
|
452
|
-
|
453
|
-
Also migrations are wrapped with `:bypass` strategy. Because the main behavor implies that indexes are resetted after migration, so there is no need for extra index updates.
|
454
|
-
Also indexing might be broken during migrations because of the outdated schema.
|
513
|
+
There are a couple of predefined strategies for your Rails application. Initially, the Rails console uses the `:urgent` strategy by default, except in the sandbox case. When you are running sandbox it switches to the `:bypass` strategy to avoid polluting the index.
|
455
514
|
|
456
|
-
|
515
|
+
Migrations are wrapped with the `:bypass` strategy. Because the main behavior implies that indices are reset after migration, there is no need for extra index updates. Also indexing might be broken during migrations because of the outdated schema.
|
457
516
|
|
458
|
-
|
517
|
+
Controller actions are wrapped with the `:atomic` strategy with middleware just to reduce the number of index update requests inside actions.
|
459
518
|
|
519
|
+
It is also a good idea to set up the `:bypass` strategy inside your test suite and import objects manually only when needed, and use `Chewy.massacre` when needed to flush test ES indices before every example. This will allow you to minimize unnecessary ES requests and reduce overhead.
|
460
520
|
|
461
521
|
```ruby
|
462
522
|
RSpec.configure do |config|
|
@@ -485,24 +545,20 @@ scope.only(:id, :email) # returns ids and emails only
|
|
485
545
|
scope.merge(other_scope) # queries could be merged
|
486
546
|
```
|
487
547
|
|
488
|
-
Also, queries can be performed on a type individually
|
548
|
+
Also, queries can be performed on a type individually:
|
489
549
|
|
490
550
|
```ruby
|
491
551
|
UsersIndex::User.filter(term: {name: 'foo'}) # will return UserIndex::User collection only
|
492
552
|
```
|
493
553
|
|
494
|
-
If you are performing more than one `filter` or `query` in the chain,
|
495
|
-
all the filters and queries will be concatenated in the way specified by
|
554
|
+
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
|
496
555
|
`filter_mode` and `query_mode` respectively.
|
497
556
|
|
498
|
-
|
557
|
+
The default `filter_mode` is `:and` and the default `query_mode` is `bool`.
|
499
558
|
|
500
|
-
Available filter modes are: `:and`, `:or`, `:must`, `:should` and
|
501
|
-
any minimum_should_match-acceptable value
|
559
|
+
Available filter modes are: `:and`, `:or`, `:must`, `:should` and any minimum_should_match-acceptable value
|
502
560
|
|
503
|
-
Available query modes are: `:must`, `:should`, `:dis_max`, any
|
504
|
-
minimum_should_match-acceptable value or float value for dis_max
|
505
|
-
query with tie_breaker specified.
|
561
|
+
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.
|
506
562
|
|
507
563
|
```ruby
|
508
564
|
UsersIndex::User.filter{ name == 'Fred' }.filter{ age < 42 } # will be wrapped with `and` filter
|
@@ -514,7 +570,7 @@ See [query.rb](lib/chewy/query.rb) for more details.
|
|
514
570
|
|
515
571
|
### Additional query action.
|
516
572
|
|
517
|
-
You may also perform additional actions on query scope, such as deleting of all the scope documents:
|
573
|
+
You may also perform additional actions on the query scope, such as deleting of all the scope documents:
|
518
574
|
|
519
575
|
```ruby
|
520
576
|
UsersIndex.delete_all
|
@@ -523,17 +579,16 @@ UsersIndex.filter{ age < 42 }.delete_all
|
|
523
579
|
UsersIndex::User.filter{ age < 42 }.delete_all
|
524
580
|
```
|
525
581
|
|
526
|
-
### Filters query DSL
|
582
|
+
### Filters query DSL
|
527
583
|
|
528
|
-
There is a test version of
|
584
|
+
There is a test version of the filter-creating DSL:
|
529
585
|
|
530
586
|
```ruby
|
531
587
|
UsersIndex.filter{ name == 'Fred' } # will produce `term` filter.
|
532
588
|
UsersIndex.filter{ age <= 42 } # will produce `range` filter.
|
533
589
|
```
|
534
590
|
|
535
|
-
The basis of the DSL is expression.
|
536
|
-
There are 2 types of expressions:
|
591
|
+
The basis of the DSL is the expression. There are 2 types of expressions:
|
537
592
|
|
538
593
|
* Simple function
|
539
594
|
|
@@ -542,10 +597,8 @@ There are 2 types of expressions:
|
|
542
597
|
UsersIndex.filter{ q(query_string: {query: 'lazy fox'}) } # query expression
|
543
598
|
```
|
544
599
|
|
545
|
-
* Field-
|
546
|
-
Consists of the field name (with dot notation
|
547
|
-
value and action operator between them. Field name might take
|
548
|
-
additional options for passing to the result expression.
|
600
|
+
* Field-dependent composite expression
|
601
|
+
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.
|
549
602
|
|
550
603
|
```ruby
|
551
604
|
UsersIndex.filter{ name == 'Name' } # simple field term filter
|
@@ -553,7 +606,7 @@ There are 2 types of expressions:
|
|
553
606
|
UsersIndex.filter{ answers.title =~ /regexp/ } # regexp filter for `answers.title` field
|
554
607
|
```
|
555
608
|
|
556
|
-
You can combine expressions as you wish with combination operators
|
609
|
+
You can combine expressions as you wish with the help of combination operators.
|
557
610
|
|
558
611
|
```ruby
|
559
612
|
UsersIndex.filter{ (name == 'Name') & (email == 'Email') } # combination produces `and` filter
|
@@ -564,10 +617,10 @@ UsersIndex.filter{
|
|
564
617
|
} # many of the combination possibilities
|
565
618
|
```
|
566
619
|
|
567
|
-
|
620
|
+
There is also a special syntax for cache enabling:
|
568
621
|
|
569
622
|
```ruby
|
570
|
-
UsersIndex.filter{ ~name == 'Name' } # you can apply
|
623
|
+
UsersIndex.filter{ ~name == 'Name' } # you can apply tilde to the field name
|
571
624
|
UsersIndex.filter{ ~(name == 'Name') } # or to the whole expression
|
572
625
|
|
573
626
|
# if you are applying cache to the one part of range filter
|
@@ -806,25 +859,102 @@ See [filters.rb](lib/chewy/query/filters.rb) for more details.
|
|
806
859
|
|
807
860
|
### Faceting
|
808
861
|
|
809
|
-
Facets are an optional sidechannel you can request from
|
862
|
+
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.
|
810
863
|
|
811
|
-
For instance, let's request the
|
864
|
+
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:
|
812
865
|
|
813
866
|
```ruby
|
814
867
|
UsersIndex.filter{ [...] }.facets({countries: {terms: {field: 'country'}}})
|
815
868
|
```
|
816
869
|
|
817
|
-
Let's look at what we asked from
|
870
|
+
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.
|
818
871
|
|
819
|
-
|
872
|
+
The response will include the `:facets` sidechannel:
|
820
873
|
|
821
874
|
```
|
822
875
|
< { ... ,"facets":{"countries":{"_type":"terms","missing":?,"total":?,"other":?,"terms":[{"term":"USA","count":?},{"term":"Brazil","count":?}, ...}}
|
823
876
|
```
|
824
877
|
|
878
|
+
### Aggregations
|
879
|
+
|
880
|
+
Aggregations are part of the optional sidechannel that can be requested with a query.
|
881
|
+
|
882
|
+
You interact with aggregations using the composable #aggregations method (or its alias #aggs)
|
883
|
+
|
884
|
+
Let's look at an example.
|
885
|
+
|
886
|
+
```ruby
|
887
|
+
class UsersIndex < Chewy::Index
|
888
|
+
define_type User do
|
889
|
+
field :name
|
890
|
+
field :rating
|
891
|
+
end
|
892
|
+
end
|
893
|
+
|
894
|
+
all_johns = UsersIndex::User.filter { name == 'john' }.aggs({ avg_rating: { avg: { field: 'rating' } } })
|
895
|
+
|
896
|
+
avg_johns_rating = all_johns.aggs
|
897
|
+
# => {"avg_rating"=>{"value"=>3.5}}
|
898
|
+
```
|
899
|
+
|
900
|
+
It is convenient to name aggregations that you intend to reuse regularly. This is achieve with the .aggregation method,
|
901
|
+
which is also available under the .agg alias method.
|
902
|
+
|
903
|
+
Here's the same example from before
|
904
|
+
|
905
|
+
```ruby
|
906
|
+
class UsersIndex < Chewy::Index
|
907
|
+
define_type User do
|
908
|
+
field :name
|
909
|
+
field :rating, type: "long"
|
910
|
+
agg :avg_rating do
|
911
|
+
{ avg: { field: 'rating' } }
|
912
|
+
end
|
913
|
+
end
|
914
|
+
end
|
915
|
+
|
916
|
+
all_johns = UsersIndex::User.filter { name == 'john' }.aggs(:avg_rating)
|
917
|
+
|
918
|
+
avg_johns_rating = all_johns.aggs
|
919
|
+
# => {"avg_rating"=>{"value"=>3.5}}
|
920
|
+
```
|
921
|
+
|
922
|
+
It is possible to run into collisions between named aggregations. This occurs when there is more than one aggregation
|
923
|
+
with the same name. To explicitly reference an aggregation you provide a string to the #aggs method of the form:
|
924
|
+
`index_name#document_type.aggregation_name`
|
925
|
+
|
926
|
+
Consider this example where there are two separate aggregations named `avg_rating`
|
927
|
+
|
928
|
+
```ruby
|
929
|
+
class UsersIndex < Chewy::Index
|
930
|
+
define_type User do
|
931
|
+
field :name
|
932
|
+
field :rating, type: "long"
|
933
|
+
agg :avg_rating do
|
934
|
+
{ avg: { field: 'rating' } }
|
935
|
+
end
|
936
|
+
end
|
937
|
+
define_type Post do
|
938
|
+
field :title
|
939
|
+
field :body
|
940
|
+
field :comments do
|
941
|
+
field :message
|
942
|
+
field :rating, type: "long"
|
943
|
+
end
|
944
|
+
agg :avg_rating do
|
945
|
+
{ avg: { field: 'comments.rating' } }
|
946
|
+
end
|
947
|
+
end
|
948
|
+
end
|
949
|
+
|
950
|
+
all_docs = UsersIndex.filter {match_all}.aggs("users#user.avg_rating")
|
951
|
+
all_docs.aggs
|
952
|
+
# => {"users#user.avg_rating"=>{"value"=>3.5}}
|
953
|
+
```
|
954
|
+
|
825
955
|
### Script fields
|
826
956
|
|
827
|
-
Script fields allow to execute
|
957
|
+
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:
|
828
958
|
|
829
959
|
```ruby
|
830
960
|
UsersIndex.script_fields(
|
@@ -837,7 +967,7 @@ UsersIndex.script_fields(
|
|
837
967
|
}
|
838
968
|
)
|
839
969
|
```
|
840
|
-
`coordinates`
|
970
|
+
Here, `coordinates` is a field with type `geo_point`. There will be a `distance` field for the index's model in the search result.
|
841
971
|
|
842
972
|
### Script scoring
|
843
973
|
|
@@ -849,7 +979,7 @@ UsersIndex.script_score("_score * doc['my_numeric_field'].value")
|
|
849
979
|
|
850
980
|
### Boost Factor
|
851
981
|
|
852
|
-
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 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 for an expert user
|
982
|
+
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:
|
853
983
|
|
854
984
|
```ruby
|
855
985
|
UsersIndex.boost_factor(5, filter: {term: {type: 'Expert'}})
|
@@ -857,7 +987,7 @@ UsersIndex.boost_factor(5, filter: {term: {type: 'Expert'}})
|
|
857
987
|
|
858
988
|
### Objects loading
|
859
989
|
|
860
|
-
It is possible to load source objects from database for every search result:
|
990
|
+
It is possible to load source objects from the database for every search result:
|
861
991
|
|
862
992
|
```ruby
|
863
993
|
scope = UsersIndex.filter(range: {rating: {gte: 100}})
|
@@ -872,7 +1002,7 @@ scope.load(scope: ->{ includes(:country) }) # and more common scope applied to e
|
|
872
1002
|
scope.only(:id).load # it is optimal to request ids only if you are not planning to use type objects
|
873
1003
|
```
|
874
1004
|
|
875
|
-
The `preload` method takes the same options as `load` and ORM/ODM objects will be loaded, but scope will still return array of Chewy wrappers. To access real objects use `_object` wrapper method:
|
1005
|
+
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:
|
876
1006
|
|
877
1007
|
```ruby
|
878
1008
|
UsersIndex.filter(range: {rating: {gte: 100}}).preload(...).query(...).map(&:_object)
|
@@ -882,7 +1012,7 @@ See [loading.rb](lib/chewy/query/loading.rb) for more details.
|
|
882
1012
|
|
883
1013
|
### `ActiveSupport::Notifications` support
|
884
1014
|
|
885
|
-
Chewy has
|
1015
|
+
Chewy has notifying the following events:
|
886
1016
|
|
887
1017
|
#### `search_query.chewy` payload
|
888
1018
|
|
@@ -892,7 +1022,7 @@ Chewy has notifing the following events:
|
|
892
1022
|
#### `import_objects.chewy` payload
|
893
1023
|
|
894
1024
|
* `payload[:type]`: currently imported type
|
895
|
-
* `payload[:import]`: imports
|
1025
|
+
* `payload[:import]`: imports stats, total imported and deleted objects count:
|
896
1026
|
|
897
1027
|
```ruby
|
898
1028
|
{index: 30, delete: 5}
|
@@ -941,25 +1071,24 @@ end
|
|
941
1071
|
|
942
1072
|
### Rake tasks
|
943
1073
|
|
944
|
-
Inside Rails application some index
|
1074
|
+
Inside the Rails application, some index-maintaining rake tasks are defined.
|
945
1075
|
|
946
1076
|
```bash
|
947
|
-
rake chewy:reset # resets all the existing
|
1077
|
+
rake chewy:reset # resets all the existing indices, declared in app/chewy
|
948
1078
|
rake chewy:reset[users] # resets UsersIndex only
|
949
1079
|
|
950
|
-
rake chewy:update # updates all the existing
|
1080
|
+
rake chewy:update # updates all the existing indices, declared in app/chewy
|
951
1081
|
rake chewy:update[users] # updates UsersIndex only
|
952
1082
|
```
|
953
1083
|
|
954
|
-
|
1084
|
+
`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).
|
955
1085
|
|
956
1086
|
|
957
1087
|
### Rspec integration
|
958
1088
|
|
959
|
-
Just add `require 'chewy/rspec'` to your spec_helper.rb and you will get additional features:
|
960
|
-
See [update_index.rb](lib/chewy/rspec/update_index.rb) for more details.
|
1089
|
+
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.
|
961
1090
|
|
962
|
-
If you use `DatabaseCleaner` in your tests with `transaction` (
|
1091
|
+
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:
|
963
1092
|
|
964
1093
|
```ruby
|
965
1094
|
#config/initializers/chewy.rb
|
@@ -969,20 +1098,20 @@ Chewy.use_after_commit_callbacks = !Rails.env.test?
|
|
969
1098
|
## TODO a.k.a coming soon:
|
970
1099
|
|
971
1100
|
* Typecasting support
|
972
|
-
* Advanced (
|
1101
|
+
* Advanced (simplified) query DSL: `UsersIndex.query { email == 'my@gmail.com' }` will produce term query
|
973
1102
|
* update_all support
|
974
1103
|
* Maybe, closer ORM/ODM integration, creating index classes implicitly
|
975
1104
|
|
976
1105
|
## Contributing
|
977
1106
|
|
978
|
-
1. Fork it (
|
1107
|
+
1. Fork it (http://github.com/toptal/chewy/fork)
|
979
1108
|
2. Create your feature branch (`git checkout -b my-new-feature`)
|
980
1109
|
3. Implement your changes, cover it with specs and make sure old specs are passing
|
981
1110
|
4. Commit your changes (`git commit -am 'Add some feature'`)
|
982
1111
|
5. Push to the branch (`git push origin my-new-feature`)
|
983
1112
|
6. Create new Pull Request
|
984
1113
|
|
985
|
-
Use the following Rake tasks to control
|
1114
|
+
Use the following Rake tasks to control the Elasticsearch cluster while developing.
|
986
1115
|
|
987
1116
|
```bash
|
988
1117
|
rake elasticsearch:start # start Elasticsearch cluster on 9250 port for tests
|