stretcher 1.12.0 → 1.13.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +7 -5
- data/lib/stretcher/index_type.rb +18 -4
- data/lib/stretcher/server.rb +67 -46
- data/lib/stretcher/version.rb +1 -1
- data/spec/lib/stretcher_index_type_spec.rb +55 -39
- metadata +2 -2
data/README.md
CHANGED
@@ -10,11 +10,12 @@ A concise, fast ElasticSearch client designed to reflect the actual elastic sear
|
|
10
10
|
# Features
|
11
11
|
|
12
12
|
* Cleanly matches up to elastic search's JSON api
|
13
|
-
* Efficiently re-uses connections on a per-server object basis (via
|
13
|
+
* Efficiently re-uses connections on a per-server object basis (via excon)
|
14
14
|
* Supports efficient bulk indexing operations
|
15
15
|
* Returns most responses in convenient Hashie::Mash form
|
16
16
|
* Configurable logging
|
17
17
|
* Pure, threadsafe, ruby
|
18
|
+
* Easily swap HTTP clients via Faraday
|
18
19
|
|
19
20
|
## Installation
|
20
21
|
|
@@ -80,15 +81,15 @@ docs = [{"_type" => "tweet", "_id" => 91011, "text" => "Bulked"}]
|
|
80
81
|
server.index(:foo).bulk_index(docs)
|
81
82
|
```
|
82
83
|
|
84
|
+
### Full Documentation
|
85
|
+
|
86
|
+
This README documents only part of stretcher's API. The full documentation for stretcher is available in its [full rdocs](http://rdoc.info/github/PoseBiz/stretcher/master/frames).
|
87
|
+
|
83
88
|
### Rails Integration
|
84
89
|
|
85
90
|
Stretcher is a low level-client, but it was built as a part of a full suite of Rails integration tools.
|
86
91
|
While not yet open-sourced, you can read our detailed blog post: [integrating Stretcher with Rails](http://blog.andrewvc.com/elasticsearch-rails-stretcher-at-pose).
|
87
92
|
|
88
|
-
### Full Documentation
|
89
|
-
|
90
|
-
This README documents only part of stretcher's API. The full documentation for stretcher is available in its [full rdocs](http://rdoc.info/github/PoseBiz/stretcher/master/frames).
|
91
|
-
|
92
93
|
## Running Specs
|
93
94
|
|
94
95
|
Running the specs requires an operational Elastic Search server on http://localhost:9200.
|
@@ -102,6 +103,7 @@ Specs may be run with `rake spec`
|
|
102
103
|
* [@aq1018](https://github.com/aq1018)
|
103
104
|
* [@akahn](https://github.com/akahn)
|
104
105
|
* [@psynix](https://github.com/psynix)
|
106
|
+
* [@cmaitchison](https://github.com/cmaitchison)
|
105
107
|
* [@fmardini](https://github.com/fmardini)
|
106
108
|
* [@chatgris](https://github.com/chatgris)
|
107
109
|
* [@alpinegizmo](https://github.com/alpinegizmo)
|
data/lib/stretcher/index_type.rb
CHANGED
@@ -11,16 +11,30 @@ module Stretcher
|
|
11
11
|
@logger = options[:logger] || index.logger
|
12
12
|
end
|
13
13
|
|
14
|
-
# Retrieves the document by ID
|
15
|
-
# Normally this returns the contents of _source, however, the 'raw' flag is passed in, it will return the full response hash
|
16
|
-
# Returns nil if the document does not exist
|
14
|
+
# Retrieves the document by ID.
|
15
|
+
# Normally this returns the contents of _source, however, if the 'raw' flag is passed in, it will return the full response hash.
|
16
|
+
# Returns nil if the document does not exist.
|
17
|
+
#
|
18
|
+
# The :fields argument can either be a csv String or an Array. e.g. [:field1,'field2] or "field1,field2".
|
19
|
+
# If the fields parameter is passed in those fields are returned instead of _source.
|
20
|
+
#
|
21
|
+
# If, you include _source as a field, along with other fields you MUST set the raw flag to true to
|
22
|
+
# receive both fields and _source. Otherwise, only _source will be returned
|
17
23
|
def get(id, options={}, raw=false)
|
18
24
|
if options == true || options == false # Support raw as second argument, legacy API
|
19
25
|
raw = true
|
20
26
|
options = {}
|
21
27
|
end
|
28
|
+
|
29
|
+
# If fields is passed in as an array, properly encode it
|
30
|
+
arg_fields = options[:fields]
|
31
|
+
if arg_fields.is_a?(Array)
|
32
|
+
# no #merge! we don't want to mutate args
|
33
|
+
options = options.merge(:fields => arg_fields.join(","))
|
34
|
+
end
|
35
|
+
|
22
36
|
res = request(:get, id, options)
|
23
|
-
raw ? res : res["_source"]
|
37
|
+
raw ? res : (res["_source"] || res["fields"])
|
24
38
|
end
|
25
39
|
|
26
40
|
# Retrieves multiple documents of the index type by ID
|
data/lib/stretcher/server.rb
CHANGED
@@ -2,6 +2,52 @@ module Stretcher
|
|
2
2
|
class Server < EsComponent
|
3
3
|
attr_reader :uri, :http, :logger
|
4
4
|
|
5
|
+
# Internal use only.
|
6
|
+
# Returns a properly configured HTTP client when initializing an instance
|
7
|
+
def self.build_client(uri, options={})
|
8
|
+
http = Faraday.new(:url => uri) do |builder|
|
9
|
+
builder.response :mashify
|
10
|
+
builder.response :json, :content_type => /\bjson$/
|
11
|
+
|
12
|
+
builder.request :json
|
13
|
+
|
14
|
+
builder.options[:read_timeout] = 4 || options[:read_timeout]
|
15
|
+
builder.options[:open_timeout] = 2 || options[:open_timeout]
|
16
|
+
|
17
|
+
if faraday_configurator = options[:faraday_configurator]
|
18
|
+
faraday_configurator.call(builder)
|
19
|
+
else
|
20
|
+
builder.adapter :excon
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
uri_components = URI.parse(uri)
|
25
|
+
if uri_components.user || uri_components.password
|
26
|
+
http.basic_auth(uri_components.user, uri_components.password)
|
27
|
+
end
|
28
|
+
|
29
|
+
http
|
30
|
+
end
|
31
|
+
|
32
|
+
# Internal use only.
|
33
|
+
# Builds a logger when initializing an instance
|
34
|
+
def self.build_logger(options)
|
35
|
+
logger = nil
|
36
|
+
|
37
|
+
if options[:logger]
|
38
|
+
logger = options[:logger]
|
39
|
+
else
|
40
|
+
logger = Logger.new(STDOUT)
|
41
|
+
logger.level = Logger::WARN
|
42
|
+
end
|
43
|
+
|
44
|
+
logger.formatter = proc do |severity, datetime, progname, msg|
|
45
|
+
"[Stretcher][#{severity}]: #{msg}\n"
|
46
|
+
end
|
47
|
+
|
48
|
+
logger
|
49
|
+
end
|
50
|
+
|
5
51
|
# Instantiate a new instance in a manner convenient for using the block syntax.
|
6
52
|
# Can be used interchangably with +Stretcher::Server.new+ but will return the value
|
7
53
|
# of the block if present. See the regular constructor for full options.
|
@@ -27,38 +73,8 @@ module Stretcher
|
|
27
73
|
def initialize(uri='http://localhost:9200', options={})
|
28
74
|
@request_mtx = Mutex.new
|
29
75
|
@uri = uri
|
30
|
-
|
31
|
-
@
|
32
|
-
builder.response :mashify
|
33
|
-
builder.response :json, :content_type => /\bjson$/
|
34
|
-
|
35
|
-
builder.request :json
|
36
|
-
|
37
|
-
builder.options[:read_timeout] = 4 || options[:read_timeout]
|
38
|
-
builder.options[:open_timeout] = 2 || options[:open_timeout]
|
39
|
-
|
40
|
-
if faraday_configurator = options[:faraday_configurator]
|
41
|
-
faraday_configurator.call(builder)
|
42
|
-
else
|
43
|
-
builder.adapter :excon
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
uri_components = URI.parse(@uri)
|
48
|
-
if uri_components.user || uri_components.password
|
49
|
-
@http.basic_auth(uri_components.user, uri_components.password)
|
50
|
-
end
|
51
|
-
|
52
|
-
if options[:logger]
|
53
|
-
@logger = options[:logger]
|
54
|
-
else
|
55
|
-
@logger = Logger.new(STDOUT)
|
56
|
-
@logger.level = Logger::WARN
|
57
|
-
end
|
58
|
-
|
59
|
-
@logger.formatter = proc do |severity, datetime, progname, msg|
|
60
|
-
"[Stretcher][#{severity}]: #{msg}\n"
|
61
|
-
end
|
76
|
+
@http = self.class.build_client(@uri, options)
|
77
|
+
@logger = self.class.build_logger(options)
|
62
78
|
end
|
63
79
|
|
64
80
|
# Returns a Stretcher::Index object for the index +name+.
|
@@ -71,7 +87,9 @@ module Stretcher
|
|
71
87
|
idx = Index.new(self, name, :logger => logger)
|
72
88
|
block ? block.call(idx) : idx
|
73
89
|
end
|
74
|
-
|
90
|
+
|
91
|
+
# Perform a raw bulk operation. You probably want to use Stretcher::Index#bulk_index
|
92
|
+
# which properly formats a bulk index request.
|
75
93
|
def bulk(data)
|
76
94
|
request(:post, path_uri("/_bulk")) do |req|
|
77
95
|
req.body = data
|
@@ -169,19 +187,22 @@ module Stretcher
|
|
169
187
|
logger.info { "Stretcher: Issuing Request #{method.to_s.upcase}, #{Util.qurl(url,query_opts)}" }
|
170
188
|
|
171
189
|
# Our default client is threadsafe, but some others might not be
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
190
|
+
check_response(@request_mtx.synchronize {
|
191
|
+
if block
|
192
|
+
http.send(method, url, query_opts, *args) do |req|
|
193
|
+
# Default content type to json, the block can change this of course
|
194
|
+
req.headers["Content-Type"] = 'application/json' unless req.headers
|
195
|
+
block.call(req)
|
196
|
+
end
|
197
|
+
else
|
198
|
+
http.send(method, url, query_opts, *args)
|
199
|
+
end
|
200
|
+
})
|
201
|
+
end
|
202
|
+
|
203
|
+
# Internal use only
|
204
|
+
# Check response codes from request
|
205
|
+
def check_response(res)
|
185
206
|
if res.status >= 200 && res.status <= 299
|
186
207
|
res.body
|
187
208
|
elsif [404, 410].include? res.status
|
data/lib/stretcher/version.rb
CHANGED
@@ -69,55 +69,71 @@ describe Stretcher::IndexType do
|
|
69
69
|
end
|
70
70
|
end
|
71
71
|
|
72
|
-
describe "
|
72
|
+
describe "ops on individual docs" do
|
73
73
|
before do
|
74
74
|
@doc = {:message => "hello!", :_timestamp => 1366420401}
|
75
75
|
@put_res = type.put(987, @doc)
|
76
76
|
end
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
77
|
+
|
78
|
+
describe "put" do
|
79
|
+
it "should put correctly" do
|
80
|
+
@put_res.should_not be_nil
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should post correctly" do
|
84
|
+
type.post(@doc).should_not be_nil
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
describe "get" do
|
89
|
+
it "should get individual documents correctly" do
|
90
|
+
type.get(987).message.should == @doc[:message]
|
91
|
+
end
|
92
|
+
|
93
|
+
it "should return nil when retrieving non-extant docs" do
|
94
|
+
lambda {
|
95
|
+
type.get(898323329)
|
96
|
+
}.should raise_exception(Stretcher::RequestError::NotFound)
|
97
|
+
end
|
98
|
+
|
99
|
+
it "should get individual fields given a String, passing through additional options" do
|
100
|
+
res = type.get(987, {:fields => '_timestamp'})
|
101
|
+
res._timestamp.should == @doc[:_timestamp]
|
102
|
+
res.message.should == nil
|
103
|
+
end
|
104
|
+
|
105
|
+
it "should get individual fields given an Array, passing through additional options" do
|
106
|
+
res = type.get(987, {:fields => ['_timestamp']})
|
107
|
+
res._timestamp.should == @doc[:_timestamp]
|
108
|
+
res.message.should == nil
|
109
|
+
end
|
110
|
+
|
111
|
+
it "should have source and other fields accessible when raw=true" do
|
112
|
+
res = type.get(987, {:fields => ['_timestamp', '_source']}, true)
|
113
|
+
res._source.message == @doc[:message]
|
114
|
+
res.fields._timestamp.should == @doc[:_timestamp]
|
115
|
+
end
|
116
|
+
|
117
|
+
it "should get individual raw documents correctly" do
|
118
|
+
res = type.get(987, {}, true)
|
119
|
+
res["_id"].should == "987"
|
120
|
+
res["_source"].message.should == @doc[:message]
|
121
|
+
end
|
122
|
+
|
123
|
+
it "should get individual raw documents correctly with legacy API" do
|
124
|
+
res = type.get(987, true)
|
125
|
+
res["_id"].should == "987"
|
126
|
+
res["_source"].message.should == @doc[:message]
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
114
130
|
it "should explain a query" do
|
115
131
|
type.exists?(987).should be_true
|
116
132
|
index.refresh
|
117
133
|
res = type.explain(987, {:query => {:match_all => {}}})
|
118
134
|
res.should have_key('explanation')
|
119
135
|
end
|
120
|
-
|
136
|
+
|
121
137
|
it "should update individual docs correctly" do
|
122
138
|
type.update(987, :script => "ctx._source.message = 'Updated!'")
|
123
139
|
type.get(987).message.should == 'Updated!'
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: stretcher
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.13.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-05
|
12
|
+
date: 2013-06-05 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: faraday
|