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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a85d4715234d67d4dac798756ad8c63b62b8aeb2
|
4
|
+
data.tar.gz: fa4bb1a83eae9d73ab8c1ce7717f4232922bd6f0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c95fda8f2273c68285ee7bfc02c7f5b01bceccdfef74c3ad2dfa86d8d5cd27420a4c4598c608ba535900c2268030dea3ced38bbed62db35a6b0f037c3630866d
|
7
|
+
data.tar.gz: 1600194a988639918c4810d0bfebf9be14c24c9b9f78eb2ed64b9f64ed8e46ae82c03c2b38d8c563f229f42910c2823284ec8fafd34097ff8bd41f1b77484c10
|
@@ -2,7 +2,8 @@ module Elastic::Commands
|
|
2
2
|
class BuildAggFromParams < Elastic::Support::Command.new(:index, :params)
|
3
3
|
def perform
|
4
4
|
parse_params
|
5
|
-
raise ArgumentError, "field not mapped
|
5
|
+
raise ArgumentError, "#{@field} not mapped" if field_definition.nil?
|
6
|
+
raise ArgumentError, "cant aggregate on #{@field}" if field_definition.nested?
|
6
7
|
|
7
8
|
path = parse_nesting_path
|
8
9
|
raise NotImplementedError, "nested paths not yet supported in aggregations" if path
|
@@ -12,10 +13,6 @@ module Elastic::Commands
|
|
12
13
|
|
13
14
|
private
|
14
15
|
|
15
|
-
def agg_name
|
16
|
-
@options.fetch(:as, @field)
|
17
|
-
end
|
18
|
-
|
19
16
|
def parse_params
|
20
17
|
@field = params[0].to_s
|
21
18
|
@options = params[1] || {}
|
@@ -28,36 +25,56 @@ module Elastic::Commands
|
|
28
25
|
end
|
29
26
|
|
30
27
|
def build_node
|
31
|
-
|
32
|
-
|
28
|
+
agg_type = infer_agg_type
|
29
|
+
raise "aggregation not supported by #{@field}" if agg_type.nil?
|
30
|
+
|
31
|
+
node_options = field_definition.public_send("#{agg_type}_aggregation_defaults")
|
32
|
+
node_options = node_options.merge(@options)
|
33
|
+
send("build_#{agg_type}", node_options)
|
34
|
+
end
|
33
35
|
|
34
|
-
|
36
|
+
def infer_agg_type
|
37
|
+
alternatives = infer_type_options
|
38
|
+
if alternatives.nil?
|
39
|
+
field_definition.supported_aggregations.first
|
40
|
+
else
|
41
|
+
field_definition.supported_aggregations.find { |q| alternatives.include? q }
|
42
|
+
end
|
35
43
|
end
|
36
44
|
|
37
|
-
def
|
38
|
-
return :
|
45
|
+
def infer_type_options
|
46
|
+
return [@options[:type].to_sym] if @options.key? :type
|
47
|
+
return [:range] if @options.key? :ranges
|
48
|
+
return [:histogram, :date_histogram] if @options.key? :interval
|
49
|
+
nil
|
50
|
+
end
|
39
51
|
|
40
|
-
|
41
|
-
|
42
|
-
|
52
|
+
def apply_query_defaults(_agg_type, _options)
|
53
|
+
_definition.default_options_for(query: _query_type).merge(_options)
|
54
|
+
end
|
43
55
|
|
44
|
-
|
56
|
+
def field_definition
|
57
|
+
@field_definition ||= index.definition.get_field @field
|
45
58
|
end
|
46
59
|
|
47
|
-
def build_range
|
60
|
+
def build_range(_options)
|
48
61
|
raise NotImplementedError, 'range aggregation not yet implemented'
|
49
62
|
end
|
50
63
|
|
51
|
-
def build_histogram
|
64
|
+
def build_histogram(_options)
|
52
65
|
raise NotImplementedError, 'histogram aggregation not yet implemented'
|
53
66
|
end
|
54
67
|
|
55
|
-
def build_date_histogram
|
56
|
-
Elastic::Nodes::Agg::DateHistogram.build(agg_name, @field, interval:
|
68
|
+
def build_date_histogram(_options)
|
69
|
+
Elastic::Nodes::Agg::DateHistogram.build(agg_name, @field, interval: _options[:interval])
|
70
|
+
end
|
71
|
+
|
72
|
+
def build_terms(_options)
|
73
|
+
Elastic::Nodes::Agg::Terms.build(agg_name, @field, size: _options[:size])
|
57
74
|
end
|
58
75
|
|
59
|
-
def
|
60
|
-
|
76
|
+
def agg_name
|
77
|
+
@options.fetch(:as, @field)
|
61
78
|
end
|
62
79
|
end
|
63
80
|
end
|
@@ -1,20 +1,10 @@
|
|
1
1
|
module Elastic::Commands
|
2
|
-
class BuildQueryFromParams < Elastic::Support::Command.new(
|
3
|
-
:index, :params, block: nil, prefix: nil
|
4
|
-
)
|
5
|
-
|
2
|
+
class BuildQueryFromParams < Elastic::Support::Command.new(:index, :params, block: nil)
|
6
3
|
def perform
|
7
4
|
if block
|
8
5
|
# TODO: builder mode, support nesting through first parameter
|
9
6
|
else
|
10
|
-
node =
|
11
|
-
Elastic::Nodes::Boolean.build_and(part.map do |field, options|
|
12
|
-
field = field.to_s
|
13
|
-
path = get_nesting_path field
|
14
|
-
query_node = build_query_node(field, options)
|
15
|
-
path.nil? ? query_node : Elastic::Nodes::Nested.build(with_prefix(path), query_node)
|
16
|
-
end)
|
17
|
-
end)
|
7
|
+
node = build_or_node(params)
|
18
8
|
end
|
19
9
|
|
20
10
|
node.simplify
|
@@ -22,111 +12,151 @@ module Elastic::Commands
|
|
22
12
|
|
23
13
|
private
|
24
14
|
|
25
|
-
def
|
26
|
-
|
27
|
-
|
28
|
-
|
15
|
+
def build_or_node(_array)
|
16
|
+
Elastic::Nodes::Boolean.build_or(_array.map do |part|
|
17
|
+
case part
|
18
|
+
when Elastic::Query
|
19
|
+
extract_query_node part
|
20
|
+
when Hash
|
21
|
+
build_and_node part
|
22
|
+
else
|
23
|
+
raise ArgumentError, "expected hash or query but got #{part.class}"
|
24
|
+
end
|
25
|
+
end)
|
29
26
|
end
|
30
27
|
|
31
|
-
def
|
32
|
-
|
33
|
-
|
28
|
+
def extract_query_node(_query)
|
29
|
+
raise ArgumentError, "query type mismatch, expected #{index.class}" if _query.index != index
|
30
|
+
_query.as_query_node
|
31
|
+
end
|
34
32
|
|
35
|
-
|
36
|
-
|
33
|
+
def build_and_node(_hash)
|
34
|
+
Elastic::Nodes::Boolean.build_and(_hash.map do |field, options|
|
35
|
+
build_query_node field, options
|
36
|
+
end)
|
37
37
|
end
|
38
38
|
|
39
|
-
def
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
nil
|
39
|
+
def build_query_node(_field, _options)
|
40
|
+
path, field = split_nesting_path(_field.to_s)
|
41
|
+
if path
|
42
|
+
definition = resolve_field_defintion! path
|
43
|
+
raise ArgumentError, "invalid nesting path #{path}" unless definition.nested?
|
44
|
+
build_nested_query(path, definition, field => _options)
|
45
|
+
else
|
46
|
+
build_regular_query(field, _options)
|
47
|
+
end
|
49
48
|
end
|
50
49
|
|
51
|
-
def
|
52
|
-
|
53
|
-
|
50
|
+
def split_nesting_path(_field)
|
51
|
+
dot_index = _field.rindex('.')
|
52
|
+
return [nil, _field] if dot_index.nil?
|
53
|
+
[_field[0..dot_index - 1], _field[dot_index + 1..-1]]
|
54
54
|
end
|
55
55
|
|
56
|
-
def
|
57
|
-
|
58
|
-
raise ArgumentError, "field not mapped: #{_field}" if properties.nil?
|
56
|
+
def build_regular_query(_field, _options)
|
57
|
+
definition = resolve_field_defintion!(_field)
|
59
58
|
|
60
|
-
|
61
|
-
|
62
|
-
prepare_nested_options _options, properties
|
63
|
-
when 'string'
|
64
|
-
prepare_string_options _options, properties
|
59
|
+
if definition.nested?
|
60
|
+
build_nested_query(_field, definition, _options)
|
65
61
|
else
|
66
|
-
|
62
|
+
query_type = infer_query_type definition, _options
|
63
|
+
raise "query not supported by #{_field}" if query_type.nil?
|
64
|
+
_options = option_to_hash(query_type, _options) unless _options.is_a? Hash
|
65
|
+
_options = definition.public_send("#{query_type}_query_defaults").merge(_options)
|
66
|
+
|
67
|
+
send("build_#{query_type}", definition, _options)
|
67
68
|
end
|
68
69
|
end
|
69
70
|
|
70
|
-
def
|
71
|
-
|
72
|
-
|
71
|
+
def resolve_field_defintion!(_path)
|
72
|
+
definition = index.definition.get_field _path
|
73
|
+
raise ArgumentError, "field not mapped: #{_path}" if definition.nil?
|
74
|
+
definition
|
73
75
|
end
|
74
76
|
|
75
|
-
def
|
76
|
-
|
77
|
-
|
77
|
+
def infer_query_type(_definition, _options)
|
78
|
+
alternatives = infer_query_type_from_options(_options)
|
79
|
+
if alternatives.nil?
|
80
|
+
_definition.supported_queries.first
|
81
|
+
else
|
82
|
+
_definition.supported_queries.find { |q| alternatives.include? q }
|
83
|
+
end
|
78
84
|
end
|
79
85
|
|
80
|
-
def
|
81
|
-
|
82
|
-
|
83
|
-
|
86
|
+
def build_nested_query(_path, _definition, _query)
|
87
|
+
case _query
|
88
|
+
when Elastic::NestedQuery
|
89
|
+
if _query.index != _definition.index
|
90
|
+
raise ArgumentError,
|
91
|
+
"query type mismatch for #{_path}, expected #{_definition.index.class}"
|
92
|
+
end
|
93
|
+
|
94
|
+
return _query.as_node.tap { |node| node.path = _path }
|
95
|
+
when Hash
|
96
|
+
_query = [_query]
|
97
|
+
end
|
98
|
+
|
99
|
+
nested_node = BuildQueryFromParams.for(index: _definition.index, params: _query)
|
100
|
+
Elastic::Nodes::Nested.build _path, nested_node
|
84
101
|
end
|
85
102
|
|
86
|
-
def
|
87
|
-
|
88
|
-
|
103
|
+
def infer_query_type_from_options(_options)
|
104
|
+
case _options
|
105
|
+
when Hash
|
106
|
+
return [_options[:type].to_sym] if _options.key?(:type)
|
107
|
+
return [:term] if _options.key?(:term) || _options.key?(:terms)
|
108
|
+
return [:match] if _options.key? :matches
|
109
|
+
return [:range] if _options.key?(:gte) || _options.key?(:gt)
|
110
|
+
return [:range] if _options.key?(:lte) || _options.key?(:lt)
|
111
|
+
when String, Symbol
|
112
|
+
return [:term, :match]
|
113
|
+
when Array
|
114
|
+
return [:term]
|
115
|
+
when Range
|
116
|
+
return [:range]
|
117
|
+
end
|
118
|
+
|
119
|
+
nil
|
120
|
+
end
|
89
121
|
|
90
|
-
|
91
|
-
|
122
|
+
def option_to_hash(_query_type, _value)
|
123
|
+
case _query_type
|
124
|
+
when :term
|
125
|
+
{ terms: _value }
|
126
|
+
when :match
|
127
|
+
{ matches: _value.to_s }
|
128
|
+
when :range
|
129
|
+
{ gte: _value.begin, (_value.exclude_end? ? :lt : :lte) => _value.end }
|
130
|
+
end
|
92
131
|
end
|
93
132
|
|
133
|
+
# NOTE: the following methods could be placed in separate factories.
|
134
|
+
|
94
135
|
def build_term(_field, _options)
|
95
|
-
terms = Array(_options
|
136
|
+
terms = Array(_options.fetch(:term, _options[:terms]))
|
96
137
|
|
97
138
|
Elastic::Nodes::Term.new.tap do |node|
|
98
|
-
node.field = _field
|
139
|
+
node.field = _field.name
|
99
140
|
node.mode = _options[:mode]
|
100
|
-
node.terms = terms.map { |t|
|
141
|
+
node.terms = terms.map { |t| _field.prepare_value_for_query(t) }
|
101
142
|
end
|
102
143
|
end
|
103
144
|
|
104
145
|
def build_range(_field, _options)
|
105
146
|
Elastic::Nodes::Range.new.tap do |node|
|
106
|
-
node.field = _field
|
107
|
-
node.gte =
|
108
|
-
node.gt =
|
109
|
-
node.lte =
|
110
|
-
node.lt =
|
147
|
+
node.field = _field.name
|
148
|
+
node.gte = _field.prepare_value_for_query(_options[:gte]) if _options.key? :gte
|
149
|
+
node.gt = _field.prepare_value_for_query(_options[:gt]) if _options.key? :gt
|
150
|
+
node.lte = _field.prepare_value_for_query(_options[:lte]) if _options.key? :lte
|
151
|
+
node.lt = _field.prepare_value_for_query(_options[:lt]) if _options.key? :lt
|
111
152
|
end
|
112
153
|
end
|
113
154
|
|
114
155
|
def build_match(_field, _options)
|
115
156
|
Elastic::Nodes::Match.new.tap do |node|
|
116
|
-
node.field = _field
|
117
|
-
node.query =
|
157
|
+
node.field = _field.name
|
158
|
+
node.query = _field.prepare_value_for_query(_options[:matches])
|
118
159
|
end
|
119
160
|
end
|
120
|
-
|
121
|
-
def range_to_options(_range)
|
122
|
-
{
|
123
|
-
gte: _range.begin,
|
124
|
-
(_range.exclude_end? ? :lt : :lte) => _range.end
|
125
|
-
}
|
126
|
-
end
|
127
|
-
|
128
|
-
def prep(_field, _value)
|
129
|
-
index.definition.get_field(_field).prepare_value_for_query(_value)
|
130
|
-
end
|
131
161
|
end
|
132
162
|
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Elastic::Commands
|
2
|
+
class BuildSortFromParams < Elastic::Support::Command.new(:index, :params)
|
3
|
+
def perform
|
4
|
+
params.each do |param|
|
5
|
+
case param
|
6
|
+
when Hash
|
7
|
+
param.each { |field, options| add_sort field, options }
|
8
|
+
else
|
9
|
+
add_sort param
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
node.add_score_sort
|
14
|
+
node
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def node
|
20
|
+
@node ||= Elastic::Nodes::Sort.new
|
21
|
+
end
|
22
|
+
|
23
|
+
def add_sort(_field, _options = {})
|
24
|
+
_field = _field.to_s
|
25
|
+
_options = { order: _options } unless _options.is_a? Hash
|
26
|
+
|
27
|
+
raise ArgumentError, "field not mapped: #{_field}" unless index.definition.has_field? _field
|
28
|
+
|
29
|
+
path = parse_nesting_path(_field)
|
30
|
+
raise NotImplementedError, "nested fields not yet supported in sorting" if path
|
31
|
+
|
32
|
+
node.add_sort(_field, _options)
|
33
|
+
end
|
34
|
+
|
35
|
+
def parse_nesting_path(_field)
|
36
|
+
dot_index = _field.rindex('.')
|
37
|
+
return nil if dot_index.nil?
|
38
|
+
_field.slice(0, dot_index)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -14,7 +14,7 @@ module Elastic::Commands
|
|
14
14
|
private
|
15
15
|
|
16
16
|
def import_collection
|
17
|
-
main_target.
|
17
|
+
main_target.collect_from(collection, middleware_options) { |obj| queue obj }
|
18
18
|
end
|
19
19
|
|
20
20
|
def import_target(_target)
|
@@ -1,13 +1,26 @@
|
|
1
1
|
module Elastic
|
2
2
|
module Configuration
|
3
|
+
DEFAULT = {
|
4
|
+
host: '127.0.0.1',
|
5
|
+
port: 9200,
|
6
|
+
page_size: 20,
|
7
|
+
coord_similarity: true
|
8
|
+
}
|
9
|
+
|
3
10
|
extend self
|
4
11
|
|
12
|
+
def reset
|
13
|
+
@config = nil
|
14
|
+
self
|
15
|
+
end
|
16
|
+
|
5
17
|
def configure(_options = nil, &_block)
|
6
18
|
if _options.nil?
|
7
19
|
_block.call self
|
8
20
|
else
|
9
21
|
@config = config.merge _options.symbolize_keys
|
10
22
|
end
|
23
|
+
self
|
11
24
|
end
|
12
25
|
|
13
26
|
def api_client
|
@@ -30,10 +43,6 @@ module Elastic
|
|
30
43
|
@config[:coord_similarity]
|
31
44
|
end
|
32
45
|
|
33
|
-
def strict_mode
|
34
|
-
@config[:strict_types]
|
35
|
-
end
|
36
|
-
|
37
46
|
def logger
|
38
47
|
@config[:logger] || default_logger
|
39
48
|
end
|
@@ -41,13 +50,7 @@ module Elastic
|
|
41
50
|
private
|
42
51
|
|
43
52
|
def config
|
44
|
-
@config ||=
|
45
|
-
host: '127.0.0.1',
|
46
|
-
port: 9200,
|
47
|
-
page_size: 20,
|
48
|
-
coord_similarity: true,
|
49
|
-
strict_types: true
|
50
|
-
}
|
53
|
+
@config ||= DEFAULT
|
51
54
|
end
|
52
55
|
|
53
56
|
def default_logger
|
data/lib/elastic/core/adaptor.rb
CHANGED
@@ -22,8 +22,8 @@ module Elastic::Core
|
|
22
22
|
not_supported :collect_all
|
23
23
|
end
|
24
24
|
|
25
|
-
def
|
26
|
-
not_supported :
|
25
|
+
def collect_from(_collection, _options, &_block)
|
26
|
+
not_supported :collect_from
|
27
27
|
end
|
28
28
|
|
29
29
|
def find_by_ids(_ids, _options)
|
@@ -18,7 +18,7 @@ module Elastic::Core
|
|
18
18
|
target.public_send(method, &_block) if method
|
19
19
|
end
|
20
20
|
|
21
|
-
def
|
21
|
+
def collect_from(_collection, _options, &_block)
|
22
22
|
method = collect_method_for(_collection)
|
23
23
|
raise ArgumentError, "Could not find a method to iterate over collection" if method.nil?
|
24
24
|
_collection.public_send(method, &_block)
|
@@ -7,11 +7,11 @@ module Elastic::Core
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def targets
|
10
|
-
@target_cache
|
10
|
+
raise 'attempting to access targets before definition has been frozen' if @target_cache.nil?
|
11
|
+
@target_cache
|
11
12
|
end
|
12
13
|
|
13
14
|
def targets=(_values)
|
14
|
-
@target_cache = nil
|
15
15
|
@targets = _values
|
16
16
|
end
|
17
17
|
|
@@ -26,12 +26,11 @@ module Elastic::Core
|
|
26
26
|
def initialize
|
27
27
|
@targets = []
|
28
28
|
@field_map = {}
|
29
|
-
@
|
29
|
+
@field_cache = {}
|
30
30
|
@middleware_options = HashWithIndifferentAccess.new
|
31
31
|
end
|
32
32
|
|
33
33
|
def register_field(_field)
|
34
|
-
raise 'definition has been frozen' if @frozen
|
35
34
|
@field_map[_field.name] = _field
|
36
35
|
end
|
37
36
|
|
@@ -40,59 +39,60 @@ module Elastic::Core
|
|
40
39
|
end
|
41
40
|
|
42
41
|
def expanded_field_names
|
43
|
-
@
|
42
|
+
@field_map.map { |_, field| field.expanded_names }.flatten
|
43
|
+
end
|
44
|
+
|
45
|
+
def freeze
|
46
|
+
return if frozen?
|
47
|
+
cache_targets
|
48
|
+
complete_and_validate_fields
|
49
|
+
freeze_fields
|
50
|
+
@middleware_options.freeze
|
51
|
+
super
|
44
52
|
end
|
45
53
|
|
46
54
|
def get_field(_name)
|
55
|
+
ensure_frozen!
|
56
|
+
|
47
57
|
_name = _name.to_s
|
48
|
-
|
49
|
-
|
50
|
-
@field_map[_name]
|
51
|
-
else
|
52
|
-
parent = @field_map[_name[0...separator]]
|
53
|
-
parent.try(:get_field, _name[separator + 1..-1])
|
54
|
-
end
|
58
|
+
@field_cache[_name] = resolve_field(_name) unless @field_cache.key? _name
|
59
|
+
@field_cache[_name]
|
55
60
|
end
|
56
61
|
|
57
62
|
def has_field?(_name)
|
63
|
+
ensure_frozen!
|
64
|
+
|
58
65
|
!get_field(_name).nil?
|
59
66
|
end
|
60
67
|
|
61
68
|
def as_es_mapping
|
62
|
-
|
69
|
+
ensure_frozen!
|
70
|
+
|
63
71
|
properties = {}
|
64
72
|
@field_map.each_value do |field|
|
65
|
-
|
66
|
-
|
67
|
-
if !field_def.key?(:type) && field.mapping_inference_enabled?
|
68
|
-
inferred = infer_mapping_options(field.name)
|
69
|
-
field_def.merge! inferred.symbolize_keys unless inferred.nil?
|
70
|
-
end
|
71
|
-
|
72
|
-
if Elastic::Configuration.strict_mode && !field_def.key?(:type)
|
73
|
-
raise "explicit field type for #{field.name} required"
|
74
|
-
end
|
75
|
-
|
76
|
-
properties[field.name] = field_def if field_def.key? :type
|
73
|
+
properties[field.name] = field.mapping_options
|
77
74
|
end
|
78
75
|
|
79
76
|
{ 'properties' => properties.as_json }
|
80
77
|
end
|
81
78
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
79
|
+
private
|
80
|
+
|
81
|
+
def resolve_field(_name)
|
82
|
+
separator = _name.index '.'
|
83
|
+
if separator.nil?
|
84
|
+
@field_map[_name]
|
85
|
+
else
|
86
|
+
parent = @field_map[_name[0...separator]]
|
87
|
+
return nil if parent.nil?
|
88
|
+
parent.get_field(_name[separator + 1..-1])
|
87
89
|
end
|
88
90
|
end
|
89
91
|
|
90
|
-
def
|
91
|
-
|
92
|
+
def cache_targets
|
93
|
+
@target_cache = load_targets.freeze
|
92
94
|
end
|
93
95
|
|
94
|
-
private
|
95
|
-
|
96
96
|
def load_targets
|
97
97
|
mode = nil
|
98
98
|
@targets.map do |target|
|
@@ -107,6 +107,25 @@ module Elastic::Core
|
|
107
107
|
end
|
108
108
|
end
|
109
109
|
|
110
|
+
def complete_and_validate_fields
|
111
|
+
@field_map.each_value do |field|
|
112
|
+
field.merge! infer_mapping_options(field.name) if field.needs_inference?
|
113
|
+
|
114
|
+
error = field.validate
|
115
|
+
raise error unless error.nil?
|
116
|
+
end
|
117
|
+
|
118
|
+
@field_map.freeze
|
119
|
+
end
|
120
|
+
|
121
|
+
def ensure_frozen!
|
122
|
+
raise 'definition needs to be frozen' unless frozen?
|
123
|
+
end
|
124
|
+
|
125
|
+
def freeze_fields
|
126
|
+
@field_map.each_value(&:freeze)
|
127
|
+
end
|
128
|
+
|
110
129
|
def load_target_middleware(_target)
|
111
130
|
Middleware.wrap(_target)
|
112
131
|
end
|