es-elasticity 0.11.1 → 0.11.5
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/CHANGELOG +11 -0
- data/README.md +21 -1
- data/lib/elasticity/base_document.rb +1 -1
- data/lib/elasticity/index_mapper.rb +22 -14
- data/lib/elasticity/search.rb +8 -5
- data/lib/elasticity/strategies/alias_index.rb +25 -2
- data/lib/elasticity/version.rb +1 -1
- data/spec/functional/persistence_spec.rb +98 -4
- data/spec/functional/search_spec.rb +117 -0
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b90fa843196b6ec0a4ed99f4605d089f1127696a
|
4
|
+
data.tar.gz: 16e810b1114f1829e21c8e655f2fd7ad40fa1022
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9d54bd8d914de323f3ce7d430e7477eda5b74d4b1dbd3bb9127a2a5b460ec7facbbef5fcbc5e00fe2f9f3df674834cca6641724191acb5c2b81922874c6d32a6
|
7
|
+
data.tar.gz: cf91125f554221f3ea89364fc8aab76395cfa9f0376fd03369bcfb02bf6235cd7b35b668ea952d7669123883c3c93c83e20cdb8024087b887fe9d95f481865e7
|
data/CHANGELOG
CHANGED
@@ -1,3 +1,14 @@
|
|
1
|
+
v0.11.5
|
2
|
+
- Give the option of retrying the deletion for certain exceptions during remap
|
3
|
+
v0.11.4
|
4
|
+
- Fully clean up if error occurs during remap (assign all aliases back to original index)
|
5
|
+
v0.11.3
|
6
|
+
- Adds support for preserving the order or normalized names of `highlight` through `highlighted_attrs`
|
7
|
+
|
8
|
+
v0.11.2
|
9
|
+
- Adds support for passing arguments to Search definition through `search(query, search_args)` in index searching and msearch
|
10
|
+
- adds _explanation to hold value of returned explanations in the base document
|
11
|
+
|
1
12
|
v0.11.1
|
2
13
|
- support `action.destructive_requires_name` setting by being explict about which indices to delete
|
3
14
|
|
data/README.md
CHANGED
@@ -15,7 +15,7 @@ Elasticity maps those documents into objects, providing a rich object representa
|
|
15
15
|
Add this line to your application's Gemfile:
|
16
16
|
|
17
17
|
```ruby
|
18
|
-
gem 'es-elasticity', require "elasticity"
|
18
|
+
gem 'es-elasticity', require: "elasticity"
|
19
19
|
```
|
20
20
|
|
21
21
|
And then execute:
|
@@ -191,6 +191,26 @@ cursor.each { |doc| ... }
|
|
191
191
|
adults = adults.active_records(User)
|
192
192
|
```
|
193
193
|
|
194
|
+
#### Search Args
|
195
|
+
|
196
|
+
##### explain: true
|
197
|
+
For `search` definitions we support passing `{ explain: true }` to the search as a second argument in order to surface the reason a search result was returned.
|
198
|
+
|
199
|
+
```ruby
|
200
|
+
# example in single search
|
201
|
+
search_results_with_explanation = SearchDoc::A.search(query_body, { explain: true }).search_results
|
202
|
+
|
203
|
+
# In multisearch
|
204
|
+
search_a = SearchDoc::A.search(query_body, { explain: true })
|
205
|
+
search_b = SearchDoc::B.search(query_body, { explain: true })
|
206
|
+
search_c = SearchDoc::C.search(query_body, { explain: true })
|
207
|
+
|
208
|
+
multi = Elasticity::MultiSearch.new do |m|
|
209
|
+
m.add(:a, search_a, documents: ::SearchDoc::A)
|
210
|
+
m.add(:b, search_b, documents: ::SearchDoc::B)
|
211
|
+
m.add(:c, search_c, documents: ::SearchDoc::C)
|
212
|
+
end
|
213
|
+
```
|
194
214
|
For more information about the `active_records` method, read [ActiveRecord integration](#activerecord-integration).
|
195
215
|
|
196
216
|
### Segmented Documents
|
@@ -12,7 +12,7 @@ module Elasticity
|
|
12
12
|
end
|
13
13
|
|
14
14
|
# Define common attributes for all documents
|
15
|
-
attr_accessor :_id, :highlighted, :_score, :sort
|
15
|
+
attr_accessor :_id, :highlighted, :_score, :sort, :_explanation, :highlighted_attrs
|
16
16
|
|
17
17
|
def attributes=(attributes)
|
18
18
|
attributes.each do |attr, value|
|
@@ -65,8 +65,9 @@ module Elasticity
|
|
65
65
|
end
|
66
66
|
|
67
67
|
# Remap
|
68
|
-
|
69
|
-
|
68
|
+
# retry_delay & max_delay are in seconds
|
69
|
+
def remap!(retry_delete_on_recoverable_errors: true, retry_delay: 30, max_delay: 600)
|
70
|
+
@strategy.remap(@index_config.definition, retry_delete_on_recoverable_errors: retry_delete_on_recoverable_errors, retry_delay: retry_delay, max_delay: max_delay)
|
70
71
|
end
|
71
72
|
|
72
73
|
# Flushes the index, forcing any writes
|
@@ -82,8 +83,10 @@ module Elasticity
|
|
82
83
|
# Searches the index using the parameters provided in the body hash, following the same
|
83
84
|
# structure Elasticsearch expects.
|
84
85
|
# Returns a DocumentSearch object.
|
85
|
-
|
86
|
-
|
86
|
+
# search_args allows for
|
87
|
+
# explain: boolean to specify we should request _explanation of the query
|
88
|
+
def search(body, search_args = {})
|
89
|
+
search_obj = Search.build(@index_config.client, @strategy.search_index, document_types, body, search_args)
|
87
90
|
Search::DocumentProxy.new(search_obj, self.method(:map_hit))
|
88
91
|
end
|
89
92
|
|
@@ -141,23 +144,28 @@ module Elasticity
|
|
141
144
|
attrs.merge!(sort: hit["sort"])
|
142
145
|
attrs.merge!(hit["_source"]) if hit["_source"]
|
143
146
|
|
144
|
-
|
145
|
-
highlighted_attrs = attrs.dup
|
146
|
-
attrs_set = Set.new
|
147
|
+
highlighted = nil
|
147
148
|
|
148
|
-
|
149
|
+
if hit["highlight"]
|
150
|
+
highlighted_attrs = hit["highlight"].each_with_object({}) do |(name, v), attrs|
|
149
151
|
name = name.gsub(/\..*\z/, '')
|
150
|
-
|
151
|
-
|
152
|
-
attrs_set << name
|
152
|
+
|
153
|
+
attrs[name] ||= v
|
153
154
|
end
|
154
155
|
|
155
|
-
highlighted = @document_klass.new(highlighted_attrs)
|
156
|
+
highlighted = @document_klass.new(attrs.merge(highlighted_attrs))
|
156
157
|
end
|
158
|
+
|
159
|
+
injected_attrs = attrs.merge({
|
160
|
+
highlighted: highlighted,
|
161
|
+
highlighted_attrs: highlighted_attrs.try(:keys),
|
162
|
+
_explanation: hit["_explanation"]
|
163
|
+
})
|
164
|
+
|
157
165
|
if @document_klass.config.subclasses.present?
|
158
|
-
@document_klass.config.subclasses[hit["_type"].to_sym].constantize.new(
|
166
|
+
@document_klass.config.subclasses[hit["_type"].to_sym].constantize.new(injected_attrs)
|
159
167
|
else
|
160
|
-
@document_klass.new(
|
168
|
+
@document_klass.new(injected_attrs)
|
161
169
|
end
|
162
170
|
end
|
163
171
|
end
|
data/lib/elasticity/search.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module Elasticity
|
2
2
|
module Search
|
3
|
-
def self.build(client, index_name, document_types, body)
|
4
|
-
search_def = Search::Definition.new(index_name, document_types, body)
|
3
|
+
def self.build(client, index_name, document_types, body, search_args = {})
|
4
|
+
search_def = Search::Definition.new(index_name, document_types, body, search_args)
|
5
5
|
Search::Facade.new(client, search_def)
|
6
6
|
end
|
7
7
|
|
@@ -10,10 +10,11 @@ module Elasticity
|
|
10
10
|
class Definition
|
11
11
|
attr_accessor :index_name, :document_types, :body
|
12
12
|
|
13
|
-
def initialize(index_name, document_types, body)
|
13
|
+
def initialize(index_name, document_types, body, search_args = {})
|
14
14
|
@index_name = index_name
|
15
15
|
@document_types = document_types
|
16
16
|
@body = body.deep_symbolize_keys!
|
17
|
+
@search_args = search_args
|
17
18
|
end
|
18
19
|
|
19
20
|
def update(body_changes)
|
@@ -28,11 +29,13 @@ module Elasticity
|
|
28
29
|
end
|
29
30
|
|
30
31
|
def to_search_args
|
31
|
-
{ index: @index_name, type: @document_types, body: @body }
|
32
|
+
@search_args.merge({ index: @index_name, type: @document_types, body: @body })
|
32
33
|
end
|
33
34
|
|
34
35
|
def to_msearch_args
|
35
|
-
|
36
|
+
search_body = @search_args.merge(@body)
|
37
|
+
|
38
|
+
{ index: @index_name, type: @document_types, search: search_body }
|
36
39
|
end
|
37
40
|
end
|
38
41
|
|
@@ -4,6 +4,11 @@ module Elasticity
|
|
4
4
|
# runtime changes by simply atomically updating the aliases. For example, look at the remap method
|
5
5
|
# implementation.
|
6
6
|
class AliasIndex
|
7
|
+
SNAPSHOT_ERROR_SNIPPET = "Cannot delete indices that are being snapshotted".freeze
|
8
|
+
RETRYABLE_ERROR_SNIPPETS = [
|
9
|
+
SNAPSHOT_ERROR_SNIPPET
|
10
|
+
].freeze
|
11
|
+
|
7
12
|
STATUSES = [:missing, :ok]
|
8
13
|
|
9
14
|
def initialize(client, index_base_name, document_type)
|
@@ -29,7 +34,7 @@ module Elasticity
|
|
29
34
|
#
|
30
35
|
# It does a little bit more to ensure consistency and to handle race-conditions. For more details
|
31
36
|
# look at the implementation.
|
32
|
-
def remap(index_def)
|
37
|
+
def remap(index_def, retry_delete_on_recoverable_errors: false, retry_delay: 0, max_delay: 0)
|
33
38
|
main_indexes = self.main_indexes
|
34
39
|
update_indexes = self.update_indexes
|
35
40
|
|
@@ -99,11 +104,23 @@ module Elasticity
|
|
99
104
|
{ remove: { index: original_index, alias: @main_alias } },
|
100
105
|
]
|
101
106
|
})
|
102
|
-
@client.index_delete(index: original_index)
|
103
107
|
|
108
|
+
waiting_duration = 0
|
109
|
+
begin
|
110
|
+
@client.index_delete(index: original_index)
|
111
|
+
rescue Elasticsearch::Transport::Transport::ServerError => e
|
112
|
+
if retryable_error?(e) && retry_delete_on_recoverable_errors && waiting_duration < max_delay
|
113
|
+
waiting_duration += retry_delay
|
114
|
+
sleep(retry_delay)
|
115
|
+
retry
|
116
|
+
else
|
117
|
+
raise e
|
118
|
+
end
|
119
|
+
end
|
104
120
|
rescue
|
105
121
|
@client.index_update_aliases(body: {
|
106
122
|
actions: [
|
123
|
+
{ add: { index: original_index, alias: @main_alias } },
|
107
124
|
{ add: { index: original_index, alias: @update_alias } },
|
108
125
|
{ remove: { index: new_index, alias: @update_alias } },
|
109
126
|
]
|
@@ -268,6 +285,12 @@ module Elasticity
|
|
268
285
|
@client.index_create(index: index_name, body: index_def)
|
269
286
|
index_name
|
270
287
|
end
|
288
|
+
|
289
|
+
def retryable_error?(e)
|
290
|
+
RETRYABLE_ERROR_SNIPPETS.any? do |s|
|
291
|
+
e.message.match(s)
|
292
|
+
end
|
293
|
+
end
|
271
294
|
end
|
272
295
|
end
|
273
296
|
end
|
data/lib/elasticity/version.rb
CHANGED
@@ -85,8 +85,9 @@ RSpec.describe "Persistence", elasticsearch: true do
|
|
85
85
|
c.index_base_name = "cats_and_dogs"
|
86
86
|
c.strategy = Elasticity::Strategies::SingleIndex
|
87
87
|
c.document_type = "cat"
|
88
|
+
|
88
89
|
c.mapping = { "properties" => {
|
89
|
-
name: { type: "
|
90
|
+
name: { type: "text", index: true },
|
90
91
|
age: { type: "integer" }
|
91
92
|
} }
|
92
93
|
end
|
@@ -104,7 +105,7 @@ RSpec.describe "Persistence", elasticsearch: true do
|
|
104
105
|
c.strategy = Elasticity::Strategies::SingleIndex
|
105
106
|
c.document_type = "dog"
|
106
107
|
c.mapping = { "properties" => {
|
107
|
-
name: { type: "
|
108
|
+
name: { type: "text", index: true },
|
108
109
|
age: { type: "integer" },
|
109
110
|
hungry: { type: "boolean" }
|
110
111
|
} }
|
@@ -167,7 +168,7 @@ RSpec.describe "Persistence", elasticsearch: true do
|
|
167
168
|
c.mapping = {
|
168
169
|
"properties" => {
|
169
170
|
id: { type: "integer" },
|
170
|
-
name: { type: "
|
171
|
+
name: { type: "text", index: true },
|
171
172
|
birthdate: { type: "date" },
|
172
173
|
},
|
173
174
|
}
|
@@ -268,7 +269,7 @@ RSpec.describe "Persistence", elasticsearch: true do
|
|
268
269
|
c.mapping = {
|
269
270
|
"properties" => {
|
270
271
|
id: { type: "integer" },
|
271
|
-
name: { type: "
|
272
|
+
name: { type: "text", index: true },
|
272
273
|
},
|
273
274
|
}
|
274
275
|
end
|
@@ -313,6 +314,88 @@ RSpec.describe "Persistence", elasticsearch: true do
|
|
313
314
|
expect(results.total).to eq(2010)
|
314
315
|
end
|
315
316
|
|
317
|
+
it "fully cleans up if error occurs deleting the old index during remap" do
|
318
|
+
expected_aliases = %w[elasticity_test_users elasticity_test_users_update]
|
319
|
+
original_aliases = all_aliases(subject)
|
320
|
+
expect(original_aliases).to match_array(expected_aliases)
|
321
|
+
number_of_docs = 20
|
322
|
+
number_of_docs.times.map do |i|
|
323
|
+
subject.new(id: i, name: "User #{i}", birthdate: random_birthdate).tap(&:update)
|
324
|
+
end
|
325
|
+
|
326
|
+
allow_any_instance_of(Elasticity::InstrumentedClient).to receive(:index_delete).and_raise("KAPOW")
|
327
|
+
expect do
|
328
|
+
subject.remap!
|
329
|
+
end.to raise_error("KAPOW")
|
330
|
+
cleaned_up_aliases = all_aliases(subject)
|
331
|
+
expect(cleaned_up_aliases).to match_array(expected_aliases)
|
332
|
+
allow_any_instance_of(Elasticity::InstrumentedClient).to receive(:index_delete).and_call_original
|
333
|
+
end
|
334
|
+
|
335
|
+
context "recovering from remap errors" do
|
336
|
+
let(:recoverable_message) do
|
337
|
+
'[400] {"error":{"root_cause":[{"type":"remote_transport_exception","reason":"[your_cluster][cluster_id][indices:admin/delete]"}],"type":"illegal_argument_exception","reason":"Cannot delete indices that are being snapshotted: [[full_index_name_and_id]]. Try again after snapshot finishes or cancel the currently running snapshot."},"status":400}'
|
338
|
+
end
|
339
|
+
after do
|
340
|
+
allow_any_instance_of(Elasticity::InstrumentedClient).to receive(:index_delete).and_call_original
|
341
|
+
end
|
342
|
+
|
343
|
+
it "waits for recoverable errors before deleting old index during remap" do
|
344
|
+
original_index_name = subject.config.client.index_get_alias(index: "#{subject.ref_index_name}-*", name: subject.ref_index_name).keys.first
|
345
|
+
|
346
|
+
call_count = 0
|
347
|
+
allow_any_instance_of(Elasticity::InstrumentedClient).to receive(:index_delete) do
|
348
|
+
call_count +=1
|
349
|
+
if call_count < 3
|
350
|
+
raise Elasticsearch::Transport::Transport::Errors::BadRequest.new(recoverable_message)
|
351
|
+
else
|
352
|
+
[]
|
353
|
+
end
|
354
|
+
end
|
355
|
+
build_some_docs(subject)
|
356
|
+
|
357
|
+
subject.remap!(retry_delete_on_recoverable_errors: true, retry_delay: 0.5, max_delay: 1)
|
358
|
+
subject.flush_index
|
359
|
+
results = subject.search({})
|
360
|
+
expect(results.total).to eq(20)
|
361
|
+
remapped_index_name = subject.config.client.index_get_alias(index: "#{subject.ref_index_name}-*", name: subject.ref_index_name).keys.first
|
362
|
+
expect(remapped_index_name).to_not eq(original_index_name)
|
363
|
+
end
|
364
|
+
|
365
|
+
it "will only retry for a set amount of time" do
|
366
|
+
allow_any_instance_of(Elasticity::InstrumentedClient).to receive(:index_delete).and_raise(
|
367
|
+
Elasticsearch::Transport::Transport::Errors::BadRequest.new(recoverable_message)
|
368
|
+
)
|
369
|
+
build_some_docs(subject)
|
370
|
+
expect {
|
371
|
+
subject.remap!(retry_delete_on_recoverable_errors: true, retry_delay: 0.5, max_delay: 1)
|
372
|
+
}.to raise_error(Elasticsearch::Transport::Transport::ServerError)
|
373
|
+
end
|
374
|
+
|
375
|
+
it "will not only retry if the arguments say not to" do
|
376
|
+
original_index_name = subject.config.client.index_get_alias(index: "#{subject.ref_index_name}-*", name: subject.ref_index_name).keys.first
|
377
|
+
allow_any_instance_of(Elasticity::InstrumentedClient).to receive(:index_delete).with(any_args).and_call_original
|
378
|
+
allow_any_instance_of(Elasticity::InstrumentedClient).to receive(:index_delete).with(index: original_index_name).and_raise(
|
379
|
+
Elasticsearch::Transport::Transport::Errors::BadRequest.new(recoverable_message)
|
380
|
+
)
|
381
|
+
build_some_docs(subject)
|
382
|
+
expect {
|
383
|
+
subject.remap!(retry_delete_on_recoverable_errors: false)
|
384
|
+
}.to raise_error(Elasticsearch::Transport::Transport::ServerError)
|
385
|
+
end
|
386
|
+
|
387
|
+
it "will not retry for 'non-recoverable' errors" do
|
388
|
+
exception_message = '[404] {"error":"alias [some_index_name] missing","status":404}'
|
389
|
+
allow_any_instance_of(Elasticity::InstrumentedClient).to receive(:index_delete).and_raise(
|
390
|
+
Elasticsearch::Transport::Transport::Errors::BadRequest.new(exception_message)
|
391
|
+
)
|
392
|
+
build_some_docs(subject)
|
393
|
+
expect {
|
394
|
+
subject.remap!(retry_delete_on_recoverable_errors: true, retry_delay: 0.5, max_delay: 1)
|
395
|
+
}.to raise_error(Elasticsearch::Transport::Transport::ServerError)
|
396
|
+
end
|
397
|
+
end
|
398
|
+
|
316
399
|
it "bulk indexes, updates and delete" do
|
317
400
|
docs = 2000.times.map do |i|
|
318
401
|
subject.new(_id: i, id: i, name: "User #{i}", birthdate: random_birthdate).tap(&:update)
|
@@ -342,4 +425,15 @@ RSpec.describe "Persistence", elasticsearch: true do
|
|
342
425
|
expect(results.total).to eq 0
|
343
426
|
end
|
344
427
|
end
|
428
|
+
|
429
|
+
def all_aliases(subj)
|
430
|
+
base_name = subj.ref_index_name
|
431
|
+
subj.config.client.index_get_alias(index: "#{base_name}-*", name: "#{base_name}*").values.first["aliases"].keys
|
432
|
+
end
|
433
|
+
|
434
|
+
def build_some_docs(subj, doc_count = 20)
|
435
|
+
doc_count.times.map do |i|
|
436
|
+
subj.new(id: i, name: "User #{i}", birthdate: random_birthdate).tap(&:update)
|
437
|
+
end
|
438
|
+
end
|
345
439
|
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
RSpec.describe "Search", elasticsearch: true do
|
2
|
+
class CatDoc < Elasticity::Document
|
3
|
+
configure do |c|
|
4
|
+
c.strategy = Elasticity::Strategies::SingleIndex
|
5
|
+
c.document_type = "cat"
|
6
|
+
c.mapping = { "properties" => {
|
7
|
+
name: { type: "text" },
|
8
|
+
description: { type: "text" },
|
9
|
+
age: { type: "integer" }
|
10
|
+
} }
|
11
|
+
end
|
12
|
+
|
13
|
+
attr_accessor :name, :age, :description
|
14
|
+
|
15
|
+
def to_document
|
16
|
+
{ name: name, age: age, description: description }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class DogDoc < Elasticity::Document
|
21
|
+
configure do |c|
|
22
|
+
c.strategy = Elasticity::Strategies::SingleIndex
|
23
|
+
c.document_type = "dog"
|
24
|
+
c.mapping = { "properties" => {
|
25
|
+
name: { type: "keyword" },
|
26
|
+
description: { type: "text" },
|
27
|
+
age: { type: "integer" },
|
28
|
+
hungry: { type: "boolean" }
|
29
|
+
} }
|
30
|
+
end
|
31
|
+
attr_accessor :name, :age, :description, :hungry
|
32
|
+
|
33
|
+
def to_document
|
34
|
+
{ name: name, age: age, description: description, hungry: hungry }
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "search_args" do
|
39
|
+
before do
|
40
|
+
CatDoc.recreate_index
|
41
|
+
DogDoc.recreate_index
|
42
|
+
|
43
|
+
@elastic_search_client.cluster.health wait_for_status: 'yellow'
|
44
|
+
|
45
|
+
cat = CatDoc.new(name: "felix the cat", age: 10, description: "I am an old cat")
|
46
|
+
dog = DogDoc.new(name: "fido", age: 4, hungry: true, description: "I am a hungry dog")
|
47
|
+
|
48
|
+
cat.update
|
49
|
+
dog.update
|
50
|
+
|
51
|
+
CatDoc.flush_index
|
52
|
+
end
|
53
|
+
|
54
|
+
describe "explain: true" do
|
55
|
+
def get_explanations(results)
|
56
|
+
results.map(&:_explanation)
|
57
|
+
end
|
58
|
+
|
59
|
+
it "supports on single index search results" do
|
60
|
+
results = CatDoc.search({}, { explain: true }).search_results
|
61
|
+
|
62
|
+
expect(get_explanations(results)).to all( be_truthy )
|
63
|
+
end
|
64
|
+
|
65
|
+
it "supports for multisearch" do
|
66
|
+
cat = CatDoc.search({}, { explain: true })
|
67
|
+
dog = DogDoc.search({})
|
68
|
+
|
69
|
+
subject = Elasticity::MultiSearch.new do |m|
|
70
|
+
m.add(:cats, cat, documents: CatDoc)
|
71
|
+
m.add(:dogs, dog, documents: DogDoc)
|
72
|
+
end
|
73
|
+
|
74
|
+
expect(get_explanations(subject[:cats])).to all( be_truthy )
|
75
|
+
expect(get_explanations(subject[:dogs])).to all( be_nil )
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe "highlight" do
|
80
|
+
it "is nil when the highlight does not return" do
|
81
|
+
results = CatDoc.search({}).search_results
|
82
|
+
|
83
|
+
expect(results.first.highlighted_attrs).to be_nil
|
84
|
+
expect(results.first.highlighted).to be_nil
|
85
|
+
end
|
86
|
+
|
87
|
+
describe "when specifying highlight" do
|
88
|
+
let(:cat_search_result) {
|
89
|
+
highlight_search = {
|
90
|
+
query: {
|
91
|
+
multi_match: {
|
92
|
+
query: "cat",
|
93
|
+
fields: ["name^1000", "description"]
|
94
|
+
}
|
95
|
+
},
|
96
|
+
highlight: {
|
97
|
+
fields: {
|
98
|
+
"*": {}
|
99
|
+
}
|
100
|
+
}
|
101
|
+
}
|
102
|
+
|
103
|
+
CatDoc.search(highlight_search).search_results.first
|
104
|
+
}
|
105
|
+
|
106
|
+
it "highlighted_attrs returns the highlighted" do
|
107
|
+
expect(cat_search_result.highlighted_attrs).to eq(["name", "description"])
|
108
|
+
end
|
109
|
+
|
110
|
+
it "highlighted returns a new object with the name transformed" do
|
111
|
+
expect(cat_search_result.highlighted.name.first).to include("felix")
|
112
|
+
expect(cat_search_result.highlighted.description.first).to include("old")
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: es-elasticity
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.11.
|
4
|
+
version: 0.11.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rodrigo Kochenburger
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-08-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -231,6 +231,7 @@ files:
|
|
231
231
|
- lib/elasticity/strategies/single_index.rb
|
232
232
|
- lib/elasticity/version.rb
|
233
233
|
- spec/functional/persistence_spec.rb
|
234
|
+
- spec/functional/search_spec.rb
|
234
235
|
- spec/functional/segmented_spec.rb
|
235
236
|
- spec/rspec_config.rb
|
236
237
|
- spec/units/document_spec.rb
|
@@ -260,12 +261,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
260
261
|
version: '0'
|
261
262
|
requirements: []
|
262
263
|
rubyforge_project:
|
263
|
-
rubygems_version: 2.6.
|
264
|
+
rubygems_version: 2.6.13
|
264
265
|
signing_key:
|
265
266
|
specification_version: 4
|
266
267
|
summary: ActiveModel-based library for working with Elasticsearch
|
267
268
|
test_files:
|
268
269
|
- spec/functional/persistence_spec.rb
|
270
|
+
- spec/functional/search_spec.rb
|
269
271
|
- spec/functional/segmented_spec.rb
|
270
272
|
- spec/rspec_config.rb
|
271
273
|
- spec/units/document_spec.rb
|