chewie 0.2.2 → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +117 -113
- data/lib/chewie/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 87efde82129dae245a02a880e4b843c9a640140ce2eee57aca0c6ed5ab3f1bdb
|
4
|
+
data.tar.gz: 1329723440602fdee2b6c7d1ff11d7907b5f6464f392d807690dfba8d45a101f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 49934eea3792c825ca77cdd38e32472aef70abb28673021fa6dfeedda08338b68e6a4a035843a8a731492b50e5a9d8c63a99ad6e472f29ed4342652e26096009
|
7
|
+
data.tar.gz: b0d75849ad471dd71826643a3fe2b6da041ffbf89fe2f6dd619b8ca551a349e28a58c0b79ee135e8e5bd2741ae450130e255af0895f26eb1274cd530194dc6d8
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -45,13 +45,13 @@ Define a `Chewie` class:
|
|
45
45
|
# app/chewies/school_chewie.rb
|
46
46
|
|
47
47
|
class SchoolChewie
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
48
|
+
extend Chewie
|
49
|
+
|
50
|
+
term :name
|
51
|
+
range :age
|
52
|
+
match :description
|
53
|
+
|
54
|
+
filter_by :governances, with: :terms
|
55
55
|
end
|
56
56
|
```
|
57
57
|
|
@@ -61,11 +61,11 @@ Pass filter parameters to the `#build` method:
|
|
61
61
|
# app/**/*.rb
|
62
62
|
|
63
63
|
params = {
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
64
|
+
query: "Park School"
|
65
|
+
filters: {
|
66
|
+
age: { 'gte': 20, 'lte': 10 },
|
67
|
+
governances: ['Charter', 'Alop']
|
68
|
+
}
|
69
69
|
}
|
70
70
|
|
71
71
|
query = params[:query]
|
@@ -75,7 +75,7 @@ query = SchoolChewie.build(query: query, filters: filters)
|
|
75
75
|
|
76
76
|
puts query
|
77
77
|
# =>
|
78
|
-
#
|
78
|
+
# {
|
79
79
|
# query: {
|
80
80
|
# term: {
|
81
81
|
# name: { value: 'Park School' }
|
@@ -97,7 +97,7 @@ puts query
|
|
97
97
|
# }
|
98
98
|
```
|
99
99
|
|
100
|
-
Chewie expects incoming parameter attributes to match the attributes defined in your Chewie class, in order to pull the correct value and build the query
|
100
|
+
Chewie expects incoming parameter attributes to match the attributes defined in your Chewie class, in order to pull the correct value and build the query.
|
101
101
|
|
102
102
|
```ruby
|
103
103
|
# definition
|
@@ -127,102 +127,106 @@ term :name
|
|
127
127
|
|
128
128
|
## Filtering by Associations
|
129
129
|
|
130
|
-
Depending on how you build your index, some fields might store values from multiple
|
130
|
+
Depending on how you build your index, some fields might store values from multiple tables.
|
131
131
|
|
132
132
|
A simple case is if you'd like to filter records through an association.
|
133
133
|
|
134
134
|
```ruby
|
135
135
|
class School
|
136
|
-
|
137
|
-
|
136
|
+
has_many :school_disciplines
|
137
|
+
has_many :disciplines, through: :school_disciplines
|
138
138
|
end
|
139
139
|
|
140
140
|
class Discipline
|
141
|
-
|
142
|
-
|
141
|
+
has_many :school_disciplines
|
142
|
+
has_many :schools, through: :school_disciplines
|
143
143
|
end
|
144
144
|
|
145
145
|
class SchoolDiscipline
|
146
|
-
|
147
|
-
|
146
|
+
belongs_to :school
|
147
|
+
belongs_to :discipline
|
148
148
|
end
|
149
149
|
```
|
150
150
|
|
151
|
-
We
|
151
|
+
We can imagine a search engine that helps users find schools in their area and allow them to filter schools by various criteria.
|
152
|
+
|
153
|
+
Some schools might offer discipline specific programs, therefore a school will have many disciplines.
|
154
|
+
|
155
|
+
Disciplines is a non-user populated collection that schools can associate with in the application.
|
152
156
|
|
153
|
-
In
|
157
|
+
In the search UI, we might provide a `disciplines` filter and allow users to filter by disciplines via dropdown.
|
154
158
|
|
155
159
|
We provide the search UI with `ids` of disciplines we'd like to filter by.
|
156
160
|
|
157
161
|
```json
|
158
162
|
{
|
159
|
-
|
160
|
-
|
161
|
-
|
163
|
+
filters: {
|
164
|
+
disciplines: [1, 2, 3, 4]
|
165
|
+
}
|
162
166
|
}
|
163
167
|
```
|
164
168
|
|
165
|
-
|
169
|
+
The idex consists of school records, therefore we won't have access to every discipline each school is associated to by default.
|
166
170
|
|
167
|
-
Instead, we need to define custom index attributes for
|
171
|
+
Instead, we need to define custom index attributes for school records to capture those relationships.
|
168
172
|
|
169
173
|
We can do that by defining model methods on `School` that collects associated id values and returns a collection of strings to be indexed.
|
170
174
|
|
171
175
|
```ruby
|
172
176
|
class School
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
177
|
+
def disciplines_index
|
178
|
+
discipline_ids = disciplines.pluck(:id)
|
179
|
+
discipline_ids.map do |discipline_id|
|
180
|
+
"discipline_#{discipline_id}"
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
# Method Elasticsearch can use to populate the index
|
185
|
+
def search_data
|
186
|
+
{
|
187
|
+
name: name,
|
188
|
+
disciplines: disciplines_index
|
189
|
+
}
|
190
|
+
end
|
187
191
|
end
|
188
192
|
```
|
189
193
|
|
190
194
|
When Elasticsearch indexes `School` records, each record will now have knowledge of which disciplines it is associated to.
|
191
195
|
|
192
196
|
```json
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
197
|
+
{
|
198
|
+
name: 'Park School',
|
199
|
+
disciplines: [
|
200
|
+
"discipline_1",
|
201
|
+
"discipline_2",
|
202
|
+
"discipline_3"
|
203
|
+
]
|
204
|
+
}
|
201
205
|
```
|
202
206
|
|
203
207
|
### Format
|
204
|
-
At this point,
|
208
|
+
At this point, the index is ready to return associated `School` records when given a collection of `Discipline` ids.
|
205
209
|
|
206
210
|
The caveat is the stored values of `:disciplines` is in a format that contains both the `School` and `Discipline` id.
|
207
211
|
|
208
|
-
We'll need to do a little extra work at search time to ensure
|
212
|
+
We'll need to do a little extra work at search time to ensure the `id` filter values are transformed into the appropriate string format.
|
209
213
|
|
210
214
|
To address this, `bool` query methods have a `:format` option that takes a lambda and exposes attribute values given.
|
211
215
|
|
212
216
|
```ruby
|
213
217
|
class SchoolChewie
|
214
|
-
|
215
|
-
|
216
|
-
|
218
|
+
disciplines_format = lambda do |id|
|
219
|
+
"discipline_#{id}"
|
220
|
+
end
|
217
221
|
|
218
|
-
|
222
|
+
filter_by :disciplines, with: :terms, format: disciplines_format
|
219
223
|
end
|
220
224
|
|
221
225
|
params = {
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
+
query: '',
|
227
|
+
filters: {
|
228
|
+
disciplines: [1, 4]
|
229
|
+
}
|
226
230
|
}
|
227
231
|
|
228
232
|
result = SchoolChewie.build(query: params[:query], filters: params[:filters])
|
@@ -245,7 +249,7 @@ puts result
|
|
245
249
|
# }
|
246
250
|
```
|
247
251
|
|
248
|
-
Now that
|
252
|
+
Now that the query for `disciplines` matches values stored in the index, Elasticsearch will find `School` records where `disciplines` match to either `"discipline_1"` or `"discipline_4"`; allowing us to find schools by their associated disciplines.
|
249
253
|
|
250
254
|
### Combine
|
251
255
|
|
@@ -255,65 +259,65 @@ Continuing with the previous example, let's say we want to filter schools by dis
|
|
255
259
|
|
256
260
|
`"active"` might be a boolean attribute found on `SchoolDiscipline`.
|
257
261
|
|
258
|
-
We can re-write
|
262
|
+
We can re-write `#discipline_index` to pull the discipline `id` and `active` attributes from `SchoolDiscipline` join records.
|
259
263
|
|
260
264
|
```ruby
|
261
265
|
class School
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
266
|
+
def disciplines_index
|
267
|
+
school_disciplines.map do |school_discipline|
|
268
|
+
discipline_id = school_discipline.id
|
269
|
+
active = school_discipline.active
|
270
|
+
|
271
|
+
"discipline_#{discipline_id}_active_#{active}"
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
# Method Elasticsearch can use to populate the index
|
276
|
+
def search_data
|
277
|
+
{
|
278
|
+
name: name,
|
279
|
+
disciplines: disciplines_index
|
280
|
+
}
|
281
|
+
end
|
278
282
|
end
|
279
283
|
```
|
280
284
|
|
281
|
-
Which changes
|
285
|
+
Which changes the index to:
|
282
286
|
|
283
287
|
```json
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
288
|
+
{
|
289
|
+
name: 'Park School',
|
290
|
+
disciplines: [
|
291
|
+
"discipline_1_active_true",
|
292
|
+
"discipline_2_active_false",
|
293
|
+
"discipline_3_active_false"
|
294
|
+
]
|
295
|
+
}
|
292
296
|
```
|
293
297
|
|
294
|
-
We can now imagine there is a `active` toggle in the search UI, which expands
|
298
|
+
We can now imagine there is a `active` toggle in the search UI, which expands the filter parameters.
|
295
299
|
|
296
300
|
```ruby
|
297
301
|
params = {
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
302
|
+
query: '',
|
303
|
+
filters: {
|
304
|
+
disciplines: [1, 4],
|
305
|
+
active: true
|
306
|
+
}
|
303
307
|
}
|
304
308
|
```
|
305
309
|
|
306
|
-
|
310
|
+
At search time we not only need to format with the `disciplines` collection, but combine those values with the `active` attribute.
|
307
311
|
|
308
|
-
Let's update
|
312
|
+
Let's update `SchoolChewie` to take this new criteria into account.
|
309
313
|
|
310
314
|
```ruby
|
311
315
|
class SchoolChewie
|
312
|
-
|
313
|
-
|
314
|
-
|
316
|
+
disciplines_format = lambda do |id, combine|
|
317
|
+
"discipline_#{id}_active_#{combine.first}"
|
318
|
+
end
|
315
319
|
|
316
|
-
|
320
|
+
filter_by :disciplines, with: :terms, combine: [:active], format: disciplines_format
|
317
321
|
end
|
318
322
|
```
|
319
323
|
|
@@ -325,13 +329,13 @@ The order of the values matches the order defined in the method call.
|
|
325
329
|
combine: [:active, :governances, :age]
|
326
330
|
|
327
331
|
lambda do |id, combine|
|
328
|
-
|
329
|
-
|
330
|
-
|
332
|
+
combine[0] #=> :active value
|
333
|
+
combine[1] #=> :governances value
|
334
|
+
combine[2] #=> :age value
|
331
335
|
end
|
332
336
|
```
|
333
337
|
|
334
|
-
The output
|
338
|
+
The new output:
|
335
339
|
|
336
340
|
```ruby
|
337
341
|
result = SchoolChewie.build(query: params[:query], filters: params[:filters])
|
@@ -358,22 +362,22 @@ puts result
|
|
358
362
|
### [Compound Queries](https://www.elastic.co/guide/en/elasticsearch/reference/current/full-text-queries.html)
|
359
363
|
#### [Bool](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-bool-query.html)
|
360
364
|
|
361
|
-
* filter (#filter_by)
|
362
|
-
* should (#should_include)
|
363
|
-
* must (#must_include)
|
364
|
-
* must_not (#must_not_include)
|
365
|
+
* [filter (#filter_by)](https://www.rubydoc.info/gems/chewie/0.2.2/Chewie/Interface/Bool)
|
366
|
+
* [should (#should_include)](https://www.rubydoc.info/gems/chewie/0.2.2/Chewie/Interface/Bool)
|
367
|
+
* [must (#must_include)](https://www.rubydoc.info/gems/chewie/0.2.2/Chewie/Interface/Bool)
|
368
|
+
* [must_not (#must_not_include)](https://www.rubydoc.info/gems/chewie/0.2.2/Chewie/Interface/Bool)
|
365
369
|
|
366
370
|
### [Term Level Queries](https://www.elastic.co/guide/en/elasticsearch/reference/current/term-level-queries.html)
|
367
371
|
|
368
|
-
* term (#term)
|
369
|
-
* terms (#terms)
|
370
|
-
* range (#range)
|
371
|
-
* fuzzy (#fuzzy)
|
372
|
+
* [term (#term)](https://www.rubydoc.info/gems/chewie/0.2.2/Chewie/Interface/TermLevel)
|
373
|
+
* [terms (#terms)](https://www.rubydoc.info/gems/chewie/0.2.2/Chewie/Interface/TermLevel)
|
374
|
+
* [range (#range)](https://www.rubydoc.info/gems/chewie/0.2.2/Chewie/Interface/TermLevel)
|
375
|
+
* [fuzzy (#fuzzy)](https://www.rubydoc.info/gems/chewie/0.2.2/Chewie/Interface/TermLevel)
|
372
376
|
|
373
377
|
### [Full Text Queries](https://www.elastic.co/guide/en/elasticsearch/reference/current/full-text-queries.html)
|
374
378
|
|
375
|
-
* match (#match)
|
376
|
-
* multi-match (#multimatch)
|
379
|
+
* [match (#match)](https://www.rubydoc.info/gems/chewie/0.2.2/Chewie/Interface/FullText)
|
380
|
+
* [multi-match (#multimatch)](https://www.rubydoc.info/gems/chewie/0.2.2/Chewie/Interface/FullText)
|
377
381
|
|
378
382
|
## Development
|
379
383
|
|
data/lib/chewie/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: chewie
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- mrjonesbot
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-12-
|
11
|
+
date: 2019-12-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|