elastic-rails 0.1.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a5c4d94d6d4b35572694f0968dfcb60251cd531a
|
4
|
+
data.tar.gz: 8fc9e4861325fb3e7ddf90d5751b7dd69892a0ac
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7084256b0dca89eecfdb1a0b2b2c8784e52b155da96fc60b9419913314fe7fb06c01525669a10414cb807e0ec75d6538d8d0c7f344d14eb6fdde16abe3f8442c
|
7
|
+
data.tar.gz: 7f38c177624c2df6216e821701507a91000bd95980226bdad50bf1fab18d6146f1041bd4ffc1845c6824bfd819a8d6b31cba12b789abfd05d875ef13efe7418b
|
data/Guardfile
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
watch(%r{^spec/.+_spec\.rb$})
|
2
|
+
# A sample Guardfile
|
3
|
+
# More info at https://github.com/guard/guard#readme
|
4
|
+
|
5
|
+
## Uncomment and set this to only include directories you want to watch
|
6
|
+
# directories %w(app lib config test spec feature)
|
7
|
+
|
8
|
+
## Uncomment to clear the screen before every task
|
9
|
+
# clearing :on
|
10
|
+
|
11
|
+
## Make Guard exit when config is changed so it can be restarted
|
12
|
+
#
|
13
|
+
## Note: if you want Guard to automatically start up again, run guard in a
|
14
|
+
## shell loop, e.g.:
|
15
|
+
#
|
16
|
+
# $ while bundle exec guard; do echo "Restarting Guard..."; done
|
17
|
+
#
|
18
|
+
## Note: if you are using the `directories` clause above and you are not
|
19
|
+
## watching the project directory ('.'), the you will want to move the Guardfile
|
20
|
+
## to a watched dir and symlink it back, e.g.
|
21
|
+
#
|
22
|
+
# $ mkdir config
|
23
|
+
# $ mv Guardfile config/
|
24
|
+
# $ ln -s config/Guardfile .
|
25
|
+
#
|
26
|
+
# and, you'll have to watch "config/Guardfile" instead of "Guardfile"
|
27
|
+
#
|
28
|
+
watch ("Guardfile") do
|
29
|
+
UI.info "Exiting because Guard must be restarted for changes to take effect"
|
30
|
+
exit 0
|
31
|
+
end
|
32
|
+
|
33
|
+
# Note: The cmd option is now required due to the increasing number of ways
|
34
|
+
# rspec may be run, below are examples of the most common uses.
|
35
|
+
# * bundler: 'bundle exec rspec'
|
36
|
+
# * bundler binstubs: 'bin/rspec'
|
37
|
+
# * spring: 'bin/rspec' (This will use spring if running and you have
|
38
|
+
# installed the spring binstubs per the docs)
|
39
|
+
# * zeus: 'zeus rspec' (requires the server to be started separately)
|
40
|
+
# * 'just' rspec: 'rspec'
|
41
|
+
|
42
|
+
guard :rspec, cmd: 'bundle exec rspec' do
|
43
|
+
watch(%r{^spec/.+_spec\.rb$})
|
44
|
+
watch(%r{^lib/elastic/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
|
45
|
+
watch('spec/spec_helper.rb') { "spec" }
|
46
|
+
end
|
data/elastic.gemspec
CHANGED
@@ -19,9 +19,18 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
20
20
|
spec.require_paths = ["lib"]
|
21
21
|
|
22
|
-
spec.add_dependency "elasticsearch", "~> 1.0"
|
22
|
+
spec.add_dependency "elasticsearch", "~> 1.0", ">= 1.0.18"
|
23
|
+
spec.add_dependency "activesupport"
|
23
24
|
|
24
|
-
spec.add_development_dependency "bundler", "~> 1.
|
25
|
-
spec.add_development_dependency "rake", "~> 10.
|
26
|
-
spec.add_development_dependency "rspec", "~> 3.
|
25
|
+
spec.add_development_dependency "bundler", "~> 1.6"
|
26
|
+
spec.add_development_dependency "rake", "~> 10.4"
|
27
|
+
spec.add_development_dependency "rspec", "~> 3.1"
|
28
|
+
spec.add_development_dependency "rspec-nc", "~> 0.2"
|
29
|
+
spec.add_development_dependency "guard", "~> 2.11"
|
30
|
+
spec.add_development_dependency "guard-rspec", "~> 4.5"
|
31
|
+
spec.add_development_dependency "terminal-notifier-guard", "~> 1.6", ">= 1.6.1"
|
32
|
+
spec.add_development_dependency "pry", "~> 0.10"
|
33
|
+
spec.add_development_dependency "pry-remote", "~> 0.1"
|
34
|
+
spec.add_development_dependency "pry-byebug", "~> 3.2"
|
35
|
+
spec.add_development_dependency "pry-nav", "~> 0.2"
|
27
36
|
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module Elastic::Commands
|
2
|
+
class BuildAggFromParams < Elastic::Support::Command.new(:index, :params)
|
3
|
+
def perform
|
4
|
+
parse_params
|
5
|
+
raise ArgumentError, "field not mapped: #{@field}" unless index.definition.has_field? @field
|
6
|
+
|
7
|
+
path = parse_nesting_path
|
8
|
+
raise NotImplementedError, "nested paths not yet supported in aggregations" if path
|
9
|
+
|
10
|
+
build_node
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def agg_name
|
16
|
+
@options.fetch(:as, @field)
|
17
|
+
end
|
18
|
+
|
19
|
+
def parse_params
|
20
|
+
@field = params[0].to_s
|
21
|
+
@options = params[1] || {}
|
22
|
+
end
|
23
|
+
|
24
|
+
def parse_nesting_path
|
25
|
+
dot_index = @field.rindex('.')
|
26
|
+
return nil if dot_index.nil?
|
27
|
+
@field.slice(0, dot_index)
|
28
|
+
end
|
29
|
+
|
30
|
+
def build_node
|
31
|
+
type = @options[:type]
|
32
|
+
type = infer_type_from_options_and_mapping if type.nil?
|
33
|
+
|
34
|
+
send("build_#{type}")
|
35
|
+
end
|
36
|
+
|
37
|
+
def infer_type_from_options_and_mapping
|
38
|
+
return :range if @options.key? :ranges
|
39
|
+
|
40
|
+
properties = index.mapping.get_field_options @field
|
41
|
+
return :date_histogram if properties['type'] == 'date'
|
42
|
+
return :histogram if @options.key? :interval
|
43
|
+
|
44
|
+
:terms
|
45
|
+
end
|
46
|
+
|
47
|
+
def build_range
|
48
|
+
raise NotImplementedError, 'range aggregation not yet implemented'
|
49
|
+
end
|
50
|
+
|
51
|
+
def build_histogram
|
52
|
+
raise NotImplementedError, 'histogram aggregation not yet implemented'
|
53
|
+
end
|
54
|
+
|
55
|
+
def build_date_histogram
|
56
|
+
Elastic::Nodes::Agg::DateHistogram.build(agg_name, @field, interval: @options[:interval])
|
57
|
+
end
|
58
|
+
|
59
|
+
def build_terms
|
60
|
+
Elastic::Nodes::Agg::Terms.build(agg_name, @field, size: @options[:size])
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
module Elastic::Commands
|
2
|
+
class BuildQueryFromParams < Elastic::Support::Command.new(
|
3
|
+
:index, :params, block: nil, prefix: nil
|
4
|
+
)
|
5
|
+
|
6
|
+
def perform
|
7
|
+
if block
|
8
|
+
# TODO: builder mode, support nesting through first parameter
|
9
|
+
else
|
10
|
+
node = Elastic::Nodes::Boolean.build_or(params.map do |part|
|
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)
|
18
|
+
end
|
19
|
+
|
20
|
+
node.simplify
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def get_nesting_path(_field)
|
26
|
+
dot_index = _field.rindex('.')
|
27
|
+
return nil if dot_index.nil?
|
28
|
+
_field.slice 0, dot_index
|
29
|
+
end
|
30
|
+
|
31
|
+
def build_query_node(_field, _options)
|
32
|
+
_field = with_prefix _field
|
33
|
+
_options = prepare_options _field, _options
|
34
|
+
|
35
|
+
type = infer_type_from_params(_options)
|
36
|
+
send("build_#{type}", _field, _options)
|
37
|
+
end
|
38
|
+
|
39
|
+
def infer_type_from_params(_query)
|
40
|
+
return :term if _query.key? :term
|
41
|
+
return :term if _query.key? :terms
|
42
|
+
return :match if _query.key? :matches
|
43
|
+
return :range if _query.key? :gte
|
44
|
+
return :range if _query.key? :gt
|
45
|
+
return :range if _query.key? :lte
|
46
|
+
return :range if _query.key? :lt
|
47
|
+
return :nested if _query.key? :nested
|
48
|
+
nil
|
49
|
+
end
|
50
|
+
|
51
|
+
def with_prefix(_path)
|
52
|
+
return _path if prefix.nil?
|
53
|
+
"#{prefix}.#{_path}"
|
54
|
+
end
|
55
|
+
|
56
|
+
def prepare_options(_field, _options)
|
57
|
+
properties = index.mapping.get_field_options _field.to_s
|
58
|
+
raise ArgumentError, "field not mapped: #{_field}" if properties.nil?
|
59
|
+
|
60
|
+
case properties['type']
|
61
|
+
when 'nested'
|
62
|
+
prepare_nested_options _options, properties
|
63
|
+
when 'string'
|
64
|
+
prepare_string_options _options, properties
|
65
|
+
else
|
66
|
+
prepare_default_options _options, properties
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def prepare_nested_options(_options, _properties)
|
71
|
+
return _options if _options.is_a?(Hash) && _options[:nested]
|
72
|
+
{ nested: _options }
|
73
|
+
end
|
74
|
+
|
75
|
+
def prepare_string_options(_options, _properties)
|
76
|
+
return _options if _options.is_a? Hash
|
77
|
+
_properties['index'] == 'not_analyzed' ? { term: _options } : { matches: _options }
|
78
|
+
end
|
79
|
+
|
80
|
+
def prepare_default_options(_options, _properties)
|
81
|
+
return _options if _options.is_a? Hash
|
82
|
+
return range_to_options(_options) if _options.is_a? Range
|
83
|
+
{ term: _options }
|
84
|
+
end
|
85
|
+
|
86
|
+
def build_nested(_field, _options)
|
87
|
+
query = _options[:nested]
|
88
|
+
query = [query] unless query.is_a? Array
|
89
|
+
|
90
|
+
nested_query = BuildQueryFromParams.for(index: index, params: query, prefix: _field)
|
91
|
+
Elastic::Nodes::Nested.build _field, nested_query
|
92
|
+
end
|
93
|
+
|
94
|
+
def build_term(_field, _options)
|
95
|
+
terms = Array(_options[:term] || _options[:terms])
|
96
|
+
|
97
|
+
Elastic::Nodes::Term.new.tap do |node|
|
98
|
+
node.field = _field
|
99
|
+
node.mode = _options[:mode]
|
100
|
+
node.terms = terms.map { |t| prep(_field, t) }
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def build_range(_field, _options)
|
105
|
+
Elastic::Nodes::Range.new.tap do |node|
|
106
|
+
node.field = _field
|
107
|
+
node.gte = prep(_field, _options[:gte]) if _options.key? :gte
|
108
|
+
node.gt = prep(_field, _options[:gt]) if _options.key? :gt
|
109
|
+
node.lte = prep(_field, _options[:lte]) if _options.key? :lte
|
110
|
+
node.lt = prep(_field, _options[:lt]) if _options.key? :lt
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def build_match(_field, _options)
|
115
|
+
Elastic::Nodes::Match.new.tap do |node|
|
116
|
+
node.field = _field
|
117
|
+
node.query = prep(_field, _options[:matches])
|
118
|
+
end
|
119
|
+
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
|
+
end
|
132
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module Elastic::Commands
|
2
|
+
class ImportIndexDocuments < Elastic::Support::Command.new(
|
3
|
+
:index, collection: nil, cache_size: 10000, verbose: false
|
4
|
+
)
|
5
|
+
def perform
|
6
|
+
if collection.present?
|
7
|
+
import_collection
|
8
|
+
else
|
9
|
+
targets.each { |target| import_target(target) }
|
10
|
+
end
|
11
|
+
flush
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def import_collection
|
17
|
+
main_target.collect_for(collection, middleware_options) { |obj| queue obj }
|
18
|
+
end
|
19
|
+
|
20
|
+
def import_target(_target)
|
21
|
+
_target.collect_all(middleware_options) { |obj| queue obj }
|
22
|
+
end
|
23
|
+
|
24
|
+
def cache
|
25
|
+
@cache ||= []
|
26
|
+
end
|
27
|
+
|
28
|
+
def queue(_object)
|
29
|
+
cache << render_for_es(_object)
|
30
|
+
flush if cache.length >= cache_size
|
31
|
+
end
|
32
|
+
|
33
|
+
def flush
|
34
|
+
unless cache.empty?
|
35
|
+
index.adaptor.bulk_index(cache)
|
36
|
+
log_flush(cache.size) if verbose
|
37
|
+
cache.clear
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def log_flush(_size)
|
42
|
+
@total ||= 0
|
43
|
+
@total += _size
|
44
|
+
Elastic::Configuration.logger.info "Imported #{@total} documents"
|
45
|
+
end
|
46
|
+
|
47
|
+
def render_for_es(_object)
|
48
|
+
index.new(_object).as_es_document
|
49
|
+
end
|
50
|
+
|
51
|
+
def main_target
|
52
|
+
index.definition.main_target
|
53
|
+
end
|
54
|
+
|
55
|
+
def targets
|
56
|
+
index.definition.targets
|
57
|
+
end
|
58
|
+
|
59
|
+
def middleware_options
|
60
|
+
index.definition.middleware_options
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module Elastic
|
2
|
+
module Configuration
|
3
|
+
extend self
|
4
|
+
|
5
|
+
def configure(_options = nil, &_block)
|
6
|
+
if _options.nil?
|
7
|
+
_block.call self
|
8
|
+
else
|
9
|
+
@config = config.merge _options.symbolize_keys
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def api_client
|
14
|
+
config[:client] ||= load_api_client
|
15
|
+
end
|
16
|
+
|
17
|
+
def index_name
|
18
|
+
config[:index]
|
19
|
+
end
|
20
|
+
|
21
|
+
def indices_path
|
22
|
+
'app/indices'
|
23
|
+
end
|
24
|
+
|
25
|
+
def page_size
|
26
|
+
@config[:page_size]
|
27
|
+
end
|
28
|
+
|
29
|
+
def coord_similarity
|
30
|
+
@config[:coord_similarity]
|
31
|
+
end
|
32
|
+
|
33
|
+
def strict_mode
|
34
|
+
@config[:strict_types]
|
35
|
+
end
|
36
|
+
|
37
|
+
def logger
|
38
|
+
@config[:logger] || default_logger
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
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
|
+
}
|
51
|
+
end
|
52
|
+
|
53
|
+
def default_logger
|
54
|
+
@default_logger ||= Logger.new(STDOUT)
|
55
|
+
end
|
56
|
+
|
57
|
+
def load_api_client
|
58
|
+
Elasticsearch::Client.new host: config[:host], port: config[:port]
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
module Elastic::Core
|
2
|
+
class Adaptor
|
3
|
+
def initialize(_suffix)
|
4
|
+
@suffix = _suffix
|
5
|
+
end
|
6
|
+
|
7
|
+
def index_name
|
8
|
+
@index_name ||= "#{Elastic::Configuration.index_name}_#{@suffix}"
|
9
|
+
end
|
10
|
+
|
11
|
+
def remap(_type, _mapping)
|
12
|
+
# TODO
|
13
|
+
end
|
14
|
+
|
15
|
+
def exists?
|
16
|
+
api_client.indices.exists? build_options
|
17
|
+
end
|
18
|
+
|
19
|
+
def ensure_index
|
20
|
+
create unless exists?
|
21
|
+
self
|
22
|
+
end
|
23
|
+
|
24
|
+
def create
|
25
|
+
api_client.indices.create build_options
|
26
|
+
api_client.cluster.health wait_for_status: 'yellow'
|
27
|
+
self
|
28
|
+
end
|
29
|
+
|
30
|
+
def drop
|
31
|
+
api_client.indices.delete build_options
|
32
|
+
self
|
33
|
+
end
|
34
|
+
|
35
|
+
def exists_type?(_type)
|
36
|
+
api_client.indices.exists_type build_options(type: _type)
|
37
|
+
end
|
38
|
+
|
39
|
+
def exists_mapping?(_type)
|
40
|
+
!api_client.indices.get_mapping(build_options(type: _type)).empty?
|
41
|
+
end
|
42
|
+
|
43
|
+
def get_mappings(type: nil)
|
44
|
+
mappings = api_client.indices.get_mapping build_options(type: type)
|
45
|
+
mappings[index_name]['mappings']
|
46
|
+
end
|
47
|
+
|
48
|
+
def set_mapping(_type, _mapping)
|
49
|
+
api_client.indices.put_mapping build_options(
|
50
|
+
type: _type,
|
51
|
+
update_all_types: true,
|
52
|
+
body: _mapping
|
53
|
+
)
|
54
|
+
self
|
55
|
+
end
|
56
|
+
|
57
|
+
def index(_document)
|
58
|
+
api_client.index build_options(
|
59
|
+
id: _document['_id'],
|
60
|
+
type: _document['_type'],
|
61
|
+
body: _document['data']
|
62
|
+
)
|
63
|
+
self
|
64
|
+
end
|
65
|
+
|
66
|
+
def bulk_index(_documents)
|
67
|
+
body = _documents.map do |doc|
|
68
|
+
{ 'index' => doc.merge('_index' => index_name) }
|
69
|
+
end
|
70
|
+
|
71
|
+
api_client.bulk body: body
|
72
|
+
self
|
73
|
+
end
|
74
|
+
|
75
|
+
def refresh
|
76
|
+
api_client.indices.refresh build_options
|
77
|
+
self
|
78
|
+
end
|
79
|
+
|
80
|
+
def find(_id, type: '_all')
|
81
|
+
api_client.get build_options(type: type, id: _id)
|
82
|
+
end
|
83
|
+
|
84
|
+
def count(type: nil, query: nil)
|
85
|
+
api_client.count(build_options(type: type, body: query))['count']
|
86
|
+
end
|
87
|
+
|
88
|
+
def query(type: nil, query: nil)
|
89
|
+
api_client.search build_options(type: type, body: query)
|
90
|
+
end
|
91
|
+
|
92
|
+
private
|
93
|
+
|
94
|
+
def api_client
|
95
|
+
Elastic::Configuration.api_client
|
96
|
+
end
|
97
|
+
|
98
|
+
def build_options(_options = {})
|
99
|
+
{ index: index_name }.merge! _options
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Elastic::Core
|
2
|
+
class BaseMiddleware
|
3
|
+
attr_reader :target
|
4
|
+
|
5
|
+
def initialize(_target)
|
6
|
+
@target = _target
|
7
|
+
end
|
8
|
+
|
9
|
+
def type_name
|
10
|
+
@target.to_s
|
11
|
+
end
|
12
|
+
|
13
|
+
def mode
|
14
|
+
not_supported :mode
|
15
|
+
end
|
16
|
+
|
17
|
+
def field_options_for(_field, _options)
|
18
|
+
not_supported :field_options_for
|
19
|
+
end
|
20
|
+
|
21
|
+
def collect_all(_options, &_block)
|
22
|
+
not_supported :collect_all
|
23
|
+
end
|
24
|
+
|
25
|
+
def collect_for(_collection, _options, &_block)
|
26
|
+
not_supported :collect_for
|
27
|
+
end
|
28
|
+
|
29
|
+
def find_by_ids(_ids, _options)
|
30
|
+
not_supported :find_by_ids
|
31
|
+
end
|
32
|
+
|
33
|
+
def build_from_data(_data, _options)
|
34
|
+
not_supported :build_from_data
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def not_supported(_feature)
|
40
|
+
raise NotImplementedError, "#{self.class} does not support '#{_feature}'"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module Elastic::Core
|
2
|
+
class DefaultMiddleware < BaseMiddleware
|
3
|
+
def mode
|
4
|
+
case target_mode
|
5
|
+
when :find_multiple_ids, :find_single_id
|
6
|
+
:index
|
7
|
+
else
|
8
|
+
:storage
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def field_options_for(_field, _options)
|
13
|
+
nil
|
14
|
+
end
|
15
|
+
|
16
|
+
def collect_all(_options, &_block)
|
17
|
+
method = collect_method_for(target)
|
18
|
+
target.public_send(method, &_block) if method
|
19
|
+
end
|
20
|
+
|
21
|
+
def collect_for(_collection, _options, &_block)
|
22
|
+
method = collect_method_for(_collection)
|
23
|
+
raise ArgumentError, "Could not find a method to iterate over collection" if method.nil?
|
24
|
+
_collection.public_send(method, &_block)
|
25
|
+
end
|
26
|
+
|
27
|
+
def find_by_ids(_ids, _options)
|
28
|
+
case target_mode
|
29
|
+
when :find_multiple_ids
|
30
|
+
target.find_by_elastic_ids(_ids)
|
31
|
+
when :find_single_id
|
32
|
+
_ids.map { |id| target.find_by_elastic_id(id) }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def build_from_data(_data, _options)
|
37
|
+
case target_mode
|
38
|
+
when :custom_build
|
39
|
+
target.build_from_elastic_data(_data)
|
40
|
+
when :open_struct
|
41
|
+
OpenStruct.new _data
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def target_mode
|
48
|
+
@target_mode ||= detect_output_mode
|
49
|
+
end
|
50
|
+
|
51
|
+
def collect_method_for(_target)
|
52
|
+
return :find_each_for_elastic if _target.respond_to?(:find_each_for_elastic)
|
53
|
+
return :each if _target.respond_to?(:each)
|
54
|
+
nil
|
55
|
+
end
|
56
|
+
|
57
|
+
def detect_output_mode
|
58
|
+
return :find_multiple_ids if target.respond_to? :find_by_elastic_ids
|
59
|
+
return :find_single_id if target.respond_to? :find_by_elastic_id
|
60
|
+
return :custom_build if target.respond_to? :build_from_elastic_data
|
61
|
+
:open_struct
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|