elastomer-client 0.3.1
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 +7 -0
- data/.gitignore +8 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +4 -0
- data/Gemfile +5 -0
- data/LICENSE.txt +22 -0
- data/README.md +108 -0
- data/Rakefile +9 -0
- data/docs/notifications.md +71 -0
- data/elastomer-client.gemspec +30 -0
- data/lib/elastomer/client.rb +307 -0
- data/lib/elastomer/client/bulk.rb +257 -0
- data/lib/elastomer/client/cluster.rb +208 -0
- data/lib/elastomer/client/docs.rb +432 -0
- data/lib/elastomer/client/errors.rb +51 -0
- data/lib/elastomer/client/index.rb +407 -0
- data/lib/elastomer/client/multi_search.rb +115 -0
- data/lib/elastomer/client/nodes.rb +87 -0
- data/lib/elastomer/client/scan.rb +161 -0
- data/lib/elastomer/client/template.rb +85 -0
- data/lib/elastomer/client/warmer.rb +96 -0
- data/lib/elastomer/core_ext/time.rb +7 -0
- data/lib/elastomer/middleware/encode_json.rb +51 -0
- data/lib/elastomer/middleware/opaque_id.rb +69 -0
- data/lib/elastomer/middleware/parse_json.rb +39 -0
- data/lib/elastomer/notifications.rb +83 -0
- data/lib/elastomer/version.rb +7 -0
- data/script/bootstrap +16 -0
- data/script/cibuild +28 -0
- data/script/console +9 -0
- data/script/testsuite +10 -0
- data/test/assertions.rb +74 -0
- data/test/client/bulk_test.rb +226 -0
- data/test/client/cluster_test.rb +113 -0
- data/test/client/docs_test.rb +394 -0
- data/test/client/index_test.rb +244 -0
- data/test/client/multi_search_test.rb +129 -0
- data/test/client/nodes_test.rb +35 -0
- data/test/client/scan_test.rb +84 -0
- data/test/client/stubbed_client_tests.rb +40 -0
- data/test/client/template_test.rb +33 -0
- data/test/client/warmer_test.rb +56 -0
- data/test/client_test.rb +86 -0
- data/test/core_ext/time_test.rb +46 -0
- data/test/middleware/encode_json_test.rb +53 -0
- data/test/middleware/opaque_id_test.rb +39 -0
- data/test/middleware/parse_json_test.rb +54 -0
- data/test/test_helper.rb +94 -0
- metadata +210 -0
@@ -0,0 +1,87 @@
|
|
1
|
+
|
2
|
+
module Elastomer
|
3
|
+
class Client
|
4
|
+
|
5
|
+
# Provides access to node-level API commands.
|
6
|
+
#
|
7
|
+
# node_id - The node ID as a String or an Array of node IDs
|
8
|
+
#
|
9
|
+
# Returns a Nodes instance.
|
10
|
+
def nodes( node_id = '_all' )
|
11
|
+
Nodes.new self, node_id
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
class Nodes
|
16
|
+
# Create a new nodes client for making API requests that pertain to
|
17
|
+
# the health and management individual nodes.
|
18
|
+
#
|
19
|
+
# client - Elastomer::Client used for HTTP requests to the server
|
20
|
+
# node_id - The node ID as a String or an Array of node IDs
|
21
|
+
#
|
22
|
+
def initialize( client, node_id )
|
23
|
+
@client = client
|
24
|
+
@node_id = node_id
|
25
|
+
end
|
26
|
+
|
27
|
+
attr_reader :client, :node_id
|
28
|
+
|
29
|
+
# Retrieve one or more (or all) of the cluster nodes information.
|
30
|
+
# See http://www.elasticsearch.org/guide/reference/api/admin-cluster-nodes-info/
|
31
|
+
#
|
32
|
+
# params - Parameters Hash
|
33
|
+
#
|
34
|
+
# Returns the response as a Hash
|
35
|
+
def info( params = {} )
|
36
|
+
response = client.get '/_nodes{/node_id}', update_params(params, :action => 'nodes.info')
|
37
|
+
response.body
|
38
|
+
end
|
39
|
+
|
40
|
+
# Retrieve one or more (or all) of the cluster nodes statistics.
|
41
|
+
# See http://www.elasticsearch.org/guide/reference/api/admin-cluster-nodes-stats/
|
42
|
+
#
|
43
|
+
# params - Parameters Hash
|
44
|
+
#
|
45
|
+
# Returns the response as a Hash
|
46
|
+
def stats( params = {} )
|
47
|
+
response = client.get '/_nodes{/node_id}/stats', update_params(params, :action => 'nodes.stats')
|
48
|
+
response.body
|
49
|
+
end
|
50
|
+
|
51
|
+
# Get the current hot threads on each node in the cluster.
|
52
|
+
# See http://www.elasticsearch.org/guide/reference/api/admin-cluster-nodes-hot-threads/
|
53
|
+
#
|
54
|
+
# params - Parameters Hash
|
55
|
+
#
|
56
|
+
# Returns the response as a Hash
|
57
|
+
def hot_threads( params = {} )
|
58
|
+
response = client.get '/_nodes{/node_id}/hot_threads', update_params(params, :action => 'nodes.hot_threads')
|
59
|
+
response.body
|
60
|
+
end
|
61
|
+
|
62
|
+
# Shutdown one or more nodes in the cluster.
|
63
|
+
# See http://www.elasticsearch.org/guide/reference/api/admin-cluster-nodes-shutdown/
|
64
|
+
#
|
65
|
+
# params - Parameters Hash
|
66
|
+
#
|
67
|
+
# Returns the response as a Hash
|
68
|
+
def shutdown( params = {} )
|
69
|
+
response = client.post '/_cluster/nodes{/node_id}/_shutdown', update_params(params, :action => 'nodes.shutdown')
|
70
|
+
response.body
|
71
|
+
end
|
72
|
+
|
73
|
+
# Internal: Add default parameters to the `params` Hash and then apply
|
74
|
+
# `overrides` to the params if any are given.
|
75
|
+
#
|
76
|
+
# params - Parameters Hash
|
77
|
+
# overrides - Optional parameter overrides as a Hash
|
78
|
+
#
|
79
|
+
# Returns a new params Hash.
|
80
|
+
def update_params( params, overrides = nil )
|
81
|
+
h = { :node_id => node_id }.update params
|
82
|
+
h.update overrides unless overrides.nil?
|
83
|
+
h
|
84
|
+
end
|
85
|
+
end # Nodes
|
86
|
+
end # Client
|
87
|
+
end # Elastomer
|
@@ -0,0 +1,161 @@
|
|
1
|
+
module Elastomer
|
2
|
+
class Client
|
3
|
+
|
4
|
+
# Create a new Scan instance for scrolling all results from a `query`.
|
5
|
+
#
|
6
|
+
# query - The query to scan as a Hash or a JSON encoded String
|
7
|
+
# opts - Options Hash
|
8
|
+
# :index - the name of the index to search
|
9
|
+
# :type - the document type to search
|
10
|
+
# :scroll - the keep alive time of the scrolling request (5 minutes by default)
|
11
|
+
# :size - the number of documents per shard to fetch per scroll
|
12
|
+
#
|
13
|
+
# Examples
|
14
|
+
#
|
15
|
+
# scan = client.scan('{"query":{"match_all":{}}}', :index => 'test')
|
16
|
+
# scan.each_document do |document|
|
17
|
+
# document['_id']
|
18
|
+
# document['_source']
|
19
|
+
# end
|
20
|
+
#
|
21
|
+
# Returns a new Scan instance
|
22
|
+
def scan( query, opts = {} )
|
23
|
+
Scan.new self, query, opts
|
24
|
+
end
|
25
|
+
|
26
|
+
# Continue scrolling a scan query.
|
27
|
+
# See http://www.elasticsearch.org/guide/reference/api/search/scroll/
|
28
|
+
#
|
29
|
+
# scroll_id - The current scroll ID as a String
|
30
|
+
# scroll - The keep alive time of the scrolling request (5 minutes by default)
|
31
|
+
#
|
32
|
+
# Examples
|
33
|
+
#
|
34
|
+
# scroll_id = client.scan('{"query":{"match_all":{}}}', :index => 'test').scroll_id
|
35
|
+
#
|
36
|
+
# h = client.scroll scroll_id # scroll to get the next set of results
|
37
|
+
# scroll_id = h['_scroll_id'] # and store the scroll_id to use later
|
38
|
+
#
|
39
|
+
# h = client.scroll scroll_id # scroll again to get the next set of results
|
40
|
+
# scroll_id = h['_scroll_id'] # and store the scroll_id to use later
|
41
|
+
#
|
42
|
+
# # repeat until the results are empty
|
43
|
+
#
|
44
|
+
# Returns the response body as a Hash.
|
45
|
+
def scroll( scroll_id, scroll = '5m' )
|
46
|
+
response = get '/_search/scroll', :body => scroll_id, :scroll => scroll, :action => 'search.scroll'
|
47
|
+
response.body
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
class Scan
|
52
|
+
# Create a new scan client that can be used to iterate over all the
|
53
|
+
# documents returned by the `query`.
|
54
|
+
#
|
55
|
+
# See http://www.elasticsearch.org/guide/reference/api/search/scroll/
|
56
|
+
# and the "Scan" section of http://www.elasticsearch.org/guide/reference/api/search/search-type/
|
57
|
+
#
|
58
|
+
# client - Elastomer::Client used for HTTP requests to the server
|
59
|
+
# query - The query to scan as a Hash or a JSON encoded String
|
60
|
+
# opts - Options Hash
|
61
|
+
# :index - the name of the index to search
|
62
|
+
# :type - the document type to search
|
63
|
+
# :scroll - the keep alive time of the scrolling request (5 minutes by default)
|
64
|
+
# :size - the number of documents per shard to fetch per scroll
|
65
|
+
#
|
66
|
+
# Examples
|
67
|
+
#
|
68
|
+
# scan = Scan.new(client, {:query => {:match_all => {}}}, :index => 'test-1')
|
69
|
+
# scan.each_document { |doc|
|
70
|
+
# doc['_id']
|
71
|
+
# doc['_source']
|
72
|
+
# }
|
73
|
+
#
|
74
|
+
def initialize( client, query, opts = {} )
|
75
|
+
@client = client
|
76
|
+
@query = query
|
77
|
+
|
78
|
+
@index = opts.fetch(:index, nil)
|
79
|
+
@type = opts.fetch(:type, nil)
|
80
|
+
@scroll = opts.fetch(:scroll, '5m')
|
81
|
+
@size = opts.fetch(:size, 50)
|
82
|
+
|
83
|
+
@offset = 0
|
84
|
+
end
|
85
|
+
|
86
|
+
attr_reader :client, :query, :index, :type, :scroll, :size
|
87
|
+
|
88
|
+
# Iterate over all the search results from the scan query.
|
89
|
+
#
|
90
|
+
# block - The block will be called for each set of matching documents
|
91
|
+
# returned from executing the scan query.
|
92
|
+
#
|
93
|
+
# Yields a hits Hash containing the 'total' number of hits, current
|
94
|
+
# 'offset' into that total, and the Array of 'hits' document Hashes.
|
95
|
+
#
|
96
|
+
# Examples
|
97
|
+
#
|
98
|
+
# scan.each do |hits|
|
99
|
+
# hits['total']
|
100
|
+
# hits['offset']
|
101
|
+
# hits['hits'].each { |document| ... }
|
102
|
+
# end
|
103
|
+
#
|
104
|
+
# Returns this Scan instance.
|
105
|
+
def each
|
106
|
+
loop do
|
107
|
+
body = client.scroll scroll_id, scroll
|
108
|
+
@scroll_id = body['_scroll_id']
|
109
|
+
|
110
|
+
hits = body['hits']
|
111
|
+
break if hits['hits'].empty?
|
112
|
+
|
113
|
+
hits['offset'] = @offset
|
114
|
+
@offset += hits['hits'].length
|
115
|
+
|
116
|
+
yield hits
|
117
|
+
end
|
118
|
+
|
119
|
+
self
|
120
|
+
end
|
121
|
+
|
122
|
+
# Iterate over each document from the scan query. This method is just a
|
123
|
+
# convenience wrapper around the `each` method; it iterates the Array of
|
124
|
+
# documents and passes them one by one to the block.
|
125
|
+
#
|
126
|
+
# block - The block will be called for each document returned from
|
127
|
+
# executing the scan query.
|
128
|
+
#
|
129
|
+
# Yields a document Hash.
|
130
|
+
#
|
131
|
+
# Examples
|
132
|
+
#
|
133
|
+
# scan.each_document do |document|
|
134
|
+
# document['_id']
|
135
|
+
# document['_source']
|
136
|
+
# end
|
137
|
+
#
|
138
|
+
# Returns this Scan instance.
|
139
|
+
def each_document( &block )
|
140
|
+
each { |hits| hits['hits'].each(&block) }
|
141
|
+
end
|
142
|
+
|
143
|
+
# Internal: Returns the current scroll ID as a String.
|
144
|
+
def scroll_id
|
145
|
+
return @scroll_id if defined? @scroll_id
|
146
|
+
|
147
|
+
response = client.get '{/index}{/type}/_search',
|
148
|
+
:action => 'search.scan',
|
149
|
+
:search_type => 'scan',
|
150
|
+
:scroll => scroll,
|
151
|
+
:size => size,
|
152
|
+
:index => index,
|
153
|
+
:type => type,
|
154
|
+
:body => query
|
155
|
+
|
156
|
+
@scroll_id = response.body['_scroll_id']
|
157
|
+
end
|
158
|
+
|
159
|
+
end # Scan
|
160
|
+
end # Client
|
161
|
+
end # Elastomer
|
@@ -0,0 +1,85 @@
|
|
1
|
+
|
2
|
+
module Elastomer
|
3
|
+
class Client
|
4
|
+
|
5
|
+
# Returns a Template instance.
|
6
|
+
def template( name )
|
7
|
+
Template.new self, name
|
8
|
+
end
|
9
|
+
|
10
|
+
|
11
|
+
class Template
|
12
|
+
|
13
|
+
# Create a new template client for making API requests that pertain to
|
14
|
+
# template management.
|
15
|
+
#
|
16
|
+
# client - Elastomer::Client used for HTTP requests to the server
|
17
|
+
# name - The name of the template as a String
|
18
|
+
#
|
19
|
+
def initialize( client, name )
|
20
|
+
@client = client
|
21
|
+
@name = name
|
22
|
+
end
|
23
|
+
|
24
|
+
attr_reader :client, :name
|
25
|
+
|
26
|
+
# Returns true if the template already exists on the cluster.
|
27
|
+
def exists?
|
28
|
+
client.cluster.templates.key? name
|
29
|
+
end
|
30
|
+
alias :exist? :exists?
|
31
|
+
|
32
|
+
# Get the template from the cluster.
|
33
|
+
# See http://www.elasticsearch.org/guide/reference/api/admin-indices-templates/
|
34
|
+
#
|
35
|
+
# params - Parameters Hash
|
36
|
+
#
|
37
|
+
# Returns the response body as a Hash
|
38
|
+
def get( params = {} )
|
39
|
+
response = client.get '/_template/{template}', update_params(params, :action => 'template.get')
|
40
|
+
response.body
|
41
|
+
end
|
42
|
+
|
43
|
+
# Create the template on the cluster.
|
44
|
+
# See http://www.elasticsearch.org/guide/reference/api/admin-indices-templates/
|
45
|
+
#
|
46
|
+
# template - The template as a Hash or a JSON encoded String
|
47
|
+
# params - Parameters Hash
|
48
|
+
#
|
49
|
+
# Returns the response body as a Hash
|
50
|
+
def create( template, params = {} )
|
51
|
+
response = client.put '/_template/{template}', update_params(params, :body => template, :action => 'template.create')
|
52
|
+
response.body
|
53
|
+
end
|
54
|
+
|
55
|
+
# Delete the template from the cluster.
|
56
|
+
# See http://www.elasticsearch.org/guide/reference/api/admin-indices-templates/
|
57
|
+
#
|
58
|
+
# params - Parameters Hash
|
59
|
+
#
|
60
|
+
# Returns the response body as a Hash
|
61
|
+
def delete( params = {} )
|
62
|
+
response = client.delete '/_template/{template}', update_params(params, :action => 'template.delete')
|
63
|
+
response.body
|
64
|
+
end
|
65
|
+
|
66
|
+
# Internal: Add default parameters to the `params` Hash and then apply
|
67
|
+
# `overrides` to the params if any are given.
|
68
|
+
#
|
69
|
+
# params - Parameters Hash
|
70
|
+
# overrides - Optional parameter overrides as a Hash
|
71
|
+
#
|
72
|
+
# Returns a new params Hash.
|
73
|
+
def update_params( params, overrides = nil )
|
74
|
+
h = defaults.update params
|
75
|
+
h.update overrides unless overrides.nil?
|
76
|
+
h
|
77
|
+
end
|
78
|
+
|
79
|
+
# Internal: Returns a Hash containing default parameters.
|
80
|
+
def defaults
|
81
|
+
{ :template => name }
|
82
|
+
end
|
83
|
+
end # Template
|
84
|
+
end # Client
|
85
|
+
end # Elastomer
|
@@ -0,0 +1,96 @@
|
|
1
|
+
module Elastomer
|
2
|
+
class Client
|
3
|
+
|
4
|
+
# Provides access to warmer API commands.
|
5
|
+
# See http://www.elasticsearch.org/guide/reference/api/admin-indices-warmers/
|
6
|
+
#
|
7
|
+
# index_name - The name of the index as a String
|
8
|
+
# warmer_name - The name of the warmer as a String
|
9
|
+
#
|
10
|
+
# Returns a Warmer instance.
|
11
|
+
def warmer(index_name, warmer_name)
|
12
|
+
Warmer.new(self, index_name, warmer_name)
|
13
|
+
end
|
14
|
+
|
15
|
+
class Warmer
|
16
|
+
|
17
|
+
# Create a new Warmer helper for making warmer API requests.
|
18
|
+
#
|
19
|
+
# client - Elastomer::Client used for HTTP requests to the server
|
20
|
+
# index_name - The name of the index as a String
|
21
|
+
# name - The name of the warmer as a String
|
22
|
+
def initialize(client, index_name, name)
|
23
|
+
@client = client
|
24
|
+
@index_name = @client.assert_param_presence(index_name, 'index name')
|
25
|
+
@name = @client.assert_param_presence(name, 'warmer name')
|
26
|
+
end
|
27
|
+
|
28
|
+
attr_reader :client, :index_name, :name
|
29
|
+
|
30
|
+
# Create a warmer.
|
31
|
+
# See http://www.elasticsearch.org/guide/reference/api/admin-indices-warmers/
|
32
|
+
#
|
33
|
+
# query - The query the warmer should run
|
34
|
+
# params - Parameters Hash
|
35
|
+
#
|
36
|
+
# Examples
|
37
|
+
#
|
38
|
+
# warmer.create(:query => {:match_all => {}})
|
39
|
+
#
|
40
|
+
# Returns the response body as a Hash
|
41
|
+
def create(query, params = {})
|
42
|
+
response = client.put '/{index}{/type}/_warmer/{warmer}', defaults.update(params.update(:body => query))
|
43
|
+
response.body
|
44
|
+
end
|
45
|
+
|
46
|
+
# Delete a warmer.
|
47
|
+
# See http://www.elasticsearch.org/guide/reference/api/admin-indices-warmers/
|
48
|
+
#
|
49
|
+
# params - Parameters Hash
|
50
|
+
#
|
51
|
+
# Returns the response body as a Hash
|
52
|
+
def delete(params = {})
|
53
|
+
response = client.delete '/{index}{/type}/_warmer/{warmer}', defaults.update(params)
|
54
|
+
response.body
|
55
|
+
end
|
56
|
+
|
57
|
+
# Get a warmer.
|
58
|
+
# See http://www.elasticsearch.org/guide/reference/api/admin-indices-warmers/
|
59
|
+
#
|
60
|
+
# params - Parameters Hash
|
61
|
+
#
|
62
|
+
# Returns the response body as a Hash
|
63
|
+
def get(params = {})
|
64
|
+
response = client.get '/{index}{/type}/_warmer/{warmer}', defaults.update(params)
|
65
|
+
response.body
|
66
|
+
end
|
67
|
+
|
68
|
+
# Check whether a warmer exists. Also aliased as exist?
|
69
|
+
#
|
70
|
+
# Since there is no native warmer exists api, this method executes
|
71
|
+
# a get and watches for an IndexWarmerMissingException error.
|
72
|
+
#
|
73
|
+
# Returns true if the warmer exists, false if not.
|
74
|
+
#COMPATIBILITY warmer response differs in ES 1.0
|
75
|
+
# ES 1.0: missing warmer returns {} with 200 status
|
76
|
+
# ES 0.90: missing warmer returns IndexWarmerMissingException error
|
77
|
+
# See https://github.com/elasticsearch/elasticsearch/issues/5155
|
78
|
+
def exists?
|
79
|
+
response = get
|
80
|
+
response != {}
|
81
|
+
rescue Elastomer::Client::Error => exception
|
82
|
+
if exception.message =~ /IndexWarmerMissingException/
|
83
|
+
false
|
84
|
+
else
|
85
|
+
raise exception
|
86
|
+
end
|
87
|
+
end
|
88
|
+
alias :exist? :exists?
|
89
|
+
|
90
|
+
# Internal: Returns a Hash containing default parameters.
|
91
|
+
def defaults
|
92
|
+
{:index => index_name, :warmer => name}
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Elastomer
|
2
|
+
module Middleware
|
3
|
+
# Request middleware that encodes the body as JSON.
|
4
|
+
#
|
5
|
+
# Processes only requests with matching Content-type or those without a type.
|
6
|
+
# If a request doesn't have a type but has a body, it sets the Content-type
|
7
|
+
# to JSON MIME-type.
|
8
|
+
#
|
9
|
+
# Doesn't try to encode bodies that already are in string form.
|
10
|
+
class EncodeJson < Faraday::Middleware
|
11
|
+
CONTENT_TYPE = 'Content-Type'.freeze
|
12
|
+
MIME_TYPE = 'application/json'.freeze
|
13
|
+
|
14
|
+
def call(env)
|
15
|
+
match_content_type(env) do |data|
|
16
|
+
env[:body] = encode data
|
17
|
+
end
|
18
|
+
@app.call env
|
19
|
+
end
|
20
|
+
|
21
|
+
def encode(data)
|
22
|
+
MultiJson.dump data
|
23
|
+
end
|
24
|
+
|
25
|
+
def match_content_type(env)
|
26
|
+
if process_request?(env)
|
27
|
+
env[:request_headers][CONTENT_TYPE] ||= MIME_TYPE
|
28
|
+
yield env[:body] unless env[:body].respond_to?(:to_str)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def process_request?(env)
|
33
|
+
type = request_type(env)
|
34
|
+
has_body?(env) and (type.empty? or type == MIME_TYPE)
|
35
|
+
end
|
36
|
+
|
37
|
+
def has_body?(env)
|
38
|
+
body = env[:body] and !(body.respond_to?(:to_str) and body.empty?)
|
39
|
+
end
|
40
|
+
|
41
|
+
def request_type(env)
|
42
|
+
type = env[:request_headers][CONTENT_TYPE].to_s
|
43
|
+
type = type.split(';', 2).first if type.index(';')
|
44
|
+
type
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
Faraday::Request.register_middleware \
|
51
|
+
:encode_json => ::Elastomer::Middleware::EncodeJson
|