stretcher 1.12.0 → 1.13.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.
- 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
|