es-elasticity 0.9.0 → 0.11.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +13 -0
- data/Gemfile +1 -1
- data/README.md +7 -7
- data/lib/elasticity/index_config.rb +2 -2
- data/lib/elasticity/search.rb +2 -1
- data/lib/elasticity/strategies/alias_index.rb +12 -3
- data/lib/elasticity/version.rb +1 -1
- data/spec/functional/persistence_spec.rb +50 -5
- data/spec/functional/segmented_spec.rb +2 -1
- data/spec/units/search_spec.rb +4 -3
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 11dddda9376573d12d8d6c0db18342c7a242199a
|
4
|
+
data.tar.gz: 2613b868ae0ca372149fa84724790ade9bbca2a2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 13a78c3cbe8eb55a911d7b39d1a31e07329e4e3f809fde432ece6a12511db5e40422af47f3508938ec597579aef697a05622dc449670537b45b4ba64ee4b22e3
|
7
|
+
data.tar.gz: bcb01eb45bf67cf5dc2d6c0cfd7bb6ad00fc40167e5068da1e067d6a77f8f7d811b812b7de923fca134eea8ea28510114e9e1e235c9ff61b148a391e30a5f035
|
data/CHANGELOG
CHANGED
@@ -1,3 +1,16 @@
|
|
1
|
+
v0.11.1
|
2
|
+
- support `action.destructive_requires_name` setting by being explict about which indices to delete
|
3
|
+
|
4
|
+
v0.11.0
|
5
|
+
- compatibilty with ES v6
|
6
|
+
- change mappings for 'index' to boolean. "string" type was replaced with "text"
|
7
|
+
- use "successful" from API response ('created' was removed)
|
8
|
+
- stringify keys for :mappings so clients can use symbol keys
|
9
|
+
v0.10.0
|
10
|
+
- update remap to removing fields from the mapping that are not explicitly
|
11
|
+
defined.
|
12
|
+
v0.9.1
|
13
|
+
- fix search enumerator, missing first result set
|
1
14
|
v0.8.3
|
2
15
|
- fix remap method to use the scan api properly.
|
3
16
|
v0.8.2
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -80,7 +80,7 @@ class Search::User < Elasticity::Document
|
|
80
80
|
def self.adults
|
81
81
|
date = Date.today - 21.years
|
82
82
|
|
83
|
-
# This is the query that will be
|
83
|
+
# This is the query that will be submitted to ES, same format ES would
|
84
84
|
# expect, translated to a Ruby hash, note the pagination params.
|
85
85
|
body = {
|
86
86
|
from: 0,
|
@@ -159,7 +159,7 @@ The search object implements `Enumerable`, so it can be treated as a collection:
|
|
159
159
|
```ruby
|
160
160
|
# Get the search object, which is an instance of `Elasticity::DocumentSearchProxy`.
|
161
161
|
# Search is not performed until data is accessed.
|
162
|
-
adults = User.adults
|
162
|
+
adults = Search::User.adults
|
163
163
|
|
164
164
|
# Iterating over the results will trigger the query
|
165
165
|
adults.each do |user|
|
@@ -203,7 +203,7 @@ Using this feature is very easy and very similar to traditional documents. The o
|
|
203
203
|
class Search::User < Elasticity::SegmentedDocument
|
204
204
|
configure do |c|
|
205
205
|
# Defines how the index will be named, the final name
|
206
|
-
# will depend on the
|
206
|
+
# will depend on the strategy being used.
|
207
207
|
c.index_base_name = "users"
|
208
208
|
|
209
209
|
# Defines the document type that this class represents.
|
@@ -227,7 +227,7 @@ class Search::User < Elasticity::SegmentedDocument
|
|
227
227
|
def self.adults
|
228
228
|
date = Date.today - 21.years
|
229
229
|
|
230
|
-
# This is the query that will be
|
230
|
+
# This is the query that will be submitted to ES, same format ES would
|
231
231
|
# expect, translated to a Ruby hash, note the pagination params.
|
232
232
|
body = {
|
233
233
|
from: 0,
|
@@ -283,7 +283,7 @@ Strategies define how index creation and index operation happens on the lower le
|
|
283
283
|
|
284
284
|
The single-index strategy is the most straightforward one. It causes one index to be created and any operation will be performed directly on that index. It's very simple but it has the downside of being a lot harder to update existing mapping since you'll have to drop the index and recreate from scratch.
|
285
285
|
|
286
|
-
The alias-index strategy is a bit more complex but it allows for
|
286
|
+
The alias-index strategy is a bit more complex but it allows for seamless hot remapping. It works by creating an index and two aliases pointing to that index. Any operation is performed on the aliases rather than the index, which allows hot swapping due atomic aliases updates.
|
287
287
|
|
288
288
|
Here is what it looks like:
|
289
289
|
|
@@ -297,7 +297,7 @@ Here is what it looks like:
|
|
297
297
|
|_____________|
|
298
298
|
```
|
299
299
|
|
300
|
-
|
300
|
+
Every time a search operation is performed, it is performed against the main alias; when an update operation is performed, it is performed against the update alias; and, when a delete operation is performed, it is performed against the indexes pointed by both aliases.
|
301
301
|
|
302
302
|
When the mapping needs to change, a hot remapping can be performed by doing the following:
|
303
303
|
|
@@ -397,7 +397,7 @@ Search::User.adults.active_records(User.where(active: true))
|
|
397
397
|
```
|
398
398
|
|
399
399
|
## Upgrading from 0.7.0 to 0.8.0
|
400
|
-
The default
|
400
|
+
The default persistence strategy changed from SingleIndex to AliasIndex in version 0.8.0 Add the following to your Document configuration to maintain the legacy behaviour.
|
401
401
|
|
402
402
|
```ruby
|
403
403
|
c.strategy = Elasticity::Strategies::SingleIndex
|
@@ -6,7 +6,7 @@ module Elasticity
|
|
6
6
|
].freeze
|
7
7
|
VALIDATABLE_ATTRS = [:index_base_name, :document_type, :strategy].freeze
|
8
8
|
|
9
|
-
attr_accessor
|
9
|
+
attr_accessor(*ATTRS)
|
10
10
|
|
11
11
|
def initialize(elasticity_config, defaults = {})
|
12
12
|
defaults.each do |k,v|
|
@@ -30,7 +30,7 @@ module Elasticity
|
|
30
30
|
def definition
|
31
31
|
return @definition if defined?(@definition)
|
32
32
|
@definition = {
|
33
|
-
settings: merge_settings, mappings: { @document_type => @mapping
|
33
|
+
settings: merge_settings, mappings: { @document_type => @mapping.nil? ? {} : @mapping.deep_stringify_keys }
|
34
34
|
}
|
35
35
|
subclasses.each do |doc_type, subclass|
|
36
36
|
@definition[:mappings][doc_type] = subclass.constantize.mapping
|
data/lib/elasticity/search.rb
CHANGED
@@ -164,7 +164,8 @@ module Elasticity
|
|
164
164
|
def enumerator
|
165
165
|
Enumerator.new do |y|
|
166
166
|
response = search
|
167
|
-
|
167
|
+
# Push the first set of results before requesting the second set
|
168
|
+
y << Search::Results.new(response, @search_definition.body, @mapper)
|
168
169
|
loop do
|
169
170
|
response = @client.scroll(scroll_id: response["_scroll_id"], scroll: @scroll, body: { scroll_id: response["_scroll_id"] })
|
170
171
|
break if response["hits"]["hits"].empty?
|
@@ -66,10 +66,17 @@ module Elasticity
|
|
66
66
|
docs = @client.mget(body: { docs: id_docs }, refresh: true)["docs"]
|
67
67
|
break if docs.empty?
|
68
68
|
|
69
|
+
# Modify document hashes to match the mapping definition so that legacy fields aren't added
|
70
|
+
defined_mapping_fields = index_def[:mappings][docs.first["_type"]]["properties"].keys
|
71
|
+
|
69
72
|
# Move only documents that still exists on the old index, into the new index.
|
70
73
|
ops = []
|
71
74
|
docs.each do |doc|
|
72
|
-
|
75
|
+
if doc["found"]
|
76
|
+
legacy_fields = doc["_source"].keys - defined_mapping_fields
|
77
|
+
legacy_fields.each { |field| doc["_source"].delete(field) }
|
78
|
+
ops << { index: { _index: new_index, _type: doc["_type"], _id: doc["_id"], data: doc["_source"] } }
|
79
|
+
end
|
73
80
|
end
|
74
81
|
|
75
82
|
@client.bulk(body: ops)
|
@@ -179,7 +186,9 @@ module Elasticity
|
|
179
186
|
end
|
180
187
|
|
181
188
|
def delete
|
182
|
-
|
189
|
+
main_indexes.each do |index|
|
190
|
+
@client.index_delete(index: index)
|
191
|
+
end
|
183
192
|
end
|
184
193
|
|
185
194
|
def delete_if_defined
|
@@ -195,7 +204,7 @@ module Elasticity
|
|
195
204
|
res = @client.index(index: @update_alias, type: type, id: id, body: attributes)
|
196
205
|
|
197
206
|
if id = res["_id"]
|
198
|
-
[id, res["
|
207
|
+
[id, res["_shards"] && res["_shards"]["successful"].to_i > 0]
|
199
208
|
else
|
200
209
|
raise IndexError.new(@update_alias, "failed to index document. Response: #{res.inspect}")
|
201
210
|
end
|
data/lib/elasticity/version.rb
CHANGED
@@ -16,8 +16,8 @@ RSpec.describe "Persistence", elasticsearch: true do
|
|
16
16
|
c.strategy = Elasticity::Strategies::SingleIndex
|
17
17
|
|
18
18
|
c.mapping = {
|
19
|
-
properties
|
20
|
-
name: { type: "
|
19
|
+
"properties" => {
|
20
|
+
name: { type: "text", index: false },
|
21
21
|
birthdate: { type: "date" },
|
22
22
|
},
|
23
23
|
}
|
@@ -85,7 +85,7 @@ 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
|
-
c.mapping = { properties
|
88
|
+
c.mapping = { "properties" => {
|
89
89
|
name: { type: "string", index: "not_analyzed" },
|
90
90
|
age: { type: "integer" }
|
91
91
|
} }
|
@@ -103,7 +103,7 @@ RSpec.describe "Persistence", elasticsearch: true do
|
|
103
103
|
c.index_base_name = "cats_and_dogs"
|
104
104
|
c.strategy = Elasticity::Strategies::SingleIndex
|
105
105
|
c.document_type = "dog"
|
106
|
-
c.mapping = { properties
|
106
|
+
c.mapping = { "properties" => {
|
107
107
|
name: { type: "string", index: "not_analyzed" },
|
108
108
|
age: { type: "integer" },
|
109
109
|
hungry: { type: "boolean" }
|
@@ -148,6 +148,7 @@ RSpec.describe "Persistence", elasticsearch: true do
|
|
148
148
|
results = Animal.search({})
|
149
149
|
expect(results.total).to eq 1
|
150
150
|
expect(results.map(&:class)).to include(Dog)
|
151
|
+
expect(results.scan_documents.count).to eq(1)
|
151
152
|
end
|
152
153
|
end
|
153
154
|
|
@@ -164,7 +165,7 @@ RSpec.describe "Persistence", elasticsearch: true do
|
|
164
165
|
c.strategy = Elasticity::Strategies::AliasIndex
|
165
166
|
|
166
167
|
c.mapping = {
|
167
|
-
properties
|
168
|
+
"properties" => {
|
168
169
|
id: { type: "integer" },
|
169
170
|
name: { type: "string", index: "not_analyzed" },
|
170
171
|
birthdate: { type: "date" },
|
@@ -242,6 +243,50 @@ RSpec.describe "Persistence", elasticsearch: true do
|
|
242
243
|
expect(results.total).to eq(2010)
|
243
244
|
end
|
244
245
|
|
246
|
+
it "does not copy over fields not defined in the mapping" do
|
247
|
+
john = subject.new(_id: 1, id: 1, name: "John", birthdate: "1985-10-31", sort: ['john'])
|
248
|
+
mari = subject.new(_id: 2, id: 2, name: "Mari", birthdate: "1986-09-24", sort: ['mari'])
|
249
|
+
|
250
|
+
john.update
|
251
|
+
mari.update
|
252
|
+
|
253
|
+
subject.flush_index
|
254
|
+
results = subject.search({})
|
255
|
+
expect(results.first.birthdate).to be
|
256
|
+
|
257
|
+
# no birthdate
|
258
|
+
subject = Class.new(Elasticity::Document) do
|
259
|
+
def self.name
|
260
|
+
"SomeClass"
|
261
|
+
end
|
262
|
+
|
263
|
+
configure do |c|
|
264
|
+
c.index_base_name = "users"
|
265
|
+
c.document_type = "user"
|
266
|
+
c.strategy = Elasticity::Strategies::AliasIndex
|
267
|
+
|
268
|
+
c.mapping = {
|
269
|
+
"properties" => {
|
270
|
+
id: { type: "integer" },
|
271
|
+
name: { type: "string", index: "not_analyzed" },
|
272
|
+
},
|
273
|
+
}
|
274
|
+
end
|
275
|
+
|
276
|
+
attr_accessor :id, :name
|
277
|
+
|
278
|
+
def to_document
|
279
|
+
{ id: id, name: name }
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
subject.remap!
|
284
|
+
subject.flush_index
|
285
|
+
|
286
|
+
results = subject.search({})
|
287
|
+
expect(results.first.respond_to?(:birthdate)).to be false
|
288
|
+
end
|
289
|
+
|
245
290
|
it "recover from remap interrupts" do
|
246
291
|
number_of_docs = 2000
|
247
292
|
docs = number_of_docs.times.map do |i|
|
@@ -10,7 +10,7 @@ RSpec.describe "Segmented indexes", elasticsearch: true do
|
|
10
10
|
c.document_type = "person"
|
11
11
|
c.mapping = {
|
12
12
|
properties: {
|
13
|
-
name: { type: "
|
13
|
+
name: { type: "text" },
|
14
14
|
},
|
15
15
|
}
|
16
16
|
end
|
@@ -42,6 +42,7 @@ RSpec.describe "Segmented indexes", elasticsearch: true do
|
|
42
42
|
ensure_index(seg)
|
43
43
|
|
44
44
|
rodrigo = seg.new(name: "rodrigo")
|
45
|
+
|
45
46
|
id, success = rodrigo.update
|
46
47
|
expect(id).to be_kind_of(String)
|
47
48
|
expect(success).to be true
|
data/spec/units/search_spec.rb
CHANGED
@@ -49,12 +49,13 @@ RSpec.describe "Search" do
|
|
49
49
|
end
|
50
50
|
|
51
51
|
let :scan_response do
|
52
|
-
{ "_scroll_id" => "abc123", "hits" => { "total" => 2
|
52
|
+
{ "_scroll_id" => "abc123", "hits" => { "total" => 2, "hits" => [
|
53
|
+
{ "_id" => 1, "_source" => { "name" => "foo" } }
|
54
|
+
]}}
|
53
55
|
end
|
54
56
|
|
55
57
|
let :scroll_response do
|
56
|
-
{ "_scroll_id" => "abc456", "hits" => { "total" =>
|
57
|
-
{ "_id" => 1, "_source" => { "name" => "foo" } },
|
58
|
+
{ "_scroll_id" => "abc456", "hits" => { "total" => 1, "hits" => [
|
58
59
|
{ "_id" => 2, "_source" => { "name" => "bar" } },
|
59
60
|
]}}
|
60
61
|
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.
|
4
|
+
version: 0.11.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rodrigo Kochenburger
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-05-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -260,7 +260,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
260
260
|
version: '0'
|
261
261
|
requirements: []
|
262
262
|
rubyforge_project:
|
263
|
-
rubygems_version: 2.6.
|
263
|
+
rubygems_version: 2.6.14
|
264
264
|
signing_key:
|
265
265
|
specification_version: 4
|
266
266
|
summary: ActiveModel-based library for working with Elasticsearch
|