elastic-rails 0.8.5 → 0.8.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +6 -3
- data/README.md +10 -0
- data/lib/elastic.rb +4 -1
- data/lib/elastic/core/query_assembler.rb +15 -6
- data/lib/elastic/dsl/metric_builder.rb +24 -7
- data/lib/elastic/dsl/result_composer.rb +15 -0
- data/lib/elastic/nodes/agg/top.rb +42 -0
- data/lib/elastic/nodes/base.rb +1 -1
- data/lib/elastic/nodes/concerns/sortable.rb +54 -0
- data/lib/elastic/nodes/sort.rb +2 -39
- data/lib/elastic/query.rb +10 -17
- data/lib/elastic/shims/multiple_aggregation.rb +16 -0
- data/lib/elastic/shims/{reducing.rb → single_aggregation.rb} +1 -1
- data/lib/elastic/version.rb +1 -1
- metadata +7 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c0035b5db3d49f0a734e2f8a2d77162ac50867cc
|
4
|
+
data.tar.gz: 0223a10c669b8f637b14c50afe88b73ef4714a17
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f95a7f7abbaae72da092ec05cbfc2fc5cdec442438d48acbcfab152a716a84c0deb1f3e2e1ae60196a756608d73753203861f8337ccabd9a1353110f720fb19d
|
7
|
+
data.tar.gz: 4f3fe1093d986f8fcda505c37623a5da5398a93bb0a407408c32863ffe33e14d161244617fa0b6247e4dfc1b946695d23931136ab9b9512d437e8db82aa28dfd
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# Elastic Rails
|
2
2
|
|
3
|
+
[![Build Status](https://travis-ci.org/platanus/elastic-rails.svg?branch=master)](https://travis-ci.org/platanus/elastic-rails)
|
4
|
+
|
3
5
|
Elasticsearch + Ruby on Rails made easy.
|
4
6
|
|
5
7
|
## Features
|
@@ -119,6 +121,14 @@ BikeIndex
|
|
119
121
|
.average(:price)
|
120
122
|
.each { |keys, price| puts "#{keys[:year]}/#{keys[:category]} => #{price}" }
|
121
123
|
|
124
|
+
# Get average and maximum bike price for bikes newer than 2014
|
125
|
+
BikeIndex
|
126
|
+
.must(year: { gte: 2014 })
|
127
|
+
.compose do |c|
|
128
|
+
c.average(:price)
|
129
|
+
c.maximum(:price)
|
130
|
+
end
|
131
|
+
|
122
132
|
# Search bikes ids that have shimano parts:
|
123
133
|
BikeIndex.must(parts: { brand: 'shimano' }).ids
|
124
134
|
```
|
data/lib/elastic.rb
CHANGED
@@ -45,6 +45,7 @@ require "elastic/nodes/agg/average"
|
|
45
45
|
require "elastic/nodes/agg/minimum"
|
46
46
|
require "elastic/nodes/agg/maximum"
|
47
47
|
require "elastic/nodes/agg/sum"
|
48
|
+
require "elastic/nodes/agg/top"
|
48
49
|
require "elastic/nodes/agg/terms"
|
49
50
|
require "elastic/nodes/agg/date_histogram"
|
50
51
|
require "elastic/nodes/agg/top_hits"
|
@@ -52,7 +53,8 @@ require "elastic/nodes/agg/top_hits"
|
|
52
53
|
require "elastic/shims/base"
|
53
54
|
require "elastic/shims/populating"
|
54
55
|
require "elastic/shims/grouping"
|
55
|
-
require "elastic/shims/
|
56
|
+
require "elastic/shims/single_aggregation"
|
57
|
+
require "elastic/shims/multiple_aggregation"
|
56
58
|
require "elastic/shims/total_picking"
|
57
59
|
require "elastic/shims/id_picking"
|
58
60
|
require "elastic/shims/field_picking"
|
@@ -79,6 +81,7 @@ require "elastic/core/query_assembler"
|
|
79
81
|
require "elastic/dsl/bool_query_builder"
|
80
82
|
require "elastic/dsl/bool_query_context"
|
81
83
|
require "elastic/dsl/metric_builder"
|
84
|
+
require "elastic/dsl/result_composer"
|
82
85
|
|
83
86
|
require "elastic/types/base_type"
|
84
87
|
require "elastic/types/faceted_type"
|
@@ -30,11 +30,16 @@ module Elastic::Core
|
|
30
30
|
end
|
31
31
|
|
32
32
|
def assemble_metric(_node)
|
33
|
-
query =
|
34
|
-
|
33
|
+
query = assemble_aggregated([_node])
|
34
|
+
single_aggregation_query query
|
35
35
|
end
|
36
36
|
|
37
|
-
def assemble_metrics(
|
37
|
+
def assemble_metrics(_nodes)
|
38
|
+
query = assemble_aggregated(_nodes)
|
39
|
+
multiple_aggregation_query query
|
40
|
+
end
|
41
|
+
|
42
|
+
def assemble_aggregated(_aggs)
|
38
43
|
query = build_base_query
|
39
44
|
query.size = 0
|
40
45
|
|
@@ -64,7 +69,7 @@ module Elastic::Core
|
|
64
69
|
last.aggregate sort_node Elastic::Nodes::TopHits.build('default')
|
65
70
|
|
66
71
|
query = grouped_query query
|
67
|
-
query =
|
72
|
+
query = single_aggregation_query query
|
68
73
|
end
|
69
74
|
|
70
75
|
query
|
@@ -93,8 +98,12 @@ module Elastic::Core
|
|
93
98
|
Elastic::Shims::Grouping.new(_query)
|
94
99
|
end
|
95
100
|
|
96
|
-
def
|
97
|
-
Elastic::Shims::
|
101
|
+
def single_aggregation_query(_query)
|
102
|
+
Elastic::Shims::SingleAggregation.new(_query)
|
103
|
+
end
|
104
|
+
|
105
|
+
def multiple_aggregation_query(_query)
|
106
|
+
Elastic::Shims::MultipleAggregation.new(_query)
|
98
107
|
end
|
99
108
|
|
100
109
|
def populated_query(_query)
|
@@ -20,15 +20,32 @@ module Elastic::Dsl
|
|
20
20
|
aggregate_metric(Elastic::Nodes::Agg::Stats, _field, _options, '%s_stats')
|
21
21
|
end
|
22
22
|
|
23
|
-
|
23
|
+
def opening(_field, _options = {})
|
24
|
+
by = _options.delete :by
|
25
|
+
raise ArgumentError, 'must provide a sorting column' if by.nil?
|
26
|
+
|
27
|
+
aggregate_metric(Elastic::Nodes::Agg::Top, _field, _options, 'open_%s') do |node|
|
28
|
+
node.add_sort(by, order: :asc)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def closing(_field, _options = {})
|
33
|
+
by = _options.delete :by
|
34
|
+
raise ArgumentError, 'must provide a sorting column' if by.nil?
|
24
35
|
|
25
|
-
|
26
|
-
|
27
|
-
# TODO: detect nested name and wrap node
|
28
|
-
name = _options[:as] || sprintf(_default_name, _field)
|
29
|
-
node = _klass.build(name, _field, missing: _options[:missing])
|
30
|
-
agg.aggregate node
|
36
|
+
aggregate_metric(Elastic::Nodes::Agg::Top, _field, _options, 'close_%s') do |node|
|
37
|
+
node.add_sort(by, order: :desc)
|
31
38
|
end
|
32
39
|
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def aggregate_metric(_klass, _field, _options, _default_name, &_block)
|
44
|
+
# TODO: detect nested name and wrap node
|
45
|
+
name = _options.delete(:as) || sprintf(_default_name, _field)
|
46
|
+
node = _klass.build(name, _field, _options)
|
47
|
+
_block.call node unless _block.nil?
|
48
|
+
aggregate node
|
49
|
+
end
|
33
50
|
end
|
34
51
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Elastic::Dsl
|
2
|
+
class ResultComposer
|
3
|
+
include MetricBuilder
|
4
|
+
|
5
|
+
def initialize(_aggs)
|
6
|
+
@aggs = _aggs
|
7
|
+
end
|
8
|
+
|
9
|
+
def aggregate(_node)
|
10
|
+
raise ArgumentError, 'node must provide a name' unless _node.name
|
11
|
+
@aggs << _node
|
12
|
+
nil
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Elastic::Nodes::Agg
|
2
|
+
class Top < Elastic::Nodes::BaseAgg
|
3
|
+
include Elastic::Nodes::Concerns::Sortable
|
4
|
+
|
5
|
+
def self.build(_name, _field, _options = {})
|
6
|
+
super(_name).tap do |node|
|
7
|
+
node.field = _field
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
attr_accessor :field
|
12
|
+
|
13
|
+
def clone
|
14
|
+
prepare_clone super
|
15
|
+
end
|
16
|
+
|
17
|
+
def simplify
|
18
|
+
prepare_clone super
|
19
|
+
end
|
20
|
+
|
21
|
+
def render(_options = {})
|
22
|
+
top_hit_config = { '_source' => { 'include' => [@field.to_s] }, 'size' => 1 }
|
23
|
+
top_hit_config['sort'] = render_sorts if registered_sorts.count > 0
|
24
|
+
|
25
|
+
{ 'top_hits' => top_hit_config }
|
26
|
+
end
|
27
|
+
|
28
|
+
def handle_result(_raw, _formatter)
|
29
|
+
raw_value = _raw['hits'] ? _raw['hits']['hits'].first['_source'][@field.to_s] : nil
|
30
|
+
|
31
|
+
# TODO: apply formatter to value
|
32
|
+
Elastic::Results::Metric.new raw_value
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def prepare_clone(_clone)
|
38
|
+
_clone.field = @field
|
39
|
+
_clone
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/lib/elastic/nodes/base.rb
CHANGED
@@ -0,0 +1,54 @@
|
|
1
|
+
module Elastic::Nodes::Concerns
|
2
|
+
module Sortable
|
3
|
+
ORDER = [:asc, :desc]
|
4
|
+
MODES = [:min, :max, :sum, :avg, :median]
|
5
|
+
|
6
|
+
def clone
|
7
|
+
copy_sorts super
|
8
|
+
end
|
9
|
+
|
10
|
+
def simplify
|
11
|
+
copy_sorts super
|
12
|
+
end
|
13
|
+
|
14
|
+
def sorts
|
15
|
+
registered_sorts.dup
|
16
|
+
end
|
17
|
+
|
18
|
+
def add_sort(_field, order: :asc, mode: nil, missing: nil)
|
19
|
+
raise ArgumentError, "invalid sort order #{order}" unless ORDER.include?(order.to_sym)
|
20
|
+
raise ArgumentError, "invalid sort mode #{mode}" if mode && !MODES.include?(mode.to_sym)
|
21
|
+
|
22
|
+
options = { 'order' => order.to_s }
|
23
|
+
options['mode'] = mode.to_s if mode.present?
|
24
|
+
options['missing'] = missing if missing.present?
|
25
|
+
|
26
|
+
registered_sorts << { _field.to_s => options.freeze }.freeze
|
27
|
+
self
|
28
|
+
end
|
29
|
+
|
30
|
+
def reset_sorts
|
31
|
+
@registered_sorts = nil
|
32
|
+
self
|
33
|
+
end
|
34
|
+
|
35
|
+
protected
|
36
|
+
|
37
|
+
attr_writer :registered_sorts
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def copy_sorts(_clone)
|
42
|
+
_clone.registered_sorts = sorts
|
43
|
+
_clone
|
44
|
+
end
|
45
|
+
|
46
|
+
def render_sorts
|
47
|
+
sorts
|
48
|
+
end
|
49
|
+
|
50
|
+
def registered_sorts
|
51
|
+
@registered_sorts ||= []
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
data/lib/elastic/nodes/sort.rb
CHANGED
@@ -1,47 +1,19 @@
|
|
1
1
|
module Elastic::Nodes
|
2
2
|
class Sort < Base
|
3
|
-
|
4
|
-
MODES = [:min, :max, :sum, :avg, :median]
|
3
|
+
include Concerns::Sortable
|
5
4
|
|
6
5
|
attr_accessor :child
|
7
6
|
|
8
|
-
def initialize
|
9
|
-
@sorts = []
|
10
|
-
end
|
11
|
-
|
12
|
-
def sorts
|
13
|
-
@sorts.dup
|
14
|
-
end
|
15
|
-
|
16
|
-
def add_sort(_field, order: :asc, mode: nil, missing: nil)
|
17
|
-
raise ArgumentError, "invalid sort order #{order}" unless ORDER.include?(order.to_sym)
|
18
|
-
raise ArgumentError, "invalid sort mode #{mode}" if mode && !MODES.include?(mode.to_sym)
|
19
|
-
|
20
|
-
options = { 'order' => order.to_s }
|
21
|
-
options['mode'] = mode.to_s if mode.present?
|
22
|
-
options['missing'] = missing if missing.present?
|
23
|
-
|
24
|
-
@sorts << { _field => options.freeze }.freeze
|
25
|
-
self
|
26
|
-
end
|
27
|
-
|
28
7
|
def add_score_sort(order: :desc)
|
29
|
-
raise ArgumentError, "invalid sort order #{order}" unless ORDER.include?(order.to_sym)
|
30
|
-
|
31
8
|
add_sort('_score', order: order)
|
32
9
|
end
|
33
10
|
|
34
|
-
def reset_sorts
|
35
|
-
@sorts = []
|
36
|
-
self
|
37
|
-
end
|
38
|
-
|
39
11
|
def clone
|
40
12
|
prepare_clone(super, child.try(:clone))
|
41
13
|
end
|
42
14
|
|
43
15
|
def simplify
|
44
|
-
if
|
16
|
+
if registered_sorts.empty?
|
45
17
|
child.try(:simplify)
|
46
18
|
else
|
47
19
|
prepare_clone(super, child.try(:simplify))
|
@@ -63,20 +35,11 @@ module Elastic::Nodes
|
|
63
35
|
@child.traverse(&_block)
|
64
36
|
end
|
65
37
|
|
66
|
-
protected
|
67
|
-
|
68
|
-
attr_writer :sorts
|
69
|
-
|
70
38
|
private
|
71
39
|
|
72
40
|
def prepare_clone(_clone, _child)
|
73
41
|
_clone.child = _child
|
74
|
-
_clone.sorts = @sorts.dup
|
75
42
|
_clone
|
76
43
|
end
|
77
|
-
|
78
|
-
def render_sorts
|
79
|
-
@sorts.dup
|
80
|
-
end
|
81
44
|
end
|
82
45
|
end
|
data/lib/elastic/query.rb
CHANGED
@@ -43,10 +43,6 @@ module Elastic
|
|
43
43
|
execute assembler.assemble_pick(_field)
|
44
44
|
end
|
45
45
|
|
46
|
-
def aggregate(_name = nil, _node = nil, &_block)
|
47
|
-
# TODO
|
48
|
-
end
|
49
|
-
|
50
46
|
def total
|
51
47
|
execute assembler.assemble_total
|
52
48
|
end
|
@@ -64,6 +60,16 @@ module Elastic
|
|
64
60
|
assembler.assemble.render
|
65
61
|
end
|
66
62
|
|
63
|
+
def compose(&_block)
|
64
|
+
agg_nodes = []
|
65
|
+
Dsl::ResultComposer.new(agg_nodes).tap(&_block)
|
66
|
+
execute assembler.assemble_metrics agg_nodes
|
67
|
+
end
|
68
|
+
|
69
|
+
def aggregate(_node)
|
70
|
+
execute assembler.assemble_metric _node
|
71
|
+
end
|
72
|
+
|
67
73
|
private
|
68
74
|
|
69
75
|
def with_clone(&_block)
|
@@ -76,11 +82,6 @@ module Elastic
|
|
76
82
|
with_clone { |config| _block.call(config.query) }
|
77
83
|
end
|
78
84
|
|
79
|
-
def with_aggregable_for_metric(&_block)
|
80
|
-
adaptor = AggregableAdaptor.new.tap(&_block)
|
81
|
-
execute assembler.assemble_metric(adaptor.agg)
|
82
|
-
end
|
83
|
-
|
84
85
|
def build_base_config
|
85
86
|
Core::QueryConfig.initial_config
|
86
87
|
end
|
@@ -101,13 +102,5 @@ module Elastic
|
|
101
102
|
def formatter
|
102
103
|
Core::SourceFormatter.new(@index.definition)
|
103
104
|
end
|
104
|
-
|
105
|
-
class AggregableAdaptor
|
106
|
-
attr_accessor :agg
|
107
|
-
|
108
|
-
def aggregate(_node)
|
109
|
-
self.agg = _node
|
110
|
-
end
|
111
|
-
end
|
112
105
|
end
|
113
106
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Elastic::Shims
|
2
|
+
class MultipleAggregation < Base
|
3
|
+
def handle_result(_raw, _formatter)
|
4
|
+
result = super
|
5
|
+
|
6
|
+
case result
|
7
|
+
when Elastic::Results::Root
|
8
|
+
result.aggregations
|
9
|
+
when Elastic::Results::GroupedResult
|
10
|
+
result
|
11
|
+
else
|
12
|
+
raise "unable to reduce result of type #{result.class}"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/elastic/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: elastic-rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.8.
|
4
|
+
version: 0.8.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ignacio Baixas
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-05-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: elasticsearch
|
@@ -248,6 +248,7 @@ files:
|
|
248
248
|
- lib/elastic/dsl/bool_query_builder.rb
|
249
249
|
- lib/elastic/dsl/bool_query_context.rb
|
250
250
|
- lib/elastic/dsl/metric_builder.rb
|
251
|
+
- lib/elastic/dsl/result_composer.rb
|
251
252
|
- lib/elastic/errors.rb
|
252
253
|
- lib/elastic/fields/nested.rb
|
253
254
|
- lib/elastic/fields/value.rb
|
@@ -261,6 +262,7 @@ files:
|
|
261
262
|
- lib/elastic/nodes/agg/stats.rb
|
262
263
|
- lib/elastic/nodes/agg/sum.rb
|
263
264
|
- lib/elastic/nodes/agg/terms.rb
|
265
|
+
- lib/elastic/nodes/agg/top.rb
|
264
266
|
- lib/elastic/nodes/agg/top_hits.rb
|
265
267
|
- lib/elastic/nodes/and.rb
|
266
268
|
- lib/elastic/nodes/base.rb
|
@@ -271,6 +273,7 @@ files:
|
|
271
273
|
- lib/elastic/nodes/concerns/bucketed.rb
|
272
274
|
- lib/elastic/nodes/concerns/field_query.rb
|
273
275
|
- lib/elastic/nodes/concerns/hit_provider.rb
|
276
|
+
- lib/elastic/nodes/concerns/sortable.rb
|
274
277
|
- lib/elastic/nodes/function_score.rb
|
275
278
|
- lib/elastic/nodes/match.rb
|
276
279
|
- lib/elastic/nodes/nested.rb
|
@@ -309,8 +312,9 @@ files:
|
|
309
312
|
- lib/elastic/shims/field_picking.rb
|
310
313
|
- lib/elastic/shims/grouping.rb
|
311
314
|
- lib/elastic/shims/id_picking.rb
|
315
|
+
- lib/elastic/shims/multiple_aggregation.rb
|
312
316
|
- lib/elastic/shims/populating.rb
|
313
|
-
- lib/elastic/shims/
|
317
|
+
- lib/elastic/shims/single_aggregation.rb
|
314
318
|
- lib/elastic/shims/total_picking.rb
|
315
319
|
- lib/elastic/support/command.rb
|
316
320
|
- lib/elastic/support/transform.rb
|