orchestrate 0.10.0 → 0.11.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +138 -10
- data/lib/orchestrate/api/response.rb +4 -0
- data/lib/orchestrate/collection.rb +8 -110
- data/lib/orchestrate/search/aggregate_builder.rb +290 -0
- data/lib/orchestrate/search/query_builder.rb +83 -0
- data/lib/orchestrate/search/results.rb +215 -0
- data/lib/orchestrate/search.rb +10 -0
- data/lib/orchestrate/version.rb +1 -1
- data/lib/orchestrate.rb +1 -0
- data/orchestrate.gemspec +14 -14
- data/test/orchestrate/collection_aggregates_test.rb +118 -0
- data/test/orchestrate/collection_geo_queries_test.rb +5 -5
- data/test/orchestrate/collection_searching_test.rb +9 -10
- data/test/orchestrate/collection_sorting_test.rb +4 -4
- metadata +32 -24
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 052b46ffb077d9256c3626b2d2fe1d6618c0f3c9
|
4
|
+
data.tar.gz: 34375247e7fc3ce08d2f836df6e0df7f778273f7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 99d0edff2baf770cf3c2173c9245bb42957dee1a92c1d4abca2c24bc8b510569bf6bda09159c2761bbd64d9631cdfd1d2273166597dccb11a12f85c1a110fb3d
|
7
|
+
data.tar.gz: 6afa7091564272f7f22d0b4d173b03cd76815a63992876aaccadd3b1c08ab11a38a6c20e884e2feafcf8e339651f0bf0b623339927de6a7e6b1e8c5fd27f39a3
|
data/README.md
CHANGED
@@ -65,20 +65,20 @@ jill.add('favorite_food', 'Pizza').remove('years_to_live').update()
|
|
65
65
|
|
66
66
|
#### Searching, Sorting for KeyValues
|
67
67
|
```ruby
|
68
|
-
users.search("name:Jill")
|
69
|
-
users.search("name:Jill").order(:created_at)
|
68
|
+
users.search("name:Jill").find # returns users with name "Jill"
|
69
|
+
users.search("name:Jill").order(:created_at).find # returns users with name "Jill" in ascending order
|
70
70
|
```
|
71
71
|
|
72
72
|
The `order` method accepts multiple arguments, allowing you to sort search results based multiple parameters. When providing multiple field names to sort by each even-numbered argument must be either `:asc` or `:desc`.
|
73
73
|
|
74
74
|
```ruby
|
75
|
-
users.search("location: Portland").order(:name, :asc, :rank, :desc)
|
75
|
+
users.search("location: Portland").order(:name, :asc, :rank, :desc).find
|
76
76
|
```
|
77
77
|
|
78
78
|
By default, odd-numbered arguments will be sorted in ascending order.
|
79
79
|
```ruby
|
80
|
-
users.search("location: Portland").order(:name)
|
81
|
-
users.search("location: Portland").order(:name, :asc, :rank, :desc, :created_at)
|
80
|
+
users.search("location: Portland").order(:name).find # returns users in ascending order by name
|
81
|
+
users.search("location: Portland").order(:name, :asc, :rank, :desc, :created_at).find # :created_at argument defaults to :asc
|
82
82
|
```
|
83
83
|
|
84
84
|
### Geo Queries
|
@@ -87,13 +87,56 @@ users.search("location: Portland").order(:name, :asc, :rank, :desc, :created_at)
|
|
87
87
|
cafes = app[:cafes]
|
88
88
|
|
89
89
|
# Find cafes near a given geographic point
|
90
|
-
cafes.near(:location, 12.56, 19.443, 4, 'mi') # returns cafes in a 4 mile radius of given latitude, longitude
|
90
|
+
cafes.near(:location, 12.56, 19.443, 4, 'mi').find # returns cafes in a 4 mile radius of given latitude, longitude
|
91
91
|
|
92
92
|
# Sort nearby cafes by distance
|
93
|
-
cafes.near(:location, 12.56, 19.443, 4, 'mi').order(:distance) # returns nearby cafes in ascending order (closest to farthest)
|
93
|
+
cafes.near(:location, 12.56, 19.443, 4, 'mi').order(:distance).find # returns nearby cafes in ascending order (closest to farthest)
|
94
94
|
|
95
95
|
# Find cafes in a given area using a bounding box
|
96
|
-
cafes.in(:location, {north:12.5, east:57, south:12, west:56}) # returns all cafes within specified bounding box
|
96
|
+
cafes.in(:location, {north:12.5, east:57, south:12, west:56}).find # returns all cafes within specified bounding box
|
97
|
+
```
|
98
|
+
|
99
|
+
### Aggregate Functions
|
100
|
+
|
101
|
+
```ruby
|
102
|
+
# Statistical Aggregate
|
103
|
+
products.search("*").aggregate # Start the search query and aggregate param builder
|
104
|
+
.stats("price") # statistics on the price field for products matching the query
|
105
|
+
.find # return SearchResults object to execute our query
|
106
|
+
.each_aggregate # return enumerator for iterating over each aggregate result
|
107
|
+
|
108
|
+
# Range Aggregate
|
109
|
+
products.search("*").aggregate # Start the search query and aggregate param builder
|
110
|
+
.range("num_sold") # set field for range function
|
111
|
+
.below(99) # count items with num_sold value below 99
|
112
|
+
.between(1, 10) # count items with num_sold value between 1 & 10
|
113
|
+
.above(5) # count items with num_sold value above 5
|
114
|
+
.find # return SearchResults object to execute our query
|
115
|
+
.each_aggregate # return enumerator for iterating over each aggregate result
|
116
|
+
|
117
|
+
# Distance Aggregate
|
118
|
+
cafes.near(:location, 12, 19, 4, 'mi').aggregate # Start the near search query and aggregate param builder
|
119
|
+
.distance("location") # set field for distance function
|
120
|
+
.below(3) # count cafes within 3 miles of given geographic point
|
121
|
+
.between(3, 4) # count cafes between 3 and 4 miles of given geographic point
|
122
|
+
.above(1) # count cafes beyond 1 mile of given geographic point
|
123
|
+
.find # return SearchResults object to execute our query
|
124
|
+
.each_aggregate # return enumerator for iterating over each aggregate result
|
125
|
+
|
126
|
+
# Time-Series Aggregate
|
127
|
+
# Accepted intervals are: year, quarter, month, week, day, and hour
|
128
|
+
comments.search("*").aggregate # Start the near search query and aggregate param builder
|
129
|
+
.time_series("posted", "day") # get count of comments posted by day
|
130
|
+
.find # return SearchResults object to execute our query
|
131
|
+
.each_aggregate # return enumerator for iterating over each aggregate result
|
132
|
+
|
133
|
+
# Multiple Aggregate Functions
|
134
|
+
products.search("*").aggregate # Start the search query and aggregate param builder
|
135
|
+
.stats("price") # statistics on the price field for products matching the query
|
136
|
+
.range("num_sold") # set field for range function
|
137
|
+
.below(99) # count items with num_sold value below 99
|
138
|
+
.find # return SearchResults object to execute our query
|
139
|
+
.each_aggregate # return enumerator for iterating over each aggregate result
|
97
140
|
```
|
98
141
|
|
99
142
|
### Method Client use
|
@@ -173,6 +216,82 @@ query = "value:IN:{ north:12.5 east:57 south:12 west:56 }"
|
|
173
216
|
client.search(:cafes, query)
|
174
217
|
```
|
175
218
|
|
219
|
+
### Aggregate Functions
|
220
|
+
|
221
|
+
```ruby
|
222
|
+
# Statistical Aggregate
|
223
|
+
query = "*"
|
224
|
+
|
225
|
+
options = {
|
226
|
+
aggregate: "value.price:stats" # get statistics for price across all items in the collection
|
227
|
+
}
|
228
|
+
|
229
|
+
response = client.search(:products, query, options)
|
230
|
+
|
231
|
+
response.aggregates # return aggregate results
|
232
|
+
|
233
|
+
|
234
|
+
# Range Aggregate
|
235
|
+
query = "*"
|
236
|
+
|
237
|
+
options = {
|
238
|
+
# count items with num_sold below 99, in between 1 & 10, and above 5
|
239
|
+
aggregate: "value.num_sold:range:*~99:1~10:5~*"
|
240
|
+
}
|
241
|
+
|
242
|
+
response = client.search(:products, query, options)
|
243
|
+
|
244
|
+
response.aggregates # return aggregate results
|
245
|
+
|
246
|
+
|
247
|
+
# Distance Aggregate
|
248
|
+
coords = {
|
249
|
+
lat: 12.56,
|
250
|
+
lon: 19.443,
|
251
|
+
dist: '4mi' # Define size of search radius for NEAR query
|
252
|
+
}
|
253
|
+
|
254
|
+
options = {
|
255
|
+
# count cafes near give geographic point within 3 miles, between 3 and 4 miles, and beyond 1 mile
|
256
|
+
aggregate: "value.location:distance:*~3:3~4:1~*"
|
257
|
+
}
|
258
|
+
|
259
|
+
# Distance Aggregates require a near clause in the search query
|
260
|
+
query = "value.location:NEAR:{lat:#{coords.lat} lon:#{coords.lon} dist:#{coords.dist}}"
|
261
|
+
|
262
|
+
response = client.search(:cafes, query, options)
|
263
|
+
|
264
|
+
response.aggregates # return aggregate results
|
265
|
+
|
266
|
+
|
267
|
+
# Time-Series Aggregate
|
268
|
+
# Accepted intervals are: year, quarter, month, week, day, and hour
|
269
|
+
|
270
|
+
options = {
|
271
|
+
# get count of comments posted by day
|
272
|
+
aggregate: "value.posted:time_series:day"
|
273
|
+
}
|
274
|
+
|
275
|
+
query = "*"
|
276
|
+
|
277
|
+
response = client.search(:comments, query, options)
|
278
|
+
|
279
|
+
response.aggregates # return aggregate results
|
280
|
+
|
281
|
+
|
282
|
+
# Multiple Aggregate Functions
|
283
|
+
options = {
|
284
|
+
# multiple aggregate params are separated by commas
|
285
|
+
aggregate: "value.price:stats,value.num_sold:stats,value.num_sold:range:*~99:1~10:5~*"
|
286
|
+
}
|
287
|
+
|
288
|
+
query = "*"
|
289
|
+
|
290
|
+
response = client.search(:products, query, options)
|
291
|
+
|
292
|
+
response.aggregates # return aggregate results
|
293
|
+
```
|
294
|
+
|
176
295
|
### Examples and Documentation
|
177
296
|
|
178
297
|
There are more examples at [Orchestrate's API Documentation][apidoc] and documentation in the [rdoc][].
|
@@ -277,10 +396,19 @@ end
|
|
277
396
|
|
278
397
|
## Release Notes
|
279
398
|
|
399
|
+
### January 7, 2014: release 0.11.0
|
400
|
+
- **BACKWARDS-INCOMPATIBLE** `Orchestrate::Collection` searches require `#find` method at the end of the method call/chain. Example: `users.search('foo').find`.
|
401
|
+
- Implement `Orchestrate::Search` module, refactor functionality of prior `Orchestrate::Collection::SearchResults`.
|
402
|
+
- Implement results enumeration & request firing functionality in prior `Orchestrate::Collection::SearchResults` to `Orchestrate::Search::Results`
|
403
|
+
- Implement `Search::QueryBuilder` to construct `Collection` search queries.
|
404
|
+
- Implement `Search::AggregateBuilder` to construct aggregate params on `Collection` search queries.
|
405
|
+
- Implement `Search::StatsBuilder`, `Search::RangeBuilder`, `Search::DistanceBuilder`, & `Search::TimeSeriesBuilder` to construct aggregate function clauses for aggregate params.
|
406
|
+
- Implement `Search::AggregateResult` objects to repesent aggregate results returned from `Collection` search.
|
407
|
+
|
280
408
|
### December 11, 2014: release 0.10.0
|
281
409
|
- **BACKWARDS-INCOMPATIBLE** Prior `KeyValue#update` & `KeyValue#update!` renamed to `KeyValue#set` & `KeyValue#set!`. `KeyValue#update` now used after `PATCH` operations to fire the request.
|
282
410
|
- Implement `Collection#near` & `Collection#in`, allowing `Collection` to perform geo queries.
|
283
|
-
- Implement `Client#patch`, `Client#patch_merge`, allowing `Client` to perform
|
411
|
+
- Implement `Client#patch`, `Client#patch_merge`, allowing `Client` to perform partial updates through `PATCH` requests.
|
284
412
|
- Implement `KeyValue::OperationSet`, allowing a set of `PATCH` operations to be built by `KeyValue` through `KeyValue#add`, `KeyValue#remove`, `KeyValue#replace`, `KeyValue#move`, `KeyValue#copy`, `KeyValue#increment`, `KeyValue#decrement`, & `KeyValue#test`. The `KeyValue::OperationSet` is fired by ending the chain with `KeyValue#update`.
|
285
413
|
- Implement `KeyValue#merge`, allowing `KeyValue` to merge partial values into existing keys through `PATCH` requests.
|
286
414
|
|
@@ -346,4 +474,4 @@ end
|
|
346
474
|
### May 21, 2014: release 0.5.0
|
347
475
|
Initial Port from @jimcar
|
348
476
|
- Uses Faraday HTTP Library as backend, with examples of alternate adapters
|
349
|
-
- Cleanup client method signatures
|
477
|
+
- Cleanup client method signatures
|
@@ -109,6 +109,9 @@ module Orchestrate::API
|
|
109
109
|
# @return [Array] The items in the response.
|
110
110
|
attr_reader :results
|
111
111
|
|
112
|
+
# @return [Array] The aggregate items in the response.
|
113
|
+
attr_reader :aggregates
|
114
|
+
|
112
115
|
# @return [String] The location for the next page of results
|
113
116
|
attr_reader :next_link
|
114
117
|
|
@@ -122,6 +125,7 @@ module Orchestrate::API
|
|
122
125
|
@count = body['count']
|
123
126
|
@total_count = body['total_count']
|
124
127
|
@results = body['results']
|
128
|
+
@aggregates = body['aggregates']
|
125
129
|
@next_link = body['next']
|
126
130
|
@prev_link = body['prev']
|
127
131
|
end
|
@@ -345,17 +345,13 @@ module Orchestrate
|
|
345
345
|
end
|
346
346
|
end
|
347
347
|
|
348
|
-
# @!group Searching
|
349
|
-
# [Search the items in a collection](http://orchestrate.io/docs/api/#search) using a Lucene
|
350
|
-
# Query Syntax.
|
351
348
|
# @param query [#to_s] The [Lucene Query
|
352
349
|
# String](http://lucene.apache.org/core/4_3_0/queryparser/org/apache/lucene/queryparser/classic/package-summary.html#Overview)
|
353
350
|
# to query the collection with.
|
354
|
-
# @return [
|
351
|
+
# @return [Orchestrate::Search::QueryBuilder] A builder object to construct the query.
|
355
352
|
def search(query)
|
356
|
-
|
353
|
+
Search::QueryBuilder.new(self, query)
|
357
354
|
end
|
358
|
-
# @!endgroup
|
359
355
|
|
360
356
|
# @!group Geo Queries
|
361
357
|
# Performs a search for items near a specified geographic point in a collection.
|
@@ -366,11 +362,11 @@ module Orchestrate
|
|
366
362
|
# @param distance [Integer] The number of distance units.
|
367
363
|
# @param units [#to_s] Unit of measurement for distance, default to kilometers (km),
|
368
364
|
# supported units: km, m, cm, mm, mi, yd, ft, in, nmi
|
369
|
-
# @return [
|
365
|
+
# @return [Orchestrate::Search::QueryBuilder] A builder object to construct the query.
|
370
366
|
def near(field, latitude, longitude, distance, units=nil)
|
371
|
-
|
372
|
-
|
373
|
-
|
367
|
+
units ||= 'km'
|
368
|
+
query = "#{field}:NEAR:{lat:#{latitude} lon:#{longitude} dist:#{distance}#{units}}"
|
369
|
+
Search::QueryBuilder.new(self, query)
|
374
370
|
end
|
375
371
|
|
376
372
|
# Performs a search for items within a particular area,
|
@@ -380,112 +376,14 @@ module Orchestrate
|
|
380
376
|
# @param box [#to_json] The values to create the bounding box,
|
381
377
|
# @example
|
382
378
|
# collection.in(:field, {north: 12.5, south: 15, east: 14, west: 3})
|
383
|
-
# @return [
|
379
|
+
# @return [Orchestrate::Search::QueryBuilder] A builder object to construct the query.
|
384
380
|
def in(field, box={})
|
385
381
|
box = box.flatten.each_slice(2).map {|dir, val| "#{dir}:#{val}" }.join(" ")
|
386
382
|
query = "#{field}:IN:{#{box}}"
|
387
|
-
|
383
|
+
Search::QueryBuilder.new(self, query)
|
388
384
|
end
|
389
385
|
# @!endgroup
|
390
386
|
|
391
|
-
# An enumerator with a query for searching an Orchestrate::Collection
|
392
|
-
class SearchResults
|
393
|
-
# @return [Collection] The collection this object will search.
|
394
|
-
attr_reader :collection
|
395
|
-
|
396
|
-
# @return [#to_s] The Lucene Query String given as the search query.
|
397
|
-
attr_reader :query
|
398
|
-
|
399
|
-
# @return [#to_s] The sorting parameters.
|
400
|
-
attr_reader :sort
|
401
|
-
|
402
|
-
# @return [Integer] The number of results to fetch per request.
|
403
|
-
attr_reader :limit
|
404
|
-
|
405
|
-
# Initialize a new SearchResults object
|
406
|
-
# @param collection [Orchestrate::Collection] The collection to search.
|
407
|
-
# @param query [#to_s] The Lucene Query to perform.
|
408
|
-
def initialize(collection, query, sort=nil)
|
409
|
-
@collection = collection
|
410
|
-
@query = query
|
411
|
-
@sort = sort
|
412
|
-
@limit = 100
|
413
|
-
@offset= nil
|
414
|
-
end
|
415
|
-
|
416
|
-
# Sets the sorting parameters for enumeration over the SearchResults items in the collection.
|
417
|
-
# #order takes multiple arguments, but each even numbered argument must be either :asc or :desc
|
418
|
-
# When given a single argument #order defaults to :asc
|
419
|
-
# @example
|
420
|
-
# @app[:items].search("location: Portland").order(:name, :asc, :rank, :desc, :created_at)
|
421
|
-
# the :created_at parameter will default to :asc
|
422
|
-
def order(*args)
|
423
|
-
sort = args.each_slice(2).map {|field, dir| dir ||= :asc; "#{field}:#{dir}" }.join(",")
|
424
|
-
self.class.new(collection, query, sort)
|
425
|
-
end
|
426
|
-
|
427
|
-
include Enumerable
|
428
|
-
|
429
|
-
# Iterates over each result from the Search. Used as the basis for Enumerable methods. Items are
|
430
|
-
# provided on the basis of score, with most relevant first.
|
431
|
-
# @overload each
|
432
|
-
# @return Enumerator
|
433
|
-
# @overload each(&block)
|
434
|
-
# @yieldparam [Array<(Float, Orchestrate::KeyValue)>] score,key_value The item's score and the item.
|
435
|
-
# @example
|
436
|
-
# collection.search("trendy").take(5).each do |score, item|
|
437
|
-
# puts "#{item.key} has a trend score of #{score}"
|
438
|
-
# end
|
439
|
-
def each
|
440
|
-
params = {limit:limit}
|
441
|
-
params[:offset] = offset if offset
|
442
|
-
params[:sort] = sort if sort
|
443
|
-
@response ||= collection.perform(:search, query, params)
|
444
|
-
return enum_for(:each) unless block_given?
|
445
|
-
raise ResultsNotReady.new if collection.app.inside_parallel?
|
446
|
-
loop do
|
447
|
-
@response.results.each do |listing|
|
448
|
-
yield [ listing['score'], KeyValue.from_listing(collection, listing, @response) ]
|
449
|
-
end
|
450
|
-
break unless @response.next_link
|
451
|
-
@response = @response.next_results
|
452
|
-
end
|
453
|
-
@response = nil
|
454
|
-
end
|
455
|
-
|
456
|
-
# Creates a Lazy Enumerator for the Search Results. If called inside its
|
457
|
-
# app's `in_parallel` block, will pre-fetch results.
|
458
|
-
def lazy
|
459
|
-
return each.lazy if collection.app.inside_parallel?
|
460
|
-
super
|
461
|
-
end
|
462
|
-
|
463
|
-
# Returns the first n items. Equivalent to Enumerable#take. Sets the
|
464
|
-
# `limit` parameter on the query to Orchestrate, so we don't ask for more than is needed.
|
465
|
-
# @param count [Integer] The number of items to limit to.
|
466
|
-
# @return [Array]
|
467
|
-
def take(count)
|
468
|
-
@limit = count > 100 ? 100 : count
|
469
|
-
super(count)
|
470
|
-
end
|
471
|
-
|
472
|
-
# Sets the offset for the query to Orchestrate, so you can skip items. Does not fire a request.
|
473
|
-
# Impelemented as separate method from drop, unlike #take, because take is a more common use case.
|
474
|
-
# @overload offset
|
475
|
-
# @return [Integer, nil] The number of items to skip. Nil is equivalent to zero.
|
476
|
-
# @overload offset(conunt)
|
477
|
-
# @param count [Integer] The number of items to skip.
|
478
|
-
# @return [SearchResults] self.
|
479
|
-
def offset(count=nil)
|
480
|
-
if count
|
481
|
-
@offset = count
|
482
|
-
self
|
483
|
-
else
|
484
|
-
@offset
|
485
|
-
end
|
486
|
-
end
|
487
|
-
end
|
488
|
-
|
489
387
|
# Tells the Applicaiton to perform a request on its client, automatically
|
490
388
|
# providing the collection name.
|
491
389
|
# @param api_method [Symbol] The method on the client to call.
|
@@ -0,0 +1,290 @@
|
|
1
|
+
module Orchestrate::Search
|
2
|
+
# Aggregate Builder object for constructing aggregate params included in a search
|
3
|
+
class AggregateBuilder
|
4
|
+
|
5
|
+
# @return [QueryBuilder]
|
6
|
+
attr_reader :builder
|
7
|
+
|
8
|
+
# @return [Array] Aggregate param arguments
|
9
|
+
attr_reader :aggregates
|
10
|
+
|
11
|
+
extend Forwardable
|
12
|
+
|
13
|
+
# Initialize a new AggregateBuilder object
|
14
|
+
# @param builder [Orchestrate::Search::SearchBuilder] The Search Builder object
|
15
|
+
def initialize(builder)
|
16
|
+
@builder = builder
|
17
|
+
@aggregates = []
|
18
|
+
end
|
19
|
+
|
20
|
+
def_delegator :@builder, :options
|
21
|
+
def_delegator :@builder, :order
|
22
|
+
def_delegator :@builder, :limit
|
23
|
+
def_delegator :@builder, :offset
|
24
|
+
def_delegator :@builder, :aggregate
|
25
|
+
def_delegator :@builder, :find
|
26
|
+
def_delegator :@builder, :collection
|
27
|
+
|
28
|
+
# @return Pretty-Printed string representation of the AggregateBuilder object
|
29
|
+
def to_s
|
30
|
+
"#<Orchestrate::Search::AggregateBuilder collection=#{collection.name} query=#{builder.query} aggregate=#{to_param}>"
|
31
|
+
end
|
32
|
+
alias :inspect :to_s
|
33
|
+
|
34
|
+
# @return constructed aggregate string parameter for search query
|
35
|
+
def to_param
|
36
|
+
aggregates.map {|agg| agg.to_param }.join(',')
|
37
|
+
end
|
38
|
+
|
39
|
+
# @!group Aggregate Functions
|
40
|
+
|
41
|
+
# @param field_name [#to_s]
|
42
|
+
# @return [AggregateBuilder]
|
43
|
+
def stats(field_name)
|
44
|
+
stat = StatsBuilder.new(self, "#{field_name}")
|
45
|
+
aggregates << stat
|
46
|
+
stat
|
47
|
+
end
|
48
|
+
|
49
|
+
# @param field_name [#to_s]
|
50
|
+
# @return [RangeBuilder]
|
51
|
+
def range(field_name)
|
52
|
+
rng = RangeBuilder.new(self, "#{field_name}")
|
53
|
+
aggregates << rng
|
54
|
+
rng
|
55
|
+
end
|
56
|
+
|
57
|
+
# @param field_name [#to_s]
|
58
|
+
# @return [DistanceBuilder]
|
59
|
+
def distance(field_name)
|
60
|
+
dist = DistanceBuilder.new(self, "#{field_name}")
|
61
|
+
aggregates << dist
|
62
|
+
dist
|
63
|
+
end
|
64
|
+
|
65
|
+
# @param field_name [#to_s]
|
66
|
+
# @return [TimeSeriesBuilder]
|
67
|
+
def time_series(field_name)
|
68
|
+
time = TimeSeriesBuilder.new(self, "#{field_name}")
|
69
|
+
aggregates << time
|
70
|
+
time
|
71
|
+
end
|
72
|
+
# @!endgroup
|
73
|
+
end
|
74
|
+
|
75
|
+
# Stats Builder object for constructing stats functions to be included in the aggregate param
|
76
|
+
class StatsBuilder
|
77
|
+
|
78
|
+
# @return [AggregateBuilder]
|
79
|
+
attr_reader :builder
|
80
|
+
|
81
|
+
# @return [#to_s] The field to operate over
|
82
|
+
attr_reader :field_name
|
83
|
+
|
84
|
+
extend Forwardable
|
85
|
+
|
86
|
+
# Initialize a new RangeBuilder object
|
87
|
+
# @param builder [AggregateBuilder] The Aggregate Builder object
|
88
|
+
# @param field_name [#to_s]
|
89
|
+
def initialize(builder, field_name)
|
90
|
+
@builder = builder
|
91
|
+
@field_name = field_name
|
92
|
+
end
|
93
|
+
|
94
|
+
def_delegator :@builder, :options
|
95
|
+
def_delegator :@builder, :order
|
96
|
+
def_delegator :@builder, :limit
|
97
|
+
def_delegator :@builder, :offset
|
98
|
+
def_delegator :@builder, :aggregate
|
99
|
+
def_delegator :@builder, :find
|
100
|
+
def_delegator :@builder, :stats
|
101
|
+
def_delegator :@builder, :range
|
102
|
+
def_delegator :@builder, :distance
|
103
|
+
def_delegator :@builder, :time_series
|
104
|
+
def_delegator :@builder, :collection
|
105
|
+
|
106
|
+
# @return Pretty-Printed string representation of the StatsBuilder object
|
107
|
+
def to_s
|
108
|
+
"#<Orchestrate::Search::StatsBuilder collection=#{collection.name} field_name=#{field_name}>"
|
109
|
+
end
|
110
|
+
alias :inspect :to_s
|
111
|
+
|
112
|
+
# @return [#to_s] constructed aggregate string clause
|
113
|
+
def to_param
|
114
|
+
"#{field_name}:stats"
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
# Range Builder object for constructing range functions to be included in the aggregate param
|
119
|
+
class RangeBuilder
|
120
|
+
|
121
|
+
# @return [AggregateBuilder]
|
122
|
+
attr_reader :builder
|
123
|
+
|
124
|
+
# @return [#to_s] The field to operate over
|
125
|
+
attr_reader :field_name
|
126
|
+
|
127
|
+
# @return [#to_s] The range sets
|
128
|
+
attr_reader :ranges
|
129
|
+
|
130
|
+
extend Forwardable
|
131
|
+
|
132
|
+
# Initialize a new RangeBuilder object
|
133
|
+
# @param builder [AggregateBuilder] The Aggregate Builder object
|
134
|
+
# @param field_name [#to_s]
|
135
|
+
def initialize(builder, field_name)
|
136
|
+
@builder = builder
|
137
|
+
@field_name = field_name
|
138
|
+
@ranges = ''
|
139
|
+
end
|
140
|
+
|
141
|
+
def_delegator :@builder, :options
|
142
|
+
def_delegator :@builder, :order
|
143
|
+
def_delegator :@builder, :limit
|
144
|
+
def_delegator :@builder, :offset
|
145
|
+
def_delegator :@builder, :aggregate
|
146
|
+
def_delegator :@builder, :find
|
147
|
+
def_delegator :@builder, :stats
|
148
|
+
def_delegator :@builder, :range
|
149
|
+
def_delegator :@builder, :distance
|
150
|
+
def_delegator :@builder, :time_series
|
151
|
+
def_delegator :@builder, :collection
|
152
|
+
|
153
|
+
# @return Pretty-Printed string representation of the RangeBuilder object
|
154
|
+
def to_s
|
155
|
+
"#<Orchestrate::Search::RangeBuilder collection=#{collection.name} field_name=#{field_name} ranges=#{ranges}>"
|
156
|
+
end
|
157
|
+
alias :inspect :to_s
|
158
|
+
|
159
|
+
# @return [#to_s] constructed aggregate string clause
|
160
|
+
def to_param
|
161
|
+
"#{field_name}:range:#{ranges}"
|
162
|
+
end
|
163
|
+
|
164
|
+
# @param x [Integer]
|
165
|
+
# @return [RangeBuilder]
|
166
|
+
def below(x)
|
167
|
+
@ranges << "*~#{x}:"
|
168
|
+
self
|
169
|
+
end
|
170
|
+
|
171
|
+
# @param x [Integer]
|
172
|
+
# @return [RangeBuilder]
|
173
|
+
def above(x)
|
174
|
+
@ranges << "#{x}~*:"
|
175
|
+
self
|
176
|
+
end
|
177
|
+
|
178
|
+
# @param x [Integer]
|
179
|
+
# @param y [Integer]
|
180
|
+
# @return [RangeBuilder]
|
181
|
+
def between(x, y)
|
182
|
+
@ranges << "#{x}~#{y}:"
|
183
|
+
self
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
# Distance Builder object for constructing distance functions for the aggregate param
|
188
|
+
class DistanceBuilder < RangeBuilder
|
189
|
+
|
190
|
+
# @return Pretty-Printed string representation of the DistanceBuilder object
|
191
|
+
def to_s
|
192
|
+
"#<Orchestrate::Search::DistanceBuilder collection=#{collection.name} field_name=#{field_name} ranges=#{ranges}>"
|
193
|
+
end
|
194
|
+
alias :inspect :to_s
|
195
|
+
|
196
|
+
# @return [#to_s] constructed aggregate string clause
|
197
|
+
def to_param
|
198
|
+
"#{field_name}:distance:#{ranges}"
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
# Time Series Builder object for constructing time series functions for the aggregate param
|
203
|
+
class TimeSeriesBuilder
|
204
|
+
|
205
|
+
# @return [AggregateBuilder]
|
206
|
+
attr_reader :builder
|
207
|
+
|
208
|
+
# @return [#to_s] The field to operate over
|
209
|
+
attr_reader :field_name
|
210
|
+
|
211
|
+
# @return [#to_s] The interval of time for the TimeSeries function
|
212
|
+
attr_reader :interval
|
213
|
+
|
214
|
+
extend Forwardable
|
215
|
+
|
216
|
+
# Initialize a new TimeSeriesBuilder object
|
217
|
+
# @param builder [AggregateBuilder] The Aggregate Builder object
|
218
|
+
# @param field_name [#to_s] The field to operate over
|
219
|
+
def initialize(builder, field_name)
|
220
|
+
@builder = builder
|
221
|
+
@field_name = field_name
|
222
|
+
@interval = nil
|
223
|
+
end
|
224
|
+
|
225
|
+
def_delegator :@builder, :options
|
226
|
+
def_delegator :@builder, :order
|
227
|
+
def_delegator :@builder, :limit
|
228
|
+
def_delegator :@builder, :offset
|
229
|
+
def_delegator :@builder, :aggregate
|
230
|
+
def_delegator :@builder, :find
|
231
|
+
def_delegator :@builder, :stats
|
232
|
+
def_delegator :@builder, :range
|
233
|
+
def_delegator :@builder, :distance
|
234
|
+
def_delegator :@builder, :time_series
|
235
|
+
def_delegator :@builder, :collection
|
236
|
+
|
237
|
+
# @return Pretty-Printed string representation of the TimeSeriesBuilder object
|
238
|
+
def to_s
|
239
|
+
"#<Orchestrate::Search::TimeSeriesBuilder collection=#{collection.name} field_name=#{field_name} interval=#{interval}>"
|
240
|
+
end
|
241
|
+
alias :inspect :to_s
|
242
|
+
|
243
|
+
# @return [#to_s] constructed aggregate string clause
|
244
|
+
def to_param
|
245
|
+
"#{field_name}:time_series:#{interval}"
|
246
|
+
end
|
247
|
+
|
248
|
+
# Set time series interval to year
|
249
|
+
# @return [AggregateBuilder]
|
250
|
+
def year
|
251
|
+
@interval = 'year'
|
252
|
+
self
|
253
|
+
end
|
254
|
+
|
255
|
+
# Set time series interval to quarter
|
256
|
+
# @return [AggregateBuilder]
|
257
|
+
def quarter
|
258
|
+
@interval = 'quarter'
|
259
|
+
self
|
260
|
+
end
|
261
|
+
|
262
|
+
# Set time series interval to month
|
263
|
+
# @return [AggregateBuilder]
|
264
|
+
def month
|
265
|
+
@interval = 'month'
|
266
|
+
self
|
267
|
+
end
|
268
|
+
|
269
|
+
# Set time series interval to week
|
270
|
+
# @return [AggregateBuilder]
|
271
|
+
def week
|
272
|
+
@interval = 'week'
|
273
|
+
self
|
274
|
+
end
|
275
|
+
|
276
|
+
# Set time series interval to day
|
277
|
+
# @return [AggregateBuilder]
|
278
|
+
def day
|
279
|
+
@interval = 'day'
|
280
|
+
self
|
281
|
+
end
|
282
|
+
|
283
|
+
# Set time series interval to hour
|
284
|
+
# @return [AggregateBuilder]
|
285
|
+
def hour
|
286
|
+
@interval = 'hour'
|
287
|
+
self
|
288
|
+
end
|
289
|
+
end
|
290
|
+
end
|