ruby-druid 0.10.0 → 0.10.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ef87663c236bf89b7937fef4c7709d3937e5f0e6
4
- data.tar.gz: 82d29a256a0cebc175aeb9d88173f1455e9a8475
3
+ metadata.gz: 62a8990d73fd742e2fbe2eb50bea8e6867d86e76
4
+ data.tar.gz: 5e17079e581ecce9e6a013b3e1dd44c25b8c2555
5
5
  SHA512:
6
- metadata.gz: a81d42c823310788cf35fcde9c683674fd863ea3f71557d1ab0e3c01d21f66cdeedd601a816deced10367b27db19d625fc19803d6463bfdaea3aa42f063f8875
7
- data.tar.gz: 1a0c049e54420fc1c6773e489cbef4a118f751f4e5c9172377ace9474173dab10cba6d41253056e305e5c4156c02cc8594814f1138852ad7806272c249532583
6
+ metadata.gz: d08040c0aefb284858e323275fc86c18c7f99290f4463e6c309f172efa7086c43ff56d06869fe70c9563be423b86f6243ef203db06dcbaa9e4ade5515ff5328c
7
+ data.tar.gz: 3dcf38b1a373577940f2de02e44bf14252e09fc7a2c760f5c8be6d7d1e6b09c2f80412e4341491708759250e306ecf62ce8f5986db5468d5c87e6cd4a69db830
data/README.md CHANGED
@@ -29,32 +29,22 @@ gem install ruby-druid
29
29
 
30
30
  ## Usage
31
31
 
32
- ```ruby
33
- Druid::Client.new('zk1:2181,zk2:2181/druid').query('service/source')
34
- ```
35
-
36
- returns a query object on which all other methods can be called to create a full and valid Druid query.
37
-
38
- A query object can be sent like this:
32
+ A query can be constructed and sent like so:
39
33
 
40
34
  ```ruby
41
- client = Druid::Client.new('zk1:2181,zk2:2181/druid')
42
- query = Druid::Query.new('service/source')
43
- client.send(query)
35
+ data_source = Druid::Client.new('zk1:2181,zk2:2181/druid').data_source('service/source')
36
+ query = Druid::Query::Builder.new.long_sum(:aggregate1).last(1.day).granularity(:all)
37
+ result = data_source.post(query)
44
38
  ```
45
39
 
46
- The `send` method returns the parsed response from the druid server as an array. If the response is not empty it contains one `ResponseRow` object for each row. The timestamp by can be received by a method with the same name (i.e. `row.timestamp`), all row values by hashlike syntax (i.e. `row['dimension'])
40
+ The `post` method on the `DataSource` returns the parsed response from the Druid server as an array.
47
41
 
48
- An options hash can be passed when creating `Druid::Client` instance:
42
+ If you don't want to use ZooKeeper for broker discovery, you can explicitly construct a `DataSource`:
49
43
 
50
44
  ```ruby
51
- client = Druid::Client.new('zk1:2181,zk2:2181/druid', http_timeout: 20)
45
+ data_source = Druid::DataSource.new('service/source', 'http://localhost:8080/druid/v2')
52
46
  ```
53
47
 
54
- Supported options are:
55
- * `static_setup` to explicitly specify a broker url, e.g. `static_setup: { 'my/source_name' => 'http://1.2.3.4:8080/druid/v2/' }`
56
- * `http_timeout` to define a timeout for sending http queries to a broker (in minutes, default value is 2)
57
-
58
48
  ### GroupBy
59
49
 
60
50
  A [GroupByQuery](http://druid.io/docs/latest/querying/groupbyquery.html) sets the
@@ -63,7 +53,7 @@ dimensions to group the data.
63
53
  `queryType` is set automatically to `groupBy`.
64
54
 
65
55
  ```ruby
66
- Druid::Query.new('service/source').group_by([:dimension1, :dimension2])
56
+ Druid::Query::Builder.new.group_by([:dimension1, :dimension2])
67
57
  ```
68
58
 
69
59
  ### TimeSeries
@@ -71,7 +61,7 @@ Druid::Query.new('service/source').group_by([:dimension1, :dimension2])
71
61
  A [TimeSeriesQuery](http://druid.io/docs/latest/querying/timeseriesquery.html) returns an array of JSON objects where each object represents a value asked for by the timeseries query.
72
62
 
73
63
  ```ruby
74
- Druid::Query.new('service/source').time_series([:aggregate1, :aggregate2])
64
+ Druid::Query::Builder.new.time_series([:aggregate1, :aggregate2])
75
65
  ```
76
66
 
77
67
  ### Aggregations
@@ -79,7 +69,7 @@ Druid::Query.new('service/source').time_series([:aggregate1, :aggregate2])
79
69
  #### longSum, doubleSum, count, min, max, hyperUnique
80
70
 
81
71
  ```ruby
82
- Druid::Query.new('service/source').long_sum([:aggregate1, :aggregate2])
72
+ Druid::Query::Builder.new.long_sum([:aggregate1, :aggregate2])
83
73
  ```
84
74
 
85
75
  In the same way could be used the following methods for [aggregations](http://druid.io/docs/latest/querying/aggregations.html) adding: `double_sum, count, min, max, hyper_unique`
@@ -87,7 +77,7 @@ In the same way could be used the following methods for [aggregations](http://dr
87
77
  #### cardinality
88
78
 
89
79
  ```ruby
90
- Druid::Query.new('service/source').cardinality(:aggregate, [:dimension1, dimension2], <by_row: true | false>)
80
+ Druid::Query::Builder.new.cardinality(:aggregate, [:dimension1, dimension2], <by_row: true | false>)
91
81
  ```
92
82
 
93
83
  #### javascript
@@ -95,7 +85,7 @@ Druid::Query.new('service/source').cardinality(:aggregate, [:dimension1, dimensi
95
85
  For example calculation for `sum(log(x)/y) + 10`:
96
86
 
97
87
  ```ruby
98
- Druid::Query.new('service/source').js_aggregation(:aggregate, [:x, :y],
88
+ Druid::Query::Builder.new.js_aggregation(:aggregate, [:x, :y],
99
89
  aggregate: "function(current, a, b) { return current + (Math.log(a) * b); }",
100
90
  combine: "function(partialA, partialB) { return partialA + partialB; }",
101
91
  reset: "function() { return 10; }"
@@ -107,7 +97,7 @@ Druid::Query.new('service/source').js_aggregation(:aggregate, [:x, :y],
107
97
  A simple syntax for post aggregations with +,-,/,* can be used like:
108
98
 
109
99
  ```ruby
110
- query = Druid::Query.new('service/source').long_sum([:aggregate1, :aggregate2])
100
+ query = Druid::Query::Builder.new.long_sum([:aggregate1, :aggregate2])
111
101
  query.postagg { (aggregate2 + aggregate2).as output_field_name }
112
102
  ```
113
103
 
@@ -124,7 +114,7 @@ query.postagg { js('function(aggregate1, aggregate2) { return aggregate1 + aggre
124
114
  The interval for the query takes a string with date and time or objects that provide an `iso8601` method.
125
115
 
126
116
  ```ruby
127
- query = Druid::Query.new('service/source').long_sum(:aggregate1)
117
+ query = Druid::Query::Builder.new.long_sum(:aggregate1)
128
118
  query.interval("2013-01-01T00", Time.now)
129
119
  ```
130
120
 
@@ -139,14 +129,14 @@ The period `'day'` or `:day` will be interpreted as `'P1D'`.
139
129
  If a period granularity is specifed, the (optional) second parameter is a time zone. It defaults to the machines local time zone. i.e.
140
130
 
141
131
  ```ruby
142
- query = Druid::Query.new('service/source').long_sum(:aggregate1)
132
+ query = Druid::Query::Builder.new.long_sum(:aggregate1)
143
133
  query.granularity(:day)
144
134
  ```
145
135
 
146
136
  is (on my box) the same as
147
137
 
148
138
  ```ruby
149
- query = Druid::Query.new('service/source').long_sum(:aggregate1)
139
+ query = Druid::Query::Builder.new.long_sum(:aggregate1)
150
140
  query.granularity('P1D', 'Europe/Berlin')
151
141
  ```
152
142
 
@@ -154,18 +144,18 @@ query.granularity('P1D', 'Europe/Berlin')
154
144
 
155
145
  ```ruby
156
146
  # equality
157
- Druid::Query.new('service/source').having { metric == 10 }
147
+ Druid::Query::Builder.new.having { metric == 10 }
158
148
  ```
159
149
 
160
150
  ```ruby
161
151
  # inequality
162
- Druid::Query.new('service/source').having { metric != 10 }
152
+ Druid::Query::Builder.new.having { metric != 10 }
163
153
  ```
164
154
 
165
155
  ```ruby
166
156
  # greater, less
167
- Druid::Query.new('service/source').having { metric > 10 }
168
- Druid::Query.new('service/source').having { metric < 10 }
157
+ Druid::Query::Builder.new.having { metric > 10 }
158
+ Druid::Query::Builder.new.having { metric < 10 }
169
159
  ```
170
160
 
171
161
  #### Compound having filters
@@ -174,17 +164,17 @@ Having filters can be combined with boolean logic.
174
164
 
175
165
  ```ruby
176
166
  # and
177
- Druid::Query.new('service/source').having { (metric != 1) & (metric2 != 2) }
167
+ Druid::Query::Builder.new.having { (metric != 1) & (metric2 != 2) }
178
168
  ```
179
169
 
180
170
  ```ruby
181
171
  # or
182
- Druid::Query.new('service/source').having { (metric == 1) | (metric2 == 2) }
172
+ Druid::Query::Builder.new.having { (metric == 1) | (metric2 == 2) }
183
173
  ```
184
174
 
185
175
  ```ruby
186
176
  # not
187
- Druid::Query.new('service/source').having{ !metric.eq(1) }
177
+ Druid::Query::Builder.new.having{ !metric.eq(1) }
188
178
  ```
189
179
 
190
180
  ### Filters
@@ -197,27 +187,27 @@ Filters can be chained `filter{...}.filter{...}`
197
187
 
198
188
  ```ruby
199
189
  # equality
200
- Druid::Query.new('service/source').filter{dimension.eq 1}
201
- Druid::Query.new('service/source').filter{dimension == 1}
190
+ Druid::Query::Builder.new.filter{dimension.eq 1}
191
+ Druid::Query::Builder.new.filter{dimension == 1}
202
192
  ```
203
193
 
204
194
  ```ruby
205
195
  # inequality
206
- Druid::Query.new('service/source').filter{dimension.neq 1}
207
- Druid::Query.new('service/source').filter{dimension != 1}
196
+ Druid::Query::Builder.new.filter{dimension.neq 1}
197
+ Druid::Query::Builder.new.filter{dimension != 1}
208
198
  ```
209
199
 
210
200
  ```ruby
211
201
  # greater, less
212
- Druid::Query.new('service/source').filter{dimension > 1}
213
- Druid::Query.new('service/source').filter{dimension >= 1}
214
- Druid::Query.new('service/source').filter{dimension < 1}
215
- Druid::Query.new('service/source').filter{dimension <= 1}
202
+ Druid::Query::Builder.new.filter{dimension > 1}
203
+ Druid::Query::Builder.new.filter{dimension >= 1}
204
+ Druid::Query::Builder.new.filter{dimension < 1}
205
+ Druid::Query::Builder.new.filter{dimension <= 1}
216
206
  ```
217
207
 
218
208
  ```ruby
219
209
  # JavaScript
220
- Druid::Query.new('service/source').filter{a.javascript('dimension >= 1 && dimension < 5')}
210
+ Druid::Query::Builder.new.filter{a.javascript('dimension >= 1 && dimension < 5')}
221
211
  ```
222
212
 
223
213
  #### Compound Filters
@@ -226,17 +216,17 @@ Filters can be combined with boolean logic.
226
216
 
227
217
  ```ruby
228
218
  # and
229
- Druid::Query.new('service/source').filter{dimension.neq 1 & dimension2.neq 2}
219
+ Druid::Query::Builder.new.filter{dimension.neq 1 & dimension2.neq 2}
230
220
  ```
231
221
 
232
222
  ```ruby
233
223
  # or
234
- Druid::Query.new('service/source').filter{dimension.neq 1 | dimension2.neq 2}
224
+ Druid::Query::Builder.new.filter{dimension.neq 1 | dimension2.neq 2}
235
225
  ```
236
226
 
237
227
  ```ruby
238
228
  # not
239
- Druid::Query.new('service/source').filter{!dimension.eq(1)}
229
+ Druid::Query::Builder.new.filter{!dimension.eq(1)}
240
230
  ```
241
231
 
242
232
  #### Inclusion Filter
@@ -244,18 +234,18 @@ Druid::Query.new('service/source').filter{!dimension.eq(1)}
244
234
  This filter creates a set of equals filters in an or filter.
245
235
 
246
236
  ```ruby
247
- Druid::Query.new('service/source').filter{dimension.in(1,2,3)}
237
+ Druid::Query::Builder.new.filter{dimension.in(1,2,3)}
248
238
  ```
249
239
  #### Geographic filter
250
240
 
251
241
  These filters have to be combined with time_series and do only work when coordinates is a spatial dimension [GeographicQueries](http://druid.io/docs/latest/development/geo.html)
252
242
 
253
243
  ```ruby
254
- Druid::Query.new('service/source').time_series().long_sum([:aggregate1]).filter{coordinates.in_rec [[50.0,13.0],[54.0,15.0]]}
244
+ Druid::Query::Builder.new.time_series().long_sum([:aggregate1]).filter{coordinates.in_rec [[50.0,13.0],[54.0,15.0]]}
255
245
  ```
256
246
 
257
247
  ```ruby
258
- Druid::Query.new('service/source').time_series().long_sum([:aggregate1]).filter{coordinates.in_circ [[53.0,13.0], 5.0]}
248
+ Druid::Query::Builder.new.time_series().long_sum([:aggregate1]).filter{coordinates.in_circ [[53.0,13.0], 5.0]}
259
249
  ```
260
250
 
261
251
  #### Exclusion Filter
@@ -263,7 +253,7 @@ Druid::Query.new('service/source').time_series().long_sum([:aggregate1]).filter{
263
253
  This filter creates a set of not-equals fitlers in an and filter.
264
254
 
265
255
  ```ruby
266
- Druid::Query.new('service/source').filter{dimension.nin(1,2,3)}
256
+ Druid::Query::Builder.new.filter{dimension.nin(1,2,3)}
267
257
  ```
268
258
 
269
259
  #### Hash syntax
@@ -271,9 +261,9 @@ Druid::Query.new('service/source').filter{dimension.nin(1,2,3)}
271
261
  Sometimes it can be useful to use a hash syntax for filtering for example if you already get them from a list or parameter hash.
272
262
 
273
263
  ```ruby
274
- Druid::Query.new('service/source').filter{dimension => 1, dimension1 =>2, dimension2 => 3}
264
+ Druid::Query::Builder.new.filter{dimension => 1, dimension1 =>2, dimension2 => 3}
275
265
  # which is equivalent to
276
- Druid::Query.new('service/source').filter{dimension.eq(1) & dimension1.eq(2) & dimension2.eq(3)}
266
+ Druid::Query::Builder.new.filter{dimension.eq(1) & dimension1.eq(2) & dimension2.eq(3)}
277
267
  ```
278
268
 
279
269
  ## Contributing
@@ -74,22 +74,49 @@ module Druid
74
74
  return self.post(query)
75
75
  end
76
76
 
77
- raise Error.new(response), "request failed"
77
+ raise Error.new(response)
78
78
  end
79
79
 
80
80
  MultiJson.load(response.body)
81
81
  end
82
82
 
83
83
  class Error < StandardError
84
- attr_reader :response
84
+ attr_reader :error, :error_message, :error_class, :host, :response
85
+
85
86
  def initialize(response)
86
87
  @response = response
88
+ parsed_body = MultiJson.load(response.body)
89
+ @error, @error_message, @error_class, @host = parsed_body.values_at(*%w(
90
+ error
91
+ errorMessage
92
+ errorClass
93
+ host
94
+ ))
87
95
  end
88
96
 
89
97
  def message
90
- MultiJson.load(response.body)["error"]
98
+ error
99
+ end
100
+
101
+ def query_timeout?
102
+ error == 'Query timeout'.freeze
103
+ end
104
+
105
+ def query_interrupted?
106
+ error == 'Query interrupted'.freeze
91
107
  end
92
- end
93
108
 
109
+ def query_cancelled?
110
+ error == 'Query cancelled'.freeze
111
+ end
112
+
113
+ def resource_limit_exceeded?
114
+ error == 'Resource limit exceeded'.freeze
115
+ end
116
+
117
+ def unknown_exception?
118
+ error == 'Unknown exception'.freeze
119
+ end
120
+ end
94
121
  end
95
122
  end
@@ -37,11 +37,11 @@ module Druid
37
37
  super(options.merge(except: %w(errors validation_context)))
38
38
  end
39
39
 
40
- def self.lookup(dimension, namespace, retain: true, injective: false)
40
+ def self.lookup(dimension, namespace, outputName: nil, retain: true, injective: false)
41
41
  new({
42
42
  type: 'extraction',
43
43
  dimension: dimension,
44
- outputName: dimension,
44
+ outputName: outputName || namespace,
45
45
  extractionFn: {
46
46
  type: 'registeredLookup',
47
47
  lookup: namespace,
@@ -365,7 +365,7 @@ module Druid
365
365
 
366
366
  def group_by(*dimensions)
367
367
  query_type(:groupBy)
368
- @query.dimensions = dimensions.map do |dimension|
368
+ @query.dimensions = dimensions.flatten.map do |dimension|
369
369
  dimension.is_a?(Dimension) ? dimension : Dimension.new(dimension)
370
370
  end
371
371
  self
@@ -1,3 +1,3 @@
1
1
  module Druid
2
- VERSION = "0.10.0"
2
+ VERSION = '0.10.1'
3
3
  end
@@ -19,20 +19,35 @@ describe Druid::DataSource do
19
19
  end
20
20
 
21
21
  it 'raises on request failure' do
22
- # MRI
23
- stub_request(:post, 'http://www.example.com/druid/v2').
24
- with(:body => "{\"context\":{\"queryId\":null},\"queryType\":\"timeseries\",\"intervals\":[\"2013-04-04T00:00:00+00:00/2013-04-04T00:00:00+00:00\"],\"granularity\":\"all\",\"dataSource\":\"test\"}",
25
- :headers => { 'Accept' => '*/*', 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Content-Type' => 'application/json', 'User-Agent' => 'Ruby' }).
26
- to_return(:status => 666, :body => 'Strange server error', :headers => {})
27
- # JRuby ... *sigh
28
- stub_request(:post, 'http://www.example.com/druid/v2').
29
- with(:body => "{\"context\":{\"queryId\":null},\"granularity\":\"all\",\"intervals\":[\"2013-04-04T00:00:00+00:00/2013-04-04T00:00:00+00:00\"],\"queryType\":\"timeseries\",\"dataSource\":\"test\"}",
30
- :headers => { 'Accept' => '*/*', 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Content-Type' => 'application/json', 'User-Agent' => 'Ruby' }).
31
- to_return(:status => 666, :body => 'Strange server error', :headers => {})
22
+ stub_request(:post, 'http://www.example.com/druid/v2')
23
+ .with(
24
+ :body => %q({"context":{"queryId":null},"queryType":"timeseries","intervals":["2013-04-04T00:00:00+00:00/2013-04-04T00:00:00+00:00"],"granularity":"all","dataSource":"test"}),
25
+ :headers => {
26
+ 'Accept' => '*/*',
27
+ 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
28
+ 'Content-Type' => 'application/json',
29
+ 'User-Agent' => 'Ruby',
30
+ }
31
+ )
32
+ .to_return(
33
+ :status => 500,
34
+ :body => %q({"error":"Unknown exception","errorMessage":"NullPointerException","errorClass":"java.lang.NullPointerException","host":"www.example.com"}),
35
+ :headers => {},
36
+ )
37
+
32
38
  ds = Druid::DataSource.new('test/test', 'http://www.example.com/druid/v2')
33
39
  query = Druid::Query::Builder.new.interval('2013-04-04', '2013-04-04').granularity(:all).query
34
40
  query.context.queryId = nil
35
- expect { ds.post(query) }.to raise_error(Druid::DataSource::Error)
41
+
42
+ expect { ds.post(query) }.to raise_error { |error|
43
+ expect(error).to be_a(Druid::DataSource::Error)
44
+ expect(error.message).to eq(error.error)
45
+ expect(error.error).to eq('Unknown exception')
46
+ expect(error.error_message).to eq('NullPointerException')
47
+ expect(error.error_class).to eq('java.lang.NullPointerException')
48
+ expect(error.host).to eq('www.example.com')
49
+ expect(error).to be_unknown_exception
50
+ }
36
51
  end
37
52
  end
38
53
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-druid
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.0
4
+ version: 0.10.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ruby Druid Community
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-10-14 00:00:00.000000000 Z
11
+ date: 2018-02-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -211,13 +211,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement
211
211
  version: '0'
212
212
  requirements: []
213
213
  rubyforge_project:
214
- rubygems_version: 2.4.8
214
+ rubygems_version: 2.6.11
215
215
  signing_key:
216
216
  specification_version: 4
217
217
  summary: A Ruby client for Druid
218
218
  test_files:
219
219
  - spec/spec_helper.rb
220
220
  - spec/lib/client_spec.rb
221
- - spec/lib/data_source_spec.rb
222
221
  - spec/lib/zk_spec.rb
222
+ - spec/lib/data_source_spec.rb
223
223
  - spec/lib/query_spec.rb