elastic-rails 0.1.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Guardfile +46 -0
- data/elastic.gemspec +13 -4
- data/lib/elastic/commands/build_agg_from_params.rb +63 -0
- data/lib/elastic/commands/build_query_from_params.rb +132 -0
- data/lib/elastic/commands/import_index_documents.rb +63 -0
- data/lib/elastic/configuration.rb +61 -0
- data/lib/elastic/core/adaptor.rb +102 -0
- data/lib/elastic/core/base_middleware.rb +43 -0
- data/lib/elastic/core/default_middleware.rb +64 -0
- data/lib/elastic/core/definition.rb +118 -0
- data/lib/elastic/core/mapping_manager.rb +120 -0
- data/lib/elastic/core/middleware.rb +26 -0
- data/lib/elastic/core/query_assembler.rb +84 -0
- data/lib/elastic/core/query_config.rb +25 -0
- data/lib/elastic/core/serializer.rb +45 -0
- data/lib/elastic/core/source_formatter.rb +40 -0
- data/lib/elastic/dsl/bool_query_builder.rb +52 -0
- data/lib/elastic/dsl/bool_query_context.rb +42 -0
- data/lib/elastic/dsl/metric_builder.rb +34 -0
- data/lib/elastic/fields/nested.rb +42 -0
- data/lib/elastic/fields/value.rb +60 -0
- data/lib/elastic/nested_type.rb +5 -0
- data/lib/elastic/nodes/agg/average.rb +7 -0
- data/lib/elastic/nodes/agg/base_metric.rb +42 -0
- data/lib/elastic/nodes/agg/date_histogram.rb +48 -0
- data/lib/elastic/nodes/agg/maximum.rb +7 -0
- data/lib/elastic/nodes/agg/minimum.rb +7 -0
- data/lib/elastic/nodes/agg/stats.rb +7 -0
- data/lib/elastic/nodes/agg/sum.rb +7 -0
- data/lib/elastic/nodes/agg/terms.rb +38 -0
- data/lib/elastic/nodes/agg/top_hits.rb +17 -0
- data/lib/elastic/nodes/and.rb +45 -0
- data/lib/elastic/nodes/base.rb +34 -0
- data/lib/elastic/nodes/base_agg.rb +32 -0
- data/lib/elastic/nodes/boolean.rb +87 -0
- data/lib/elastic/nodes/concerns/aggregable.rb +52 -0
- data/lib/elastic/nodes/concerns/boostable.rb +25 -0
- data/lib/elastic/nodes/concerns/bucketed.rb +17 -0
- data/lib/elastic/nodes/concerns/hit_provider.rb +39 -0
- data/lib/elastic/nodes/function_score.rb +116 -0
- data/lib/elastic/nodes/match.rb +45 -0
- data/lib/elastic/nodes/nested.rb +42 -0
- data/lib/elastic/nodes/or.rb +9 -0
- data/lib/elastic/nodes/range.rb +36 -0
- data/lib/elastic/nodes/search.rb +48 -0
- data/lib/elastic/nodes/term.rb +58 -0
- data/lib/elastic/query.rb +84 -22
- data/lib/elastic/railtie.rb +41 -0
- data/lib/elastic/railties/ar_helpers.rb +51 -0
- data/lib/elastic/railties/ar_middleware.rb +45 -0
- data/lib/elastic/{indexable_record.rb → railties/indexable_record.rb} +21 -18
- data/lib/elastic/railties/query_extensions.rb +9 -0
- data/lib/elastic/railties/rspec.rb +6 -0
- data/lib/elastic/railties/tasks/es.rake +19 -0
- data/lib/elastic/railties/type_extensions.rb +14 -0
- data/lib/elastic/railties/utils.rb +62 -0
- data/lib/elastic/results/aggregations.rb +29 -0
- data/lib/elastic/results/base.rb +13 -0
- data/lib/elastic/results/bucket.rb +15 -0
- data/lib/elastic/results/bucket_collection.rb +17 -0
- data/lib/elastic/results/grouped_result.rb +37 -0
- data/lib/elastic/results/hit.rb +25 -0
- data/lib/elastic/results/hit_collection.rb +38 -0
- data/lib/elastic/results/metric.rb +13 -0
- data/lib/elastic/results/result_group.rb +19 -0
- data/lib/elastic/results/root.rb +15 -0
- data/lib/elastic/shims/base.rb +23 -0
- data/lib/elastic/shims/grouping.rb +23 -0
- data/lib/elastic/shims/populating.rb +69 -0
- data/lib/elastic/shims/reducing.rb +20 -0
- data/lib/elastic/support/command.rb +34 -0
- data/lib/elastic/support/transform.rb +37 -0
- data/lib/elastic/support/traversable.rb +22 -0
- data/lib/elastic/type.rb +56 -84
- data/lib/elastic/types/base_type.rb +38 -0
- data/lib/elastic/types/faceted_type.rb +16 -0
- data/lib/elastic/types/nestable_type.rb +14 -0
- data/lib/elastic/version.rb +1 -1
- data/lib/elastic.rb +72 -30
- data/lib/generators/elastic/index_generator.rb +10 -0
- data/lib/generators/elastic/templates/index.rb +17 -0
- metadata +222 -16
- data/lib/elastic/capabilities/aggregation_builder.rb +0 -64
- data/lib/elastic/capabilities/bool_query_builder.rb +0 -74
- data/lib/elastic/capabilities/context_handler.rb +0 -31
- data/lib/elastic/histogram.rb +0 -49
- data/lib/elastic/index.rb +0 -113
- data/lib/elastic/indexable.rb +0 -25
- data/lib/elastic/value_transform.rb +0 -15
@@ -0,0 +1,42 @@
|
|
1
|
+
module Elastic::Nodes::Agg
|
2
|
+
class BaseMetric < Elastic::Nodes::BaseAgg
|
3
|
+
def self.build(_name, _field, missing: nil)
|
4
|
+
super(_name).tap do |node|
|
5
|
+
node.field = _field
|
6
|
+
node.missing = missing
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
attr_accessor :field, :missing
|
11
|
+
|
12
|
+
def clone
|
13
|
+
prepare_clone super
|
14
|
+
end
|
15
|
+
|
16
|
+
def simplify
|
17
|
+
prepare_clone super
|
18
|
+
end
|
19
|
+
|
20
|
+
def render
|
21
|
+
options = { 'field' => @field.to_s }
|
22
|
+
options['missing'] = @missing if @missing
|
23
|
+
|
24
|
+
{ metric => options }
|
25
|
+
end
|
26
|
+
|
27
|
+
def handle_result(_raw)
|
28
|
+
Elastic::Results::Metric.new _raw['value']
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def metric
|
34
|
+
end
|
35
|
+
|
36
|
+
def prepare_clone(_clone)
|
37
|
+
_clone.field = @field
|
38
|
+
_clone.missing = @missing
|
39
|
+
_clone
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Elastic::Nodes::Agg
|
2
|
+
class DateHistogram < Elastic::Nodes::BaseAgg
|
3
|
+
include Elastic::Nodes::Concerns::Aggregable
|
4
|
+
include Elastic::Nodes::Concerns::Bucketed
|
5
|
+
|
6
|
+
def self.build(_name, _field, interval: nil)
|
7
|
+
super(_name).tap do |node|
|
8
|
+
node.field = _field
|
9
|
+
node.interval = interval
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
attr_accessor :field
|
14
|
+
attr_reader :interval
|
15
|
+
|
16
|
+
def interval=(_value)
|
17
|
+
raise ArgumentError, 'invalid interval' if _value && !valid_interval?(_value)
|
18
|
+
@interval = _value
|
19
|
+
end
|
20
|
+
|
21
|
+
def clone
|
22
|
+
prepare_clone(super)
|
23
|
+
end
|
24
|
+
|
25
|
+
def simplify
|
26
|
+
prepare_clone(super)
|
27
|
+
end
|
28
|
+
|
29
|
+
def render
|
30
|
+
options = { 'field' => @field.to_s }
|
31
|
+
options['interval'] = @interval if @interval
|
32
|
+
|
33
|
+
render_aggs 'date_histogram' => options
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def prepare_clone(_clone)
|
39
|
+
_clone.field = @field
|
40
|
+
_clone.interval = @interval
|
41
|
+
_clone
|
42
|
+
end
|
43
|
+
|
44
|
+
def valid_interval?(_value)
|
45
|
+
/^\d+(\.\d+)?(y|M|w|d|h|m|s)$/ === _value
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Elastic::Nodes::Agg
|
2
|
+
class Terms < Elastic::Nodes::BaseAgg
|
3
|
+
include Elastic::Nodes::Concerns::Aggregable
|
4
|
+
include Elastic::Nodes::Concerns::Bucketed
|
5
|
+
|
6
|
+
def self.build(_name, _field, size: nil)
|
7
|
+
super(_name).tap do |node|
|
8
|
+
node.field = _field
|
9
|
+
node.size = size
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
attr_accessor :field, :size
|
14
|
+
|
15
|
+
def clone
|
16
|
+
prepare_clone(super)
|
17
|
+
end
|
18
|
+
|
19
|
+
def simplify
|
20
|
+
prepare_clone(super)
|
21
|
+
end
|
22
|
+
|
23
|
+
def render
|
24
|
+
options = { 'field' => @field.to_s }
|
25
|
+
options['size'] = @size if @size
|
26
|
+
|
27
|
+
render_aggs 'terms' => options
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def prepare_clone(_clone)
|
33
|
+
_clone.field = @field
|
34
|
+
_clone.size = @size
|
35
|
+
_clone
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Elastic::Nodes
|
2
|
+
class TopHits < BaseAgg
|
3
|
+
include Concerns::HitProvider
|
4
|
+
|
5
|
+
def render
|
6
|
+
options = {}
|
7
|
+
render_hit_options options
|
8
|
+
|
9
|
+
{ 'top_hits' => options }
|
10
|
+
end
|
11
|
+
|
12
|
+
def handle_result(_raw)
|
13
|
+
hits = _raw['hits'] ? _raw['hits']['hits'].map { |h| Elastic::Results::Hit.new h } : []
|
14
|
+
Elastic::Results::HitCollection.new(hits)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Elastic::Nodes
|
2
|
+
class And < Base
|
3
|
+
def self.build(_children)
|
4
|
+
new.tap { |node| node.children = _children }
|
5
|
+
end
|
6
|
+
|
7
|
+
def add_child(_child)
|
8
|
+
@children << _child
|
9
|
+
end
|
10
|
+
|
11
|
+
def children=(_value)
|
12
|
+
@children = _value.dup.to_a
|
13
|
+
end
|
14
|
+
|
15
|
+
def traverse(&_block)
|
16
|
+
super
|
17
|
+
@children.each { |c| c.traverse(&_block) }
|
18
|
+
end
|
19
|
+
|
20
|
+
def clone
|
21
|
+
prepare_clone super, @children.map(&:clone)
|
22
|
+
end
|
23
|
+
|
24
|
+
def simplify
|
25
|
+
new_children = @children.map(&:simplify)
|
26
|
+
return new_children.first if new_children.count == 1
|
27
|
+
prepare_clone(super, new_children)
|
28
|
+
end
|
29
|
+
|
30
|
+
def render
|
31
|
+
{ operation => @children.map(&:render) }
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def prepare_clone(_clone, _children)
|
37
|
+
_clone.children = _children
|
38
|
+
_clone
|
39
|
+
end
|
40
|
+
|
41
|
+
def operation
|
42
|
+
'and'
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Elastic::Nodes
|
2
|
+
class Base
|
3
|
+
include Elastic::Support::Traversable
|
4
|
+
|
5
|
+
def ==(_node)
|
6
|
+
render == _node.render
|
7
|
+
end
|
8
|
+
|
9
|
+
def traverse(&_block)
|
10
|
+
_block.call(self)
|
11
|
+
end
|
12
|
+
|
13
|
+
def render
|
14
|
+
raise NotImplementedError, 'render must be implemented by each node'
|
15
|
+
end
|
16
|
+
|
17
|
+
def clone
|
18
|
+
self.class.new
|
19
|
+
end
|
20
|
+
|
21
|
+
def simplify
|
22
|
+
self.class.new
|
23
|
+
end
|
24
|
+
|
25
|
+
def handle_result(_raw)
|
26
|
+
nil
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
require "elastic/nodes/concerns/hit_provider"
|
32
|
+
require "elastic/nodes/concerns/aggregable"
|
33
|
+
require "elastic/nodes/concerns/bucketed"
|
34
|
+
require "elastic/nodes/concerns/boostable"
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Elastic::Nodes
|
2
|
+
class BaseAgg < Base
|
3
|
+
attr_reader :name
|
4
|
+
|
5
|
+
def self.build(_name)
|
6
|
+
new.tap { |n| n.name = _name }
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@name = 'default'
|
11
|
+
end
|
12
|
+
|
13
|
+
def name=(_value)
|
14
|
+
@name = _value.to_s
|
15
|
+
end
|
16
|
+
|
17
|
+
def clone
|
18
|
+
copy_name super
|
19
|
+
end
|
20
|
+
|
21
|
+
def simplify
|
22
|
+
copy_name super
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def copy_name(_clone)
|
28
|
+
_clone.name = @name
|
29
|
+
_clone
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
module Elastic::Nodes
|
2
|
+
class Boolean < Base
|
3
|
+
include Concerns::Boostable
|
4
|
+
|
5
|
+
def self.build_and(_nodes)
|
6
|
+
new.tap { |n| n.musts = _nodes }
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.build_or(_nodes)
|
10
|
+
new.tap { |n| n.shoulds = _nodes }
|
11
|
+
end
|
12
|
+
|
13
|
+
attr_accessor :minimum_should_match, :disable_coord
|
14
|
+
|
15
|
+
def initialize
|
16
|
+
super
|
17
|
+
@musts = []
|
18
|
+
@shoulds = []
|
19
|
+
end
|
20
|
+
|
21
|
+
def must(_node)
|
22
|
+
@musts << _node
|
23
|
+
end
|
24
|
+
|
25
|
+
def should(_node)
|
26
|
+
@shoulds << _node
|
27
|
+
end
|
28
|
+
|
29
|
+
def musts=(_nodes)
|
30
|
+
@musts = _nodes.dup.to_a
|
31
|
+
end
|
32
|
+
|
33
|
+
def musts
|
34
|
+
@musts.each
|
35
|
+
end
|
36
|
+
|
37
|
+
def shoulds=(_nodes)
|
38
|
+
@shoulds = _nodes.dup.to_a
|
39
|
+
end
|
40
|
+
|
41
|
+
def shoulds
|
42
|
+
@shoulds.each
|
43
|
+
end
|
44
|
+
|
45
|
+
def traverse(&_block)
|
46
|
+
super
|
47
|
+
@shoulds.each { |c| c.traverse(&_block) }
|
48
|
+
@musts.each { |c| c.traverse(&_block) }
|
49
|
+
end
|
50
|
+
|
51
|
+
def render
|
52
|
+
options = {}.tap do |boolean|
|
53
|
+
boolean['must'] = @musts.map(&:render) if !@musts.empty?
|
54
|
+
boolean['should'] = @shoulds.map(&:render) if !@shoulds.empty?
|
55
|
+
boolean['minimum_should_match'] = minimum_should_match unless minimum_should_match.nil?
|
56
|
+
boolean['disable_coord'] = true if disable_coord
|
57
|
+
render_boost(boolean)
|
58
|
+
end
|
59
|
+
|
60
|
+
{ "bool" => options }
|
61
|
+
end
|
62
|
+
|
63
|
+
def clone
|
64
|
+
prepare_clone super, @musts.map(&:clone), @shoulds.map(&:clone)
|
65
|
+
end
|
66
|
+
|
67
|
+
def simplify
|
68
|
+
new_must = @musts.map(&:simplify)
|
69
|
+
new_should = @shoulds.map(&:simplify)
|
70
|
+
|
71
|
+
return new_must.first if new_must.length == 1 && new_should.empty?
|
72
|
+
return new_should.first if new_should.length == 1 && new_must.empty? # at least 1 should match
|
73
|
+
|
74
|
+
prepare_clone(super, new_must, new_should)
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
def prepare_clone(_clone, _musts, _shoulds)
|
80
|
+
_clone.musts = _musts
|
81
|
+
_clone.shoulds = _shoulds
|
82
|
+
_clone.minimum_should_match = @minimum_should_match
|
83
|
+
_clone.disable_coord = @disable_coord
|
84
|
+
_clone
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Elastic::Nodes::Concerns
|
2
|
+
module Aggregable
|
3
|
+
def has_aggs?
|
4
|
+
aggs.count > 0
|
5
|
+
end
|
6
|
+
|
7
|
+
def aggs=(_aggs)
|
8
|
+
@aggs = _aggs.dup.to_a
|
9
|
+
end
|
10
|
+
|
11
|
+
def aggregate(_node)
|
12
|
+
raise ArgumentError, 'node must provide a name' unless _node.name
|
13
|
+
aggs << _node
|
14
|
+
end
|
15
|
+
|
16
|
+
def traverse(&_block)
|
17
|
+
super
|
18
|
+
aggs.each { |a| a.traverse(&_block) }
|
19
|
+
end
|
20
|
+
|
21
|
+
def clone
|
22
|
+
node = super
|
23
|
+
node.aggs = aggs.map(&:clone)
|
24
|
+
node
|
25
|
+
end
|
26
|
+
|
27
|
+
def simplify
|
28
|
+
node = super
|
29
|
+
node.aggs = aggs.map(&:simplify)
|
30
|
+
node
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def aggs
|
36
|
+
@aggs ||= []
|
37
|
+
end
|
38
|
+
|
39
|
+
def render_aggs(_into)
|
40
|
+
_into['aggs'] = Hash[aggs.map { |a| [a.name, a.render] }] if has_aggs?
|
41
|
+
_into
|
42
|
+
end
|
43
|
+
|
44
|
+
def load_aggs_results(_raw)
|
45
|
+
{}.tap do |result|
|
46
|
+
aggs.each do |node|
|
47
|
+
result[node.name] = node.handle_result(_raw[node.name])
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Elastic::Nodes::Concerns
|
2
|
+
module Boostable
|
3
|
+
attr_accessor :boost
|
4
|
+
|
5
|
+
def clone
|
6
|
+
copy_boost super
|
7
|
+
end
|
8
|
+
|
9
|
+
def simplify
|
10
|
+
copy_boost super
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def copy_boost(_clone)
|
16
|
+
_clone.boost = @boost
|
17
|
+
_clone
|
18
|
+
end
|
19
|
+
|
20
|
+
def render_boost(_hash)
|
21
|
+
_hash['boost'] = @boost.to_f unless @boost.nil?
|
22
|
+
_hash
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Elastic::Nodes::Concerns
|
2
|
+
module Bucketed
|
3
|
+
def handle_result(_raw)
|
4
|
+
buckets = _raw['buckets'].map do |raw_bucket|
|
5
|
+
aggs = load_aggs_results(raw_bucket)
|
6
|
+
|
7
|
+
# TODO: allow bucket aggregation to return single nested aggregation if node is
|
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)
|
12
|
+
end
|
13
|
+
|
14
|
+
Elastic::Results::BucketCollection.new buckets
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Elastic::Nodes::Concerns
|
2
|
+
module HitProvider
|
3
|
+
attr_accessor :size
|
4
|
+
attr_reader :source
|
5
|
+
|
6
|
+
def source=(_values)
|
7
|
+
case _values
|
8
|
+
when nil, false
|
9
|
+
@source = _values
|
10
|
+
when Array, Enumerable
|
11
|
+
@source = _values.dup.to_a
|
12
|
+
else
|
13
|
+
raise ArgumentError, 'invalid query source value'
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def clone
|
18
|
+
copy_hit_options super
|
19
|
+
end
|
20
|
+
|
21
|
+
def simplify
|
22
|
+
copy_hit_options super
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def copy_hit_options(_clone)
|
28
|
+
_clone.size = @size
|
29
|
+
_clone.source = @source
|
30
|
+
_clone
|
31
|
+
end
|
32
|
+
|
33
|
+
def render_hit_options(_hash)
|
34
|
+
_hash['size'] = @size unless @size.nil?
|
35
|
+
_hash["_source"] = @source unless @source.nil?
|
36
|
+
_hash
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
module Elastic::Nodes
|
2
|
+
class FunctionScore < Base
|
3
|
+
include Concerns::Boostable
|
4
|
+
|
5
|
+
SCORE_MODES = [:multiply, :sum, :avg, :first, :max, :min]
|
6
|
+
BOOST_MODES = [:multiply, :replace, :sum, :avg, :max, :min]
|
7
|
+
|
8
|
+
def self.build(_query)
|
9
|
+
new.tap { |node| node.query = _query }
|
10
|
+
end
|
11
|
+
|
12
|
+
attr_accessor :query
|
13
|
+
attr_reader :score_mode, :boost_mode
|
14
|
+
|
15
|
+
def initialize
|
16
|
+
@functions = []
|
17
|
+
end
|
18
|
+
|
19
|
+
def functions=(_values)
|
20
|
+
@functions = _values.dup.to_a
|
21
|
+
end
|
22
|
+
|
23
|
+
def score_mode=(_value)
|
24
|
+
raise ArgumentError, "invalid score mode #{_value}" if _value && !SCORE_MODES.include?(_value)
|
25
|
+
@score_mode = _value
|
26
|
+
end
|
27
|
+
|
28
|
+
def boost_mode=(_value)
|
29
|
+
raise ArgumentError, "invalid boost mode #{_value}" if _value && !BOOST_MODES.include?(_value)
|
30
|
+
@boost_mode = _value
|
31
|
+
end
|
32
|
+
|
33
|
+
def add_weight_function(_weight, filter: nil)
|
34
|
+
add_function(nil, nil, filter, _weight)
|
35
|
+
end
|
36
|
+
|
37
|
+
def add_field_function(_field, factor: 1, modifier: :none, missing: 1, weight: nil, filter: nil)
|
38
|
+
params = {
|
39
|
+
'field' => _field,
|
40
|
+
'factor' => factor,
|
41
|
+
'modifier' => modifier,
|
42
|
+
'missing' => missing
|
43
|
+
}
|
44
|
+
|
45
|
+
add_function('field_value_factor', params, filter, weight)
|
46
|
+
end
|
47
|
+
|
48
|
+
def add_decay_function(_field, _options = {})
|
49
|
+
raise NotImplementedError, 'decay function not implemented'
|
50
|
+
end
|
51
|
+
|
52
|
+
def traverse(&_block)
|
53
|
+
super
|
54
|
+
@query.traverse(&_block)
|
55
|
+
end
|
56
|
+
|
57
|
+
def render
|
58
|
+
function_score = { 'query' => @query.render }
|
59
|
+
function_score['boost_mode'] = @boost_mode.to_s if @boost_mode && @boost_mode != :multiply
|
60
|
+
|
61
|
+
if @functions.length > 1
|
62
|
+
function_score['score_mode'] = @score_mode.to_s if @score_mode && @score_mode != :multiply
|
63
|
+
function_score['functions'] = @functions
|
64
|
+
elsif @functions.length == 1
|
65
|
+
function_score.merge! @functions.first
|
66
|
+
end
|
67
|
+
|
68
|
+
{ 'function_score' => render_boost(function_score) }
|
69
|
+
end
|
70
|
+
|
71
|
+
alias :super_clone :clone
|
72
|
+
private :super_clone
|
73
|
+
|
74
|
+
def clone
|
75
|
+
prepare_clone super, @query.clone
|
76
|
+
end
|
77
|
+
|
78
|
+
def clone_with_query(_query)
|
79
|
+
prepare_clone super_clone, _query
|
80
|
+
end
|
81
|
+
|
82
|
+
def simplify
|
83
|
+
new_query = query.simplify
|
84
|
+
|
85
|
+
if @functions.empty?
|
86
|
+
return new_query if boost.nil?
|
87
|
+
|
88
|
+
if new_query.class.include?(Concerns::Boostable) && new_query.boost.nil?
|
89
|
+
new_query.boost = boost
|
90
|
+
return new_query
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
prepare_clone(super, new_query)
|
95
|
+
end
|
96
|
+
|
97
|
+
private
|
98
|
+
|
99
|
+
def add_function(_function, _params, _filter, _weight)
|
100
|
+
@functions << {}.tap do |hash|
|
101
|
+
hash[_function] = _params if _function
|
102
|
+
hash['weight'] = _weight unless _weight.nil?
|
103
|
+
hash['filter'] = _filter.render unless _filter.nil?
|
104
|
+
end
|
105
|
+
self
|
106
|
+
end
|
107
|
+
|
108
|
+
def prepare_clone(_clone, _query)
|
109
|
+
_clone.query = _query
|
110
|
+
_clone.functions = @functions
|
111
|
+
_clone.boost_mode = @boost_mode
|
112
|
+
_clone.score_mode = @score_mode
|
113
|
+
_clone
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Elastic::Nodes
|
2
|
+
class Match < Base
|
3
|
+
include Concerns::Boostable
|
4
|
+
|
5
|
+
MATCH_MODES = [:boolean, :phrase, :phrase_prefix]
|
6
|
+
|
7
|
+
attr_accessor :field, :query
|
8
|
+
attr_reader :mode
|
9
|
+
|
10
|
+
def query=(_query)
|
11
|
+
raise ArgumentError, 'query must be a string' unless _query.is_a? String
|
12
|
+
@query = _query
|
13
|
+
end
|
14
|
+
|
15
|
+
def mode=(_value)
|
16
|
+
_value = _value.try(:to_sym)
|
17
|
+
raise ArgumentError, 'invalid match mode' if !_value.nil? && !MATCH_MODES.include?(_value)
|
18
|
+
@mode = _value
|
19
|
+
end
|
20
|
+
|
21
|
+
def clone
|
22
|
+
prepare_clone(super)
|
23
|
+
end
|
24
|
+
|
25
|
+
def simplify
|
26
|
+
prepare_clone(super)
|
27
|
+
end
|
28
|
+
|
29
|
+
def render
|
30
|
+
query_options = { 'query' => @query }
|
31
|
+
query_options['type'] = @mode.to_s unless @mode.nil? || @mode == :boolean
|
32
|
+
|
33
|
+
{ "match" => { @field.to_s => render_boost(query_options) } }
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def prepare_clone(_clone)
|
39
|
+
_clone.field = @field
|
40
|
+
_clone.query = @query
|
41
|
+
_clone.mode = @mode
|
42
|
+
_clone
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|