elastomer-client 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|