elastic-rails 0.5.0 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/elastic/commands/build_agg_from_params.rb +37 -20
- data/lib/elastic/commands/build_query_from_params.rb +109 -79
- data/lib/elastic/commands/build_sort_from_params.rb +41 -0
- data/lib/elastic/commands/import_index_documents.rb +1 -1
- data/lib/elastic/configuration.rb +14 -11
- data/lib/elastic/core/adaptor.rb +0 -1
- data/lib/elastic/core/base_middleware.rb +2 -2
- data/lib/elastic/core/default_middleware.rb +1 -1
- data/lib/elastic/core/definition.rb +53 -34
- data/lib/elastic/core/query_assembler.rb +51 -19
- data/lib/elastic/core/query_config.rb +4 -5
- data/lib/elastic/core/source_formatter.rb +12 -31
- data/lib/elastic/datatypes/date.rb +32 -0
- data/lib/elastic/datatypes/default.rb +74 -0
- data/lib/elastic/datatypes/string.rb +7 -0
- data/lib/elastic/datatypes/term.rb +10 -0
- data/lib/elastic/datatypes/time.rb +29 -0
- data/lib/elastic/dsl/bool_query_builder.rb +4 -0
- data/lib/elastic/fields/nested.rb +24 -6
- data/lib/elastic/fields/value.rb +69 -25
- data/lib/elastic/nested_query.rb +34 -0
- data/lib/elastic/nested_type.rb +10 -0
- data/lib/elastic/nodes/agg/average.rb +3 -1
- data/lib/elastic/nodes/agg/base_metric.rb +6 -5
- data/lib/elastic/nodes/agg/date_histogram.rb +4 -4
- data/lib/elastic/nodes/agg/maximum.rb +3 -1
- data/lib/elastic/nodes/agg/minimum.rb +3 -1
- data/lib/elastic/nodes/agg/stats.rb +3 -1
- data/lib/elastic/nodes/agg/sum.rb +3 -1
- data/lib/elastic/nodes/agg/terms.rb +4 -4
- data/lib/elastic/nodes/agg/top_hits.rb +6 -6
- data/lib/elastic/nodes/and.rb +2 -2
- data/lib/elastic/nodes/base.rb +5 -3
- data/lib/elastic/nodes/base_agg.rb +2 -2
- data/lib/elastic/nodes/boolean.rb +34 -14
- data/lib/elastic/nodes/concerns/aggregable.rb +12 -8
- data/lib/elastic/nodes/concerns/bucketed.rb +4 -7
- data/lib/elastic/nodes/concerns/field_query.rb +10 -0
- data/lib/elastic/nodes/concerns/hit_provider.rb +11 -0
- data/lib/elastic/nodes/function_score.rb +8 -7
- data/lib/elastic/nodes/match.rb +6 -5
- data/lib/elastic/nodes/nested.rb +28 -7
- data/lib/elastic/nodes/range.rb +9 -8
- data/lib/elastic/nodes/search.rb +11 -10
- data/lib/elastic/nodes/sort.rb +82 -0
- data/lib/elastic/nodes/term.rb +7 -6
- data/lib/elastic/query.rb +24 -12
- data/lib/elastic/railtie.rb +7 -0
- data/lib/elastic/railties/ar_helpers.rb +2 -1
- data/lib/elastic/railties/configuration_extensions.rb +13 -0
- data/lib/elastic/railties/indexable_record.rb +1 -2
- data/lib/elastic/railties/indexing_job.rb +8 -0
- data/lib/elastic/railties/type_extensions.rb +1 -1
- data/lib/elastic/results/aggregations.rb +1 -1
- data/lib/elastic/results/bucket.rb +3 -2
- data/lib/elastic/results/grouped_result.rb +31 -1
- data/lib/elastic/results/hit.rb +8 -20
- data/lib/elastic/results/hit_collection.rb +2 -33
- data/lib/elastic/results/root.rb +3 -2
- data/lib/elastic/results/scored_collection.rb +44 -0
- data/lib/elastic/results/scored_item.rb +10 -0
- data/lib/elastic/shims/base.rb +6 -4
- data/lib/elastic/shims/concerns/hit_picker.rb +41 -0
- data/lib/elastic/shims/field_picking.rb +20 -0
- data/lib/elastic/shims/grouping.rb +17 -8
- data/lib/elastic/shims/id_picking.rb +15 -0
- data/lib/elastic/shims/populating.rb +4 -11
- data/lib/elastic/shims/reducing.rb +3 -7
- data/lib/elastic/shims/total_picking.rb +16 -0
- data/lib/elastic/type.rb +6 -3
- data/lib/elastic/types/base_type.rb +16 -9
- data/lib/elastic/types/faceted_type.rb +1 -1
- data/lib/elastic/types/nestable_type.rb +2 -2
- data/lib/elastic/version.rb +1 -1
- data/lib/elastic.rb +15 -0
- data/lib/generators/elastic/index_generator.rb +1 -1
- data/lib/generators/elastic/init_generator.rb +10 -0
- data/lib/generators/elastic/templates/elastic.yml +14 -0
- data/lib/generators/elastic/templates/index.rb +0 -1
- metadata +21 -2
@@ -20,11 +20,11 @@ module Elastic::Nodes::Agg
|
|
20
20
|
prepare_clone(super)
|
21
21
|
end
|
22
22
|
|
23
|
-
def render
|
24
|
-
|
25
|
-
|
23
|
+
def render(_options = {})
|
24
|
+
hash = { 'field' => @field.to_s }
|
25
|
+
hash['size'] = @size if @size
|
26
26
|
|
27
|
-
render_aggs 'terms' =>
|
27
|
+
render_aggs({ 'terms' => hash }, _options)
|
28
28
|
end
|
29
29
|
|
30
30
|
private
|
@@ -2,15 +2,15 @@ module Elastic::Nodes
|
|
2
2
|
class TopHits < BaseAgg
|
3
3
|
include Concerns::HitProvider
|
4
4
|
|
5
|
-
def render
|
6
|
-
|
7
|
-
render_hit_options
|
5
|
+
def render(_options = {})
|
6
|
+
hash = {}
|
7
|
+
render_hit_options hash
|
8
8
|
|
9
|
-
{ 'top_hits' =>
|
9
|
+
{ 'top_hits' => hash }
|
10
10
|
end
|
11
11
|
|
12
|
-
def handle_result(_raw)
|
13
|
-
hits = _raw['hits'] ? _raw['hits']['hits']
|
12
|
+
def handle_result(_raw, _formatter)
|
13
|
+
hits = _raw['hits'] ? prepare_hits(_raw['hits']['hits'], _formatter) : []
|
14
14
|
Elastic::Results::HitCollection.new(hits)
|
15
15
|
end
|
16
16
|
end
|
data/lib/elastic/nodes/and.rb
CHANGED
data/lib/elastic/nodes/base.rb
CHANGED
@@ -10,7 +10,7 @@ module Elastic::Nodes
|
|
10
10
|
_block.call(self)
|
11
11
|
end
|
12
12
|
|
13
|
-
def render
|
13
|
+
def render(_options = {})
|
14
14
|
raise NotImplementedError, 'render must be implemented by each node'
|
15
15
|
end
|
16
16
|
|
@@ -22,8 +22,8 @@ module Elastic::Nodes
|
|
22
22
|
self.class.new
|
23
23
|
end
|
24
24
|
|
25
|
-
def handle_result(_raw)
|
26
|
-
|
25
|
+
def handle_result(_raw, _formatter)
|
26
|
+
_raw
|
27
27
|
end
|
28
28
|
end
|
29
29
|
end
|
@@ -32,3 +32,5 @@ require "elastic/nodes/concerns/hit_provider"
|
|
32
32
|
require "elastic/nodes/concerns/aggregable"
|
33
33
|
require "elastic/nodes/concerns/bucketed"
|
34
34
|
require "elastic/nodes/concerns/boostable"
|
35
|
+
require "elastic/nodes/concerns/field_query"
|
36
|
+
|
@@ -16,6 +16,8 @@ module Elastic::Nodes
|
|
16
16
|
super
|
17
17
|
@musts = []
|
18
18
|
@shoulds = []
|
19
|
+
@filters = []
|
20
|
+
@disable_coord = !Elastic::Configuration.coord_similarity
|
19
21
|
end
|
20
22
|
|
21
23
|
def must(_node)
|
@@ -26,6 +28,10 @@ module Elastic::Nodes
|
|
26
28
|
@shoulds << _node
|
27
29
|
end
|
28
30
|
|
31
|
+
def filter(_node)
|
32
|
+
@filters << _node
|
33
|
+
end
|
34
|
+
|
29
35
|
def musts=(_nodes)
|
30
36
|
@musts = _nodes.dup.to_a
|
31
37
|
end
|
@@ -42,43 +48,57 @@ module Elastic::Nodes
|
|
42
48
|
@shoulds.each
|
43
49
|
end
|
44
50
|
|
51
|
+
def filters=(_nodes)
|
52
|
+
@filters = _nodes.dup.to_a
|
53
|
+
end
|
54
|
+
|
55
|
+
def filters
|
56
|
+
@filters.each
|
57
|
+
end
|
58
|
+
|
45
59
|
def traverse(&_block)
|
46
60
|
super
|
47
61
|
@shoulds.each { |c| c.traverse(&_block) }
|
48
62
|
@musts.each { |c| c.traverse(&_block) }
|
49
63
|
end
|
50
64
|
|
51
|
-
def render
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
65
|
+
def render(_options = {})
|
66
|
+
hash = {}
|
67
|
+
hash['must'] = @musts.map { |n| n.render(_options) } if !@musts.empty?
|
68
|
+
hash['should'] = @shoulds.map { |n| n.render(_options) } if !@shoulds.empty?
|
69
|
+
hash['filters'] = @filters.map { |n| n.render(_options) } if !@filters.empty?
|
70
|
+
hash['minimum_should_match'] = minimum_should_match unless minimum_should_match.nil?
|
71
|
+
hash['disable_coord'] = true if disable_coord
|
72
|
+
render_boost(hash)
|
59
73
|
|
60
|
-
{ "bool" =>
|
74
|
+
{ "bool" => hash }
|
61
75
|
end
|
62
76
|
|
63
77
|
def clone
|
64
|
-
prepare_clone super, @musts.map(&:clone), @shoulds.map(&:clone)
|
78
|
+
prepare_clone super, @musts.map(&:clone), @shoulds.map(&:clone), @filters.map(&:clone)
|
65
79
|
end
|
66
80
|
|
67
81
|
def simplify
|
68
82
|
new_must = @musts.map(&:simplify)
|
69
83
|
new_should = @shoulds.map(&:simplify)
|
84
|
+
new_filter = @filters.map(&:simplify)
|
70
85
|
|
71
|
-
|
72
|
-
|
86
|
+
# TODO: detect must elements with boost = 0 and move them to "filter"
|
87
|
+
|
88
|
+
if boost.nil? && (new_must.length + new_should.length + new_filter.length) == 1
|
89
|
+
return new_must.first unless new_must.empty?
|
90
|
+
return new_should.first unless new_should.empty? # at least 1 should match
|
91
|
+
end
|
73
92
|
|
74
|
-
prepare_clone(super, new_must, new_should)
|
93
|
+
prepare_clone(super, new_must, new_should, new_filter)
|
75
94
|
end
|
76
95
|
|
77
96
|
private
|
78
97
|
|
79
|
-
def prepare_clone(_clone, _musts, _shoulds)
|
98
|
+
def prepare_clone(_clone, _musts, _shoulds, _filters)
|
80
99
|
_clone.musts = _musts
|
81
100
|
_clone.shoulds = _shoulds
|
101
|
+
_clone.filters = _filters
|
82
102
|
_clone.minimum_should_match = @minimum_should_match
|
83
103
|
_clone.disable_coord = @disable_coord
|
84
104
|
_clone
|
@@ -1,13 +1,17 @@
|
|
1
1
|
module Elastic::Nodes::Concerns
|
2
2
|
module Aggregable
|
3
|
-
def
|
3
|
+
def has_aggregations?
|
4
4
|
aggs.count > 0
|
5
5
|
end
|
6
6
|
|
7
|
-
def
|
7
|
+
def aggregations=(_aggs)
|
8
8
|
@aggs = _aggs.dup.to_a
|
9
9
|
end
|
10
10
|
|
11
|
+
def aggregations
|
12
|
+
@aggs.each
|
13
|
+
end
|
14
|
+
|
11
15
|
def aggregate(_node)
|
12
16
|
raise ArgumentError, 'node must provide a name' unless _node.name
|
13
17
|
aggs << _node
|
@@ -20,13 +24,13 @@ module Elastic::Nodes::Concerns
|
|
20
24
|
|
21
25
|
def clone
|
22
26
|
node = super
|
23
|
-
node.
|
27
|
+
node.aggregations = aggs.map(&:clone)
|
24
28
|
node
|
25
29
|
end
|
26
30
|
|
27
31
|
def simplify
|
28
32
|
node = super
|
29
|
-
node.
|
33
|
+
node.aggregations = aggs.map(&:simplify)
|
30
34
|
node
|
31
35
|
end
|
32
36
|
|
@@ -36,15 +40,15 @@ module Elastic::Nodes::Concerns
|
|
36
40
|
@aggs ||= []
|
37
41
|
end
|
38
42
|
|
39
|
-
def render_aggs(_into)
|
40
|
-
_into['aggs'] = Hash[aggs.map { |a| [a.name, a.render] }] if
|
43
|
+
def render_aggs(_into, _options)
|
44
|
+
_into['aggs'] = Hash[aggs.map { |a| [a.name.to_s, a.render(_options)] }] if has_aggregations?
|
41
45
|
_into
|
42
46
|
end
|
43
47
|
|
44
|
-
def load_aggs_results(_raw)
|
48
|
+
def load_aggs_results(_raw, _formatter)
|
45
49
|
{}.tap do |result|
|
46
50
|
aggs.each do |node|
|
47
|
-
result[node.name] = node.handle_result(_raw[node.name])
|
51
|
+
result[node.name] = node.handle_result(_raw[node.name.to_s], _formatter)
|
48
52
|
end
|
49
53
|
end
|
50
54
|
end
|
@@ -1,14 +1,11 @@
|
|
1
1
|
module Elastic::Nodes::Concerns
|
2
2
|
module Bucketed
|
3
|
-
def handle_result(_raw)
|
3
|
+
def handle_result(_raw, _formatter)
|
4
4
|
buckets = _raw['buckets'].map do |raw_bucket|
|
5
|
-
|
5
|
+
key = _formatter.format_field(field, raw_bucket['key'])
|
6
|
+
aggs = load_aggs_results(raw_bucket, _formatter)
|
6
7
|
|
7
|
-
|
8
|
-
# configured that way
|
9
|
-
# return Elastic::Results::SimpleBucket.new(raw_bucket['key'], aggs.first) if blebliblu
|
10
|
-
|
11
|
-
Elastic::Results::Bucket.new(raw_bucket['key'], aggs)
|
8
|
+
Elastic::Results::Bucket.new(key, raw_bucket['doc_count'], aggs)
|
12
9
|
end
|
13
10
|
|
14
11
|
Elastic::Results::BucketCollection.new buckets
|
@@ -24,6 +24,17 @@ module Elastic::Nodes::Concerns
|
|
24
24
|
|
25
25
|
private
|
26
26
|
|
27
|
+
def prepare_hits(_hits, _formatter)
|
28
|
+
_hits.map do |raw_hit|
|
29
|
+
Elastic::Results::Hit.new(
|
30
|
+
raw_hit['_type'],
|
31
|
+
raw_hit['_id'],
|
32
|
+
raw_hit['_score'],
|
33
|
+
raw_hit['_source'] ? _formatter.format(raw_hit['_source']) : nil
|
34
|
+
)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
27
38
|
def copy_hit_options(_clone)
|
28
39
|
_clone.size = @size
|
29
40
|
_clone.source = @source
|
@@ -54,18 +54,19 @@ module Elastic::Nodes
|
|
54
54
|
@query.traverse(&_block)
|
55
55
|
end
|
56
56
|
|
57
|
-
def render
|
58
|
-
|
59
|
-
|
57
|
+
def render(_options = {})
|
58
|
+
hash = { 'query' => @query.render(_options) }
|
59
|
+
hash['boost_mode'] = @boost_mode.to_s if @boost_mode && @boost_mode != :multiply
|
60
60
|
|
61
|
+
# TODO: add support for the query_path option
|
61
62
|
if @functions.length > 1
|
62
|
-
|
63
|
-
|
63
|
+
hash['score_mode'] = @score_mode.to_s if @score_mode && @score_mode != :multiply
|
64
|
+
hash['functions'] = @functions
|
64
65
|
elsif @functions.length == 1
|
65
|
-
|
66
|
+
hash.merge! @functions.first
|
66
67
|
end
|
67
68
|
|
68
|
-
{ 'function_score' => render_boost(
|
69
|
+
{ 'function_score' => render_boost(hash) }
|
69
70
|
end
|
70
71
|
|
71
72
|
alias :super_clone :clone
|
data/lib/elastic/nodes/match.rb
CHANGED
@@ -1,10 +1,11 @@
|
|
1
1
|
module Elastic::Nodes
|
2
2
|
class Match < Base
|
3
3
|
include Concerns::Boostable
|
4
|
+
include Concerns::FieldQuery
|
4
5
|
|
5
6
|
MATCH_MODES = [:boolean, :phrase, :phrase_prefix]
|
6
7
|
|
7
|
-
attr_accessor :
|
8
|
+
attr_accessor :query
|
8
9
|
attr_reader :mode
|
9
10
|
|
10
11
|
def query=(_query)
|
@@ -26,11 +27,11 @@ module Elastic::Nodes
|
|
26
27
|
prepare_clone(super)
|
27
28
|
end
|
28
29
|
|
29
|
-
def render
|
30
|
-
|
31
|
-
|
30
|
+
def render(_options = {})
|
31
|
+
hash = { 'query' => @query }
|
32
|
+
hash['type'] = @mode.to_s unless @mode.nil? || @mode == :boolean
|
32
33
|
|
33
|
-
{ "match" => {
|
34
|
+
{ "match" => { render_field(_options) => render_boost(hash) } }
|
34
35
|
end
|
35
36
|
|
36
37
|
private
|
data/lib/elastic/nodes/nested.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
module Elastic::Nodes
|
2
2
|
class Nested < Base
|
3
|
+
SCORE_MODES = [:avg, :sum, :min, :max, :none]
|
4
|
+
|
3
5
|
def self.build(_path, _child)
|
4
6
|
new.tap do |node|
|
5
7
|
node.path = _path
|
@@ -8,6 +10,7 @@ module Elastic::Nodes
|
|
8
10
|
end
|
9
11
|
|
10
12
|
attr_accessor :path, :child
|
13
|
+
attr_reader :score_mode
|
11
14
|
|
12
15
|
def traverse(&_block)
|
13
16
|
super
|
@@ -18,17 +21,34 @@ module Elastic::Nodes
|
|
18
21
|
prepare_clone super, @child.clone
|
19
22
|
end
|
20
23
|
|
24
|
+
def score_mode=(_value)
|
25
|
+
raise ArgumentError, "invalid score mode #{_value}" if _value && !SCORE_MODES.include?(_value)
|
26
|
+
@score_mode = _value
|
27
|
+
end
|
28
|
+
|
21
29
|
def simplify
|
22
|
-
|
30
|
+
new_child = @child.simplify
|
31
|
+
if new_child.is_a? Nested
|
32
|
+
prepare_clone(super, new_child.child).tap do |clone|
|
33
|
+
clone.path = "#{clone.path}.#{new_child.path}"
|
34
|
+
end
|
35
|
+
else
|
36
|
+
prepare_clone super, new_child
|
37
|
+
end
|
23
38
|
end
|
24
39
|
|
25
|
-
def render
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
40
|
+
def render(_options = {})
|
41
|
+
path = @path
|
42
|
+
path = "#{_options[:query_path]}.#{path}" if _options.key? :query_path
|
43
|
+
|
44
|
+
hash = {
|
45
|
+
'path' => path,
|
46
|
+
'query' => @child.render(_options.merge(query_path: path))
|
31
47
|
}
|
48
|
+
|
49
|
+
hash['score_mode'] = @score_mode.to_s if @score_mode && @score_mode != :avg
|
50
|
+
|
51
|
+
{ "nested" => hash }
|
32
52
|
end
|
33
53
|
|
34
54
|
private
|
@@ -36,6 +56,7 @@ module Elastic::Nodes
|
|
36
56
|
def prepare_clone(_clone, _child)
|
37
57
|
_clone.path = @path
|
38
58
|
_clone.child = _child
|
59
|
+
_clone.score_mode = @score_mode
|
39
60
|
_clone
|
40
61
|
end
|
41
62
|
end
|
data/lib/elastic/nodes/range.rb
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
module Elastic::Nodes
|
2
2
|
class Range < Base
|
3
3
|
include Concerns::Boostable
|
4
|
+
include Concerns::FieldQuery
|
4
5
|
|
5
|
-
attr_accessor :
|
6
|
+
attr_accessor :gte, :gt, :lte, :lt
|
6
7
|
|
7
8
|
def clone
|
8
9
|
prepare_clone(super)
|
@@ -12,14 +13,14 @@ module Elastic::Nodes
|
|
12
13
|
prepare_clone(super)
|
13
14
|
end
|
14
15
|
|
15
|
-
def render
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
16
|
+
def render(_options = {})
|
17
|
+
hash = {}
|
18
|
+
hash['gte'] = @gte unless @gte.nil?
|
19
|
+
hash['gt'] = @gt unless @gt.nil?
|
20
|
+
hash['lte'] = @lte unless @lte.nil?
|
21
|
+
hash['lt'] = @lt unless @lt.nil?
|
21
22
|
|
22
|
-
{ "range" => {
|
23
|
+
{ "range" => { render_field(_options) => render_boost(hash) } }
|
23
24
|
end
|
24
25
|
|
25
26
|
private
|
data/lib/elastic/nodes/search.rb
CHANGED
@@ -14,11 +14,11 @@ module Elastic::Nodes
|
|
14
14
|
@query.traverse(&_block)
|
15
15
|
end
|
16
16
|
|
17
|
-
def render
|
18
|
-
{ "query" => @query.render }.tap do |
|
19
|
-
|
20
|
-
render_hit_options(
|
21
|
-
render_aggs(
|
17
|
+
def render(_options = {})
|
18
|
+
{ "query" => @query.render(_options) }.tap do |hash|
|
19
|
+
hash["from"] = @offset if offset && offset > 0
|
20
|
+
render_hit_options(hash)
|
21
|
+
render_aggs(hash, _options)
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
@@ -30,11 +30,12 @@ module Elastic::Nodes
|
|
30
30
|
prepare_clone(super, @query.simplify)
|
31
31
|
end
|
32
32
|
|
33
|
-
def handle_result(_raw)
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
33
|
+
def handle_result(_raw, _formatter)
|
34
|
+
Elastic::Results::Root.new(
|
35
|
+
_raw['hits'] ? prepare_hits(_raw['hits']['hits'], _formatter) : [],
|
36
|
+
_raw['hits'] ? _raw['hits']['total'] : 0,
|
37
|
+
_raw['aggregations'] ? load_aggs_results(_raw['aggregations'], _formatter) : {}
|
38
|
+
)
|
38
39
|
end
|
39
40
|
|
40
41
|
private
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module Elastic::Nodes
|
2
|
+
class Sort < Base
|
3
|
+
ORDER = [:asc, :desc]
|
4
|
+
MODES = [:min, :max, :sum, :avg, :median]
|
5
|
+
|
6
|
+
attr_accessor :child
|
7
|
+
|
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
|
+
def add_score_sort(order: :desc)
|
29
|
+
raise ArgumentError, "invalid sort order #{order}" unless ORDER.include?(order.to_sym)
|
30
|
+
|
31
|
+
add_sort('_score', order: order)
|
32
|
+
end
|
33
|
+
|
34
|
+
def reset_sorts
|
35
|
+
@sorts = []
|
36
|
+
self
|
37
|
+
end
|
38
|
+
|
39
|
+
def clone
|
40
|
+
prepare_clone(super, child.try(:clone))
|
41
|
+
end
|
42
|
+
|
43
|
+
def simplify
|
44
|
+
if @sorts.empty?
|
45
|
+
child.try(:simplify)
|
46
|
+
else
|
47
|
+
prepare_clone(super, child.try(:simplify))
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def render(_options = {})
|
52
|
+
hash = child.render(_options)
|
53
|
+
hash['sort'] = render_sorts
|
54
|
+
hash
|
55
|
+
end
|
56
|
+
|
57
|
+
def handle_result(_raw, _formatter)
|
58
|
+
@child.handle_result(_raw, _formatter)
|
59
|
+
end
|
60
|
+
|
61
|
+
def traverse(&_block)
|
62
|
+
super
|
63
|
+
@child.traverse(&_block)
|
64
|
+
end
|
65
|
+
|
66
|
+
protected
|
67
|
+
|
68
|
+
attr_writer :sorts
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
def prepare_clone(_clone, _child)
|
73
|
+
_clone.child = _child
|
74
|
+
_clone.sorts = @sorts.dup
|
75
|
+
_clone
|
76
|
+
end
|
77
|
+
|
78
|
+
def render_sorts
|
79
|
+
@sorts.dup
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
data/lib/elastic/nodes/term.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
module Elastic::Nodes
|
2
2
|
class Term < Base
|
3
3
|
include Concerns::Boostable
|
4
|
+
include Concerns::FieldQuery
|
4
5
|
|
5
6
|
BOOLEAN_MODE = [:any, :all]
|
6
7
|
|
@@ -30,19 +31,19 @@ module Elastic::Nodes
|
|
30
31
|
prepare_clone(super)
|
31
32
|
end
|
32
33
|
|
33
|
-
def render
|
34
|
-
raise ArgumentError,
|
34
|
+
def render(_options = {})
|
35
|
+
raise ArgumentError, "terms not provided for #{@field}" if !@terms
|
35
36
|
|
36
37
|
if @terms.length == 1
|
37
|
-
{ 'term' => {
|
38
|
-
elsif @mode == :all
|
38
|
+
{ 'term' => { render_field(_options) => render_boost('value' => @terms.first) } }
|
39
|
+
elsif @mode == :all && !@terms.empty?
|
39
40
|
{
|
40
41
|
'bool' => render_boost(
|
41
|
-
'must' => @terms.map { |t| { 'term' => {
|
42
|
+
'must' => @terms.map { |t| { 'term' => { render_field(_options) => t } } }
|
42
43
|
)
|
43
44
|
}
|
44
45
|
else
|
45
|
-
{ 'terms' => render_boost(
|
46
|
+
{ 'terms' => render_boost(render_field(_options) => @terms) }
|
46
47
|
end
|
47
48
|
end
|
48
49
|
|
data/lib/elastic/query.rb
CHANGED
@@ -14,10 +14,6 @@ module Elastic
|
|
14
14
|
@config = _query_config || build_base_config
|
15
15
|
end
|
16
16
|
|
17
|
-
def coord_similarity(_enable)
|
18
|
-
with_clone { |config| config.root.query.disable_coord = !_enable }
|
19
|
-
end
|
20
|
-
|
21
17
|
def limit(_size)
|
22
18
|
with_clone { |config| config.limit = _size }
|
23
19
|
end
|
@@ -27,6 +23,12 @@ module Elastic
|
|
27
23
|
with_clone { |config| config.offset = _offset }
|
28
24
|
end
|
29
25
|
|
26
|
+
def sort(*_params)
|
27
|
+
with_clone do |config|
|
28
|
+
config.sort = Commands::BuildSortFromParams.for(index: index, params: _params)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
30
32
|
def segment(*_params)
|
31
33
|
with_clone do |config|
|
32
34
|
config.groups << Commands::BuildAggFromParams.for(index: index, params: _params)
|
@@ -37,8 +39,8 @@ module Elastic
|
|
37
39
|
execute assembler.assemble_ids
|
38
40
|
end
|
39
41
|
|
40
|
-
def
|
41
|
-
execute assembler.
|
42
|
+
def pick(_field)
|
43
|
+
execute assembler.assemble_pick(_field)
|
42
44
|
end
|
43
45
|
|
44
46
|
def aggregate(_name = nil, _node = nil, &_block)
|
@@ -54,6 +56,10 @@ module Elastic
|
|
54
56
|
@result ||= execute(assembler.assemble)
|
55
57
|
end
|
56
58
|
|
59
|
+
def as_query_node
|
60
|
+
@config.query.clone
|
61
|
+
end
|
62
|
+
|
57
63
|
def as_es_query
|
58
64
|
assembler.assemble.render
|
59
65
|
end
|
@@ -67,7 +73,7 @@ module Elastic
|
|
67
73
|
end
|
68
74
|
|
69
75
|
def with_bool_query(&_block)
|
70
|
-
with_clone { |config| _block.call(config.
|
76
|
+
with_clone { |config| _block.call(config.query) }
|
71
77
|
end
|
72
78
|
|
73
79
|
def with_aggregable_for_metric(&_block)
|
@@ -79,15 +85,21 @@ module Elastic
|
|
79
85
|
Core::QueryConfig.initial_config
|
80
86
|
end
|
81
87
|
|
82
|
-
def assembler
|
83
|
-
@assembler ||= Core::QueryAssembler.new(@index, @config)
|
84
|
-
end
|
85
|
-
|
86
88
|
def execute(_query)
|
87
|
-
|
89
|
+
raw = @index.adaptor.query(
|
88
90
|
type: @index.definition.types,
|
89
91
|
query: _query.render
|
90
92
|
)
|
93
|
+
|
94
|
+
_query.handle_result(raw, formatter)
|
95
|
+
end
|
96
|
+
|
97
|
+
def assembler
|
98
|
+
Core::QueryAssembler.new(@index, @config)
|
99
|
+
end
|
100
|
+
|
101
|
+
def formatter
|
102
|
+
Core::SourceFormatter.new(@index.definition)
|
91
103
|
end
|
92
104
|
|
93
105
|
class AggregableAdaptor
|