elastomer-client 2.3.0 → 3.0.0
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/.gitignore +2 -0
- data/.travis.yml +0 -4
- data/CHANGELOG.md +8 -0
- data/docker/docker-compose.cibuild.yml +8 -0
- data/docker/docker-compose.es24.yml +34 -0
- data/docker/docker-compose.es56.yml +37 -0
- data/docker/elasticsearch.yml +15 -0
- data/docs/index.md +2 -2
- data/docs/notifications.md +1 -1
- data/elastomer-client.gemspec +2 -0
- data/lib/elastomer/client.rb +86 -33
- data/lib/elastomer/client/app_delete_by_query.rb +158 -0
- data/lib/elastomer/client/delete_by_query.rb +8 -115
- data/lib/elastomer/client/docs.rb +63 -13
- data/lib/elastomer/client/errors.rb +10 -2
- data/lib/elastomer/client/index.rb +40 -12
- data/lib/elastomer/client/multi_percolate.rb +2 -2
- data/lib/elastomer/client/native_delete_by_query.rb +60 -0
- data/lib/elastomer/client/percolator.rb +6 -3
- data/lib/elastomer/client/scroller.rb +22 -7
- data/lib/elastomer/client/tasks.rb +188 -0
- data/lib/elastomer/client/warmer.rb +6 -0
- data/lib/elastomer/notifications.rb +1 -0
- data/lib/elastomer/version.rb +1 -1
- data/lib/elastomer/version_support.rb +177 -0
- data/script/cibuild +77 -6
- data/script/cibuild-elastomer-client +1 -0
- data/script/cibuild-elastomer-client-es24 +8 -0
- data/script/cibuild-elastomer-client-es56 +8 -0
- data/script/poll-for-es +20 -0
- data/test/client/{delete_by_query_test.rb → app_delete_by_query_test.rb} +7 -7
- data/test/client/bulk_test.rb +9 -13
- data/test/client/cluster_test.rb +2 -2
- data/test/client/docs_test.rb +133 -49
- data/test/client/errors_test.rb +21 -1
- data/test/client/es_5_x_warmer_test.rb +13 -0
- data/test/client/index_test.rb +104 -39
- data/test/client/multi_percolate_test.rb +13 -6
- data/test/client/multi_search_test.rb +5 -5
- data/test/client/native_delete_by_query_test.rb +123 -0
- data/test/client/nodes_test.rb +1 -1
- data/test/client/percolator_test.rb +10 -2
- data/test/client/repository_test.rb +1 -1
- data/test/client/scroller_test.rb +16 -6
- data/test/client/snapshot_test.rb +1 -1
- data/test/client/stubbed_client_test.rb +1 -1
- data/test/client/tasks_test.rb +139 -0
- data/test/client/template_test.rb +1 -1
- data/test/client/warmer_test.rb +8 -4
- data/test/client_test.rb +99 -0
- data/test/core_ext/time_test.rb +1 -1
- data/test/notifications_test.rb +4 -0
- data/test/test_helper.rb +129 -21
- data/test/version_support_test.rb +119 -0
- metadata +59 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7db106056a2ea4d14012e82621bc4c4073c85c15
|
4
|
+
data.tar.gz: ed047e4e19b8f45e7c553998cb0935ea59c1a94e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cb92e602580ce508195626093783510df3320ba20416cac7c879fcf80839ce87fbb64dd0af7c8f37b0a2775cf9f0c3d603a692251b8ab9c7c87bcfe867b955a4
|
7
|
+
data.tar.gz: 423da9494641de0a33a90dc26fdae67564469291a1120202015a5f9daecab22da06bbbf9c1e351a41a825b031563e90066ba9585b483d5c257ad3044c64ba449
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
@@ -6,10 +6,6 @@ env:
|
|
6
6
|
- ES_VERSION=2.3.5 ES_DOWNLOAD_URL=https://download.elastic.co/elasticsearch/release/org/elasticsearch/distribution/tar/elasticsearch/${ES_VERSION}/elasticsearch-${ES_VERSION}.tar.gz
|
7
7
|
- ES_VERSION=5.6.4 ES_DOWNLOAD_URL=https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-${ES_VERSION}.tar.gz
|
8
8
|
|
9
|
-
matrix:
|
10
|
-
allow_failures:
|
11
|
-
- env: ES_VERSION=5.6.4 ES_DOWNLOAD_URL=https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-${ES_VERSION}.tar.gz
|
12
|
-
|
13
9
|
# Configure a specific version of Elasticsearch
|
14
10
|
# See: https://docs.travis-ci.com/user/database-setup/#Installing-ElasticSearch-on-trusty-container-based-infrastructure
|
15
11
|
install:
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
## 3.0.0 (2017-12-15)
|
2
|
+
- Fixed swapped args in {Client,Index}#multi\_percolate count calls using block API
|
3
|
+
- Support for Elasticsearch 5.x
|
4
|
+
- Uses Elasticsearch's built-in `_delete_by_query` when supported
|
5
|
+
- GET and HEAD requests are retried when possible
|
6
|
+
- Add support for `_tasks` API
|
7
|
+
- Replace `scan` queries with `scroll` sorted by `doc_id`
|
8
|
+
|
1
9
|
## 2.3.0 (2017-11-29)
|
2
10
|
- Remove Elasticsearch 1.x and earlier code paths
|
3
11
|
- Fix CI and configure an Elasticsearch 5.6 build
|
@@ -0,0 +1,34 @@
|
|
1
|
+
version: "2.1"
|
2
|
+
|
3
|
+
services:
|
4
|
+
elasticsearch2.4:
|
5
|
+
image: elasticsearch:2.4.6
|
6
|
+
container_name: es2.4
|
7
|
+
environment:
|
8
|
+
- cluster.name=elastomer2.4
|
9
|
+
- bootstrap.memory_lock=true
|
10
|
+
- discovery.type=single-node
|
11
|
+
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
|
12
|
+
ulimits:
|
13
|
+
memlock:
|
14
|
+
soft: -1
|
15
|
+
hard: -1
|
16
|
+
nofile:
|
17
|
+
soft: 65536
|
18
|
+
hard: 65536
|
19
|
+
mem_limit: 1g
|
20
|
+
cap_add:
|
21
|
+
- IPC_LOCK
|
22
|
+
volumes:
|
23
|
+
- esrepos:/usr/share/elasticsearch/repos
|
24
|
+
- ./elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml
|
25
|
+
ports:
|
26
|
+
- 127.0.0.1:19200:9200
|
27
|
+
|
28
|
+
volumes:
|
29
|
+
esrepos:
|
30
|
+
driver: local
|
31
|
+
driver_opts:
|
32
|
+
device: tmpfs
|
33
|
+
type: tmpfs
|
34
|
+
o: size=100m,uid=102,gid=102
|
@@ -0,0 +1,37 @@
|
|
1
|
+
version: "2.1"
|
2
|
+
|
3
|
+
services:
|
4
|
+
elasticsearch5.6:
|
5
|
+
image: docker.elastic.co/elasticsearch/elasticsearch:5.6.4
|
6
|
+
container_name: es5.6
|
7
|
+
environment:
|
8
|
+
- cluster.name=elastomer5.6
|
9
|
+
- bootstrap.memory_lock=true
|
10
|
+
- discovery.type=single-node
|
11
|
+
- xpack.monitoring.enabled=false
|
12
|
+
- xpack.security.enabled=false
|
13
|
+
- xpack.watcher.enabled=false
|
14
|
+
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
|
15
|
+
ulimits:
|
16
|
+
memlock:
|
17
|
+
soft: -1
|
18
|
+
hard: -1
|
19
|
+
nofile:
|
20
|
+
soft: 65536
|
21
|
+
hard: 65536
|
22
|
+
mem_limit: 1g
|
23
|
+
cap_add:
|
24
|
+
- IPC_LOCK
|
25
|
+
volumes:
|
26
|
+
- esrepos:/usr/share/elasticsearch/repos
|
27
|
+
- ./elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml
|
28
|
+
ports:
|
29
|
+
- 127.0.0.1:19200:9200
|
30
|
+
|
31
|
+
volumes:
|
32
|
+
esrepos:
|
33
|
+
driver: local
|
34
|
+
driver_opts:
|
35
|
+
device: tmpfs
|
36
|
+
type: tmpfs
|
37
|
+
o: size=100m,uid=102,gid=102
|
@@ -0,0 +1,15 @@
|
|
1
|
+
cluster.name: "docker-cluster"
|
2
|
+
|
3
|
+
network.host: 0.0.0.0
|
4
|
+
|
5
|
+
discovery.zen.minimum_master_nodes: 1
|
6
|
+
|
7
|
+
path:
|
8
|
+
data: /usr/share/elasticsearch/data
|
9
|
+
logs: /usr/share/elasticsearch/logs
|
10
|
+
repo: /usr/share/elasticsearch/repos
|
11
|
+
|
12
|
+
transport.tcp.port: 9300
|
13
|
+
http.port: 9200
|
14
|
+
http.max_content_length: 50mb
|
15
|
+
|
data/docs/index.md
CHANGED
@@ -137,8 +137,8 @@ Let's take a look at some simple event log maintenance using elastomer-client.
|
|
137
137
|
# the previous month's event log
|
138
138
|
index = client.index "event-log-2014-09"
|
139
139
|
|
140
|
-
#
|
141
|
-
index.
|
140
|
+
# force merge the index to have only 1 segment file (expunges deleted documents)
|
141
|
+
index.force merge \
|
142
142
|
:max_num_segments => 1,
|
143
143
|
:wait_for_merge => true
|
144
144
|
|
data/docs/notifications.md
CHANGED
data/elastomer-client.gemspec
CHANGED
@@ -28,7 +28,9 @@ Gem::Specification.new do |spec|
|
|
28
28
|
spec.add_development_dependency "activesupport", ">= 3.0"
|
29
29
|
spec.add_development_dependency "minitest", "~> 5.10"
|
30
30
|
spec.add_development_dependency "minitest-fail-fast", "~> 0.1.0"
|
31
|
+
spec.add_development_dependency "minitest-focus", "~> 1.1", ">= 1.1.2"
|
31
32
|
spec.add_development_dependency "webmock", "~> 2.3"
|
32
33
|
spec.add_development_dependency "awesome_print", "~> 1.8"
|
34
|
+
spec.add_development_dependency "pry-byebug", "~> 3.4"
|
33
35
|
spec.add_development_dependency "rake"
|
34
36
|
end
|
data/lib/elastomer/client.rb
CHANGED
@@ -4,16 +4,23 @@ require "multi_json"
|
|
4
4
|
require "semantic"
|
5
5
|
|
6
6
|
require "elastomer/version"
|
7
|
+
require "elastomer/version_support"
|
7
8
|
|
8
9
|
module Elastomer
|
9
10
|
|
10
11
|
class Client
|
11
12
|
MAX_REQUEST_SIZE = 250 * 2**20 # 250 MB
|
12
13
|
|
14
|
+
RETRYABLE_METHODS = %i[get head].freeze
|
15
|
+
|
13
16
|
# Create a new client that can be used to make HTTP requests to the
|
14
|
-
# Elasticsearch server.
|
17
|
+
# Elasticsearch server. If you use `:max_retries`, then any GET or HEAD
|
18
|
+
# request will be retried up to this many times with a 75ms delay between
|
19
|
+
# the retry attempts. Only non-fatal exceptions will retried automatically.
|
20
|
+
#
|
21
|
+
# see lib/elastomer/client/errors.rb#L92-L94
|
15
22
|
#
|
16
|
-
#
|
23
|
+
# Method params:
|
17
24
|
# :host - the host as a String
|
18
25
|
# :port - the port number of the server
|
19
26
|
# :url - the URL as a String (overrides :host and :port)
|
@@ -22,25 +29,43 @@ module Elastomer
|
|
22
29
|
# :adapter - the Faraday adapter to use (defaults to :excon)
|
23
30
|
# :opaque_id - set to `true` to use the 'X-Opaque-Id' request header
|
24
31
|
# :max_request_size - the maximum allowed request size in bytes (defaults to 250 MB)
|
32
|
+
# :max_retries - the maximum number of request retires (defaults to 0)
|
33
|
+
# :retry_delay - delay in seconds between retries (defaults to 0.075)
|
25
34
|
#
|
26
|
-
def initialize(
|
27
|
-
|
28
|
-
|
29
|
-
|
35
|
+
def initialize(host: "localhost", port: 9200, url: nil,
|
36
|
+
read_timeout: 5, open_timeout: 2, max_retries: 0, retry_delay: 0.075,
|
37
|
+
opaque_id: false, adapter: Faraday.default_adapter, max_request_size: MAX_REQUEST_SIZE)
|
38
|
+
|
39
|
+
@url = url || "http://#{host}:#{port}"
|
30
40
|
|
31
41
|
uri = Addressable::URI.parse @url
|
32
42
|
@host = uri.host
|
33
43
|
@port = uri.port
|
34
44
|
|
35
|
-
@read_timeout =
|
36
|
-
@open_timeout =
|
37
|
-
@
|
38
|
-
@
|
39
|
-
@
|
45
|
+
@read_timeout = read_timeout
|
46
|
+
@open_timeout = open_timeout
|
47
|
+
@max_retries = max_retries
|
48
|
+
@retry_delay = retry_delay
|
49
|
+
@adapter = adapter
|
50
|
+
@opaque_id = opaque_id
|
51
|
+
@max_request_size = max_request_size
|
40
52
|
end
|
41
53
|
|
42
54
|
attr_reader :host, :port, :url
|
43
|
-
attr_reader :read_timeout, :open_timeout
|
55
|
+
attr_reader :read_timeout, :open_timeout
|
56
|
+
attr_reader :max_retries, :retry_delay, :max_request_size
|
57
|
+
|
58
|
+
# Returns a duplicate of this Client connection configured in the exact same
|
59
|
+
# fashion.
|
60
|
+
def dup
|
61
|
+
self.class.new \
|
62
|
+
url: url,
|
63
|
+
read_timeout: read_timeout,
|
64
|
+
open_timeout: open_timeout,
|
65
|
+
adapter: @adapter,
|
66
|
+
opaque_id: @opaque_id,
|
67
|
+
max_request_size: max_request_size
|
68
|
+
end
|
44
69
|
|
45
70
|
# Returns true if the server is available; returns false otherwise.
|
46
71
|
def ping
|
@@ -90,6 +115,15 @@ module Elastomer
|
|
90
115
|
end
|
91
116
|
end
|
92
117
|
|
118
|
+
# Internal: Reset the client by removing the current Faraday::Connection. A
|
119
|
+
# new connection will be established on the next request.
|
120
|
+
#
|
121
|
+
# Returns this Client instance.
|
122
|
+
def reset!
|
123
|
+
@connection = nil
|
124
|
+
self
|
125
|
+
end
|
126
|
+
|
93
127
|
# Internal: Sends an HTTP HEAD request to the server.
|
94
128
|
#
|
95
129
|
# path - The path as a String
|
@@ -153,15 +187,18 @@ module Elastomer
|
|
153
187
|
# params - Parameters Hash
|
154
188
|
# :body - Will be used as the request body
|
155
189
|
# :read_timeout - Optional read timeout (in seconds) for the request
|
190
|
+
# :max_retires - Optional retry number for the request
|
156
191
|
#
|
157
192
|
# Returns a Faraday::Response
|
158
193
|
# Raises an Elastomer::Client::Error on 4XX and 5XX responses
|
159
194
|
# rubocop:disable Metrics/MethodLength
|
160
195
|
def request( method, path, params )
|
161
|
-
read_timeout = params.delete
|
162
|
-
|
163
|
-
|
196
|
+
read_timeout = params.delete(:read_timeout)
|
197
|
+
request_max_retries = params.delete(:max_retries) || max_retries
|
198
|
+
body = extract_body(params)
|
199
|
+
path = expand_path(path, params)
|
164
200
|
|
201
|
+
params[:retries] = retries = 0
|
165
202
|
instrument(path, body, params) do
|
166
203
|
begin
|
167
204
|
response =
|
@@ -195,14 +232,35 @@ module Elastomer
|
|
195
232
|
|
196
233
|
# wrap Faraday errors with appropriate Elastomer::Client error classes
|
197
234
|
rescue Faraday::Error::ClientError => boom
|
198
|
-
|
199
|
-
|
200
|
-
|
235
|
+
error = wrap_faraday_error(boom, method, path)
|
236
|
+
if error.retry? && RETRYABLE_METHODS.include?(method) && (retries += 1) <= request_max_retries
|
237
|
+
params[:retries] = retries
|
238
|
+
sleep retry_delay
|
239
|
+
retry
|
240
|
+
end
|
241
|
+
raise error
|
242
|
+
rescue OpaqueIdError => boom
|
243
|
+
reset!
|
244
|
+
raise boom
|
201
245
|
end
|
202
246
|
end
|
203
247
|
end
|
204
248
|
# rubocop:enable Metrics/MethodLength
|
205
249
|
|
250
|
+
# Internal: Returns a new Elastomer::Client error that wraps the given
|
251
|
+
# Faraday error. A generic Error is returned if we cannot wrap the given
|
252
|
+
# Faraday error.
|
253
|
+
#
|
254
|
+
# error - The Faraday error
|
255
|
+
# method - The request method
|
256
|
+
# path - The request path
|
257
|
+
#
|
258
|
+
def wrap_faraday_error(error, method, path)
|
259
|
+
error_name = error.class.name.split("::").last
|
260
|
+
error_class = Elastomer::Client.const_get(error_name) rescue Elastomer::Client::Error
|
261
|
+
error_class.new(error, method.upcase, path)
|
262
|
+
end
|
263
|
+
|
206
264
|
# Internal: Extract the :body from the params Hash and convert it to a
|
207
265
|
# JSON String format. If the params Hash does not contain a :body then no
|
208
266
|
# action is taken and `nil` is returned.
|
@@ -263,6 +321,7 @@ module Elastomer
|
|
263
321
|
query_values = params.dup
|
264
322
|
query_values.delete :action
|
265
323
|
query_values.delete :context
|
324
|
+
query_values.delete :retries
|
266
325
|
|
267
326
|
template.keys.map(&:to_sym).each do |key|
|
268
327
|
value = query_values.delete key
|
@@ -305,21 +364,11 @@ module Elastomer
|
|
305
364
|
raise ServerError, response if response.status >= 500
|
306
365
|
|
307
366
|
if response.body.is_a?(Hash) && (error = response.body["error"])
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
when "query_parsing_exception"; raise QueryParsingError, response
|
314
|
-
end
|
315
|
-
|
316
|
-
# ES 1.X style
|
317
|
-
elsif error.is_a?(String)
|
318
|
-
case error
|
319
|
-
when %r/IndexMissingException/; raise IndexNotFoundError, response
|
320
|
-
when %r/QueryParsingException/; raise QueryParsingError, response
|
321
|
-
when %r/ParseException/; raise QueryParsingError, response
|
322
|
-
end
|
367
|
+
root_cause = Array(error["root_cause"]).first || error
|
368
|
+
case root_cause["type"]
|
369
|
+
when "index_not_found_exception"; raise IndexNotFoundError, response
|
370
|
+
when "illegal_argument_exception"; raise IllegalArgument, response
|
371
|
+
when *version_support.query_parse_exception; raise QueryParsingError, response
|
323
372
|
end
|
324
373
|
|
325
374
|
raise RequestError, response
|
@@ -361,6 +410,10 @@ module Elastomer
|
|
361
410
|
end
|
362
411
|
end
|
363
412
|
|
413
|
+
def version_support
|
414
|
+
@version_support ||= VersionSupport.new(version)
|
415
|
+
end
|
416
|
+
|
364
417
|
end # Client
|
365
418
|
end # Elastomer
|
366
419
|
|
@@ -0,0 +1,158 @@
|
|
1
|
+
module Elastomer
|
2
|
+
class Client
|
3
|
+
|
4
|
+
# DEPRECATED: Delete documents from one or more indices and one or more
|
5
|
+
# types based on a query.
|
6
|
+
#
|
7
|
+
# The return value follows the format returned by the Elasticsearch Delete
|
8
|
+
# by Query plugin: https://github.com/elastic/elasticsearch/blob/v2.4.6/docs/plugins/delete-by-query.asciidoc
|
9
|
+
#
|
10
|
+
# Internally, this method uses a combination of scroll and bulk delete
|
11
|
+
# instead of the Delete by Query API, which was removed in Elasticsearch
|
12
|
+
# 2.0.
|
13
|
+
#
|
14
|
+
# For native _delete_by_query functionality in Elasticsearch 5+, see the
|
15
|
+
# native_delete_by_query method.
|
16
|
+
#
|
17
|
+
# query - The query body as a Hash
|
18
|
+
# params - Parameters Hash
|
19
|
+
#
|
20
|
+
# Examples
|
21
|
+
#
|
22
|
+
# # request body query
|
23
|
+
# app_delete_by_query({:query => {:match_all => {}}}, :type => 'tweet')
|
24
|
+
#
|
25
|
+
# # same thing but using the URI request method
|
26
|
+
# app_delete_by_query(nil, { :q => '*:*', :type => 'tweet' })
|
27
|
+
#
|
28
|
+
# See https://www.elastic.co/guide/en/elasticsearch/plugins/current/delete-by-query-usage.html
|
29
|
+
#
|
30
|
+
# Returns a Hash of statistics about the delete operations, for example:
|
31
|
+
#
|
32
|
+
# {
|
33
|
+
# "took" : 639,
|
34
|
+
# "_indices" : {
|
35
|
+
# "_all" : {
|
36
|
+
# "found" : 5901,
|
37
|
+
# "deleted" : 5901,
|
38
|
+
# "missing" : 0,
|
39
|
+
# "failed" : 0
|
40
|
+
# },
|
41
|
+
# "twitter" : {
|
42
|
+
# "found" : 5901,
|
43
|
+
# "deleted" : 5901,
|
44
|
+
# "missing" : 0,
|
45
|
+
# "failed" : 0
|
46
|
+
# }
|
47
|
+
# },
|
48
|
+
# "failures" : [ ]
|
49
|
+
# }
|
50
|
+
def app_delete_by_query(query, params = {})
|
51
|
+
AppDeleteByQuery.new(self, query, params).execute
|
52
|
+
end
|
53
|
+
|
54
|
+
class AppDeleteByQuery
|
55
|
+
|
56
|
+
SEARCH_PARAMETERS = %i[
|
57
|
+
index
|
58
|
+
type
|
59
|
+
q
|
60
|
+
df
|
61
|
+
analyzer
|
62
|
+
analyze_wildcard
|
63
|
+
batched_reduce_size
|
64
|
+
default_operator
|
65
|
+
lenient
|
66
|
+
explain
|
67
|
+
_source
|
68
|
+
stored_fields
|
69
|
+
sort
|
70
|
+
track_scores
|
71
|
+
timeout
|
72
|
+
terminate_after
|
73
|
+
from
|
74
|
+
size
|
75
|
+
search_type
|
76
|
+
scroll
|
77
|
+
].to_set.freeze
|
78
|
+
|
79
|
+
|
80
|
+
# Create a new DeleteByQuery command for deleting documents matching a
|
81
|
+
# query
|
82
|
+
#
|
83
|
+
# client - Elastomer::Client used for HTTP requests to the server
|
84
|
+
# query - The query used to find documents to delete
|
85
|
+
# params - Other URL parameters
|
86
|
+
def initialize(client, query, params = {})
|
87
|
+
@client = client
|
88
|
+
@query = query
|
89
|
+
@params = params
|
90
|
+
@response_stats = { "took" => 0, "_indices" => { "_all" => {} }, "failures" => [] }
|
91
|
+
end
|
92
|
+
|
93
|
+
attr_reader :client, :query, :params, :response_stats
|
94
|
+
|
95
|
+
# Internal: Determine whether or not an HTTP status code is in the range
|
96
|
+
# 200 to 299
|
97
|
+
#
|
98
|
+
# status - HTTP status code
|
99
|
+
#
|
100
|
+
# Returns a boolean
|
101
|
+
def is_ok?(status)
|
102
|
+
status.between?(200, 299)
|
103
|
+
end
|
104
|
+
|
105
|
+
# Internal: Tally the contributions of an item to the found, deleted,
|
106
|
+
# missing, and failed counts for the summary statistics
|
107
|
+
#
|
108
|
+
# item - An element of the items array from a bulk response
|
109
|
+
#
|
110
|
+
# Returns a Hash of counts for each category
|
111
|
+
def categorize(item)
|
112
|
+
{
|
113
|
+
"found" => item["found"] || item["status"] == 409 ? 1 : 0,
|
114
|
+
"deleted" => is_ok?(item["status"]) ? 1 : 0,
|
115
|
+
"missing" => !item["found"] && !item.key?("error") ? 1 : 0,
|
116
|
+
"failed" => item.key?("error") ? 1 : 0,
|
117
|
+
}
|
118
|
+
end
|
119
|
+
|
120
|
+
# Internal: Combine a response item with the existing statistics
|
121
|
+
#
|
122
|
+
# item - A bulk response item
|
123
|
+
def accumulate(item)
|
124
|
+
item = item["delete"]
|
125
|
+
(@response_stats["_indices"][item["_index"]] ||= {}).merge!(categorize(item)) { |_, n, m| n + m }
|
126
|
+
@response_stats["_indices"]["_all"].merge!(categorize(item)) { |_, n, m| n + m }
|
127
|
+
@response_stats["failures"] << item unless is_ok? item["status"]
|
128
|
+
end
|
129
|
+
|
130
|
+
# Perform the Delete by Query action
|
131
|
+
#
|
132
|
+
# Returns a Hash of statistics about the bulk operation
|
133
|
+
def execute
|
134
|
+
ops = Enumerator.new do |yielder|
|
135
|
+
@client.scan(@query, search_params).each_document do |hit|
|
136
|
+
yielder.yield([:delete, hit.select { |key, _| ["_index", "_type", "_id", "_routing"].include?(key) }])
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
stats = @client.bulk_stream_items(ops, bulk_params) { |item| accumulate(item) }
|
141
|
+
@response_stats["took"] = stats["took"]
|
142
|
+
@response_stats
|
143
|
+
end
|
144
|
+
|
145
|
+
# Internal: Remove parameters that are not valid for the _search endpoint
|
146
|
+
def search_params
|
147
|
+
params = @params.merge(:_source => false)
|
148
|
+
params.select {|p, _| SEARCH_PARAMETERS.include? p}
|
149
|
+
end
|
150
|
+
|
151
|
+
# Internal: Remove parameters that are not valid for the _bulk endpoint
|
152
|
+
def bulk_params
|
153
|
+
@params.clone.tap { |p| p.delete(:q) }
|
154
|
+
end
|
155
|
+
|
156
|
+
end # AppDeleteByQuery
|
157
|
+
end # Client
|
158
|
+
end # Elastomer
|