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
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
|