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.
Files changed (90) hide show
  1. checksums.yaml +4 -4
  2. data/Guardfile +46 -0
  3. data/elastic.gemspec +13 -4
  4. data/lib/elastic/commands/build_agg_from_params.rb +63 -0
  5. data/lib/elastic/commands/build_query_from_params.rb +132 -0
  6. data/lib/elastic/commands/import_index_documents.rb +63 -0
  7. data/lib/elastic/configuration.rb +61 -0
  8. data/lib/elastic/core/adaptor.rb +102 -0
  9. data/lib/elastic/core/base_middleware.rb +43 -0
  10. data/lib/elastic/core/default_middleware.rb +64 -0
  11. data/lib/elastic/core/definition.rb +118 -0
  12. data/lib/elastic/core/mapping_manager.rb +120 -0
  13. data/lib/elastic/core/middleware.rb +26 -0
  14. data/lib/elastic/core/query_assembler.rb +84 -0
  15. data/lib/elastic/core/query_config.rb +25 -0
  16. data/lib/elastic/core/serializer.rb +45 -0
  17. data/lib/elastic/core/source_formatter.rb +40 -0
  18. data/lib/elastic/dsl/bool_query_builder.rb +52 -0
  19. data/lib/elastic/dsl/bool_query_context.rb +42 -0
  20. data/lib/elastic/dsl/metric_builder.rb +34 -0
  21. data/lib/elastic/fields/nested.rb +42 -0
  22. data/lib/elastic/fields/value.rb +60 -0
  23. data/lib/elastic/nested_type.rb +5 -0
  24. data/lib/elastic/nodes/agg/average.rb +7 -0
  25. data/lib/elastic/nodes/agg/base_metric.rb +42 -0
  26. data/lib/elastic/nodes/agg/date_histogram.rb +48 -0
  27. data/lib/elastic/nodes/agg/maximum.rb +7 -0
  28. data/lib/elastic/nodes/agg/minimum.rb +7 -0
  29. data/lib/elastic/nodes/agg/stats.rb +7 -0
  30. data/lib/elastic/nodes/agg/sum.rb +7 -0
  31. data/lib/elastic/nodes/agg/terms.rb +38 -0
  32. data/lib/elastic/nodes/agg/top_hits.rb +17 -0
  33. data/lib/elastic/nodes/and.rb +45 -0
  34. data/lib/elastic/nodes/base.rb +34 -0
  35. data/lib/elastic/nodes/base_agg.rb +32 -0
  36. data/lib/elastic/nodes/boolean.rb +87 -0
  37. data/lib/elastic/nodes/concerns/aggregable.rb +52 -0
  38. data/lib/elastic/nodes/concerns/boostable.rb +25 -0
  39. data/lib/elastic/nodes/concerns/bucketed.rb +17 -0
  40. data/lib/elastic/nodes/concerns/hit_provider.rb +39 -0
  41. data/lib/elastic/nodes/function_score.rb +116 -0
  42. data/lib/elastic/nodes/match.rb +45 -0
  43. data/lib/elastic/nodes/nested.rb +42 -0
  44. data/lib/elastic/nodes/or.rb +9 -0
  45. data/lib/elastic/nodes/range.rb +36 -0
  46. data/lib/elastic/nodes/search.rb +48 -0
  47. data/lib/elastic/nodes/term.rb +58 -0
  48. data/lib/elastic/query.rb +84 -22
  49. data/lib/elastic/railtie.rb +41 -0
  50. data/lib/elastic/railties/ar_helpers.rb +51 -0
  51. data/lib/elastic/railties/ar_middleware.rb +45 -0
  52. data/lib/elastic/{indexable_record.rb → railties/indexable_record.rb} +21 -18
  53. data/lib/elastic/railties/query_extensions.rb +9 -0
  54. data/lib/elastic/railties/rspec.rb +6 -0
  55. data/lib/elastic/railties/tasks/es.rake +19 -0
  56. data/lib/elastic/railties/type_extensions.rb +14 -0
  57. data/lib/elastic/railties/utils.rb +62 -0
  58. data/lib/elastic/results/aggregations.rb +29 -0
  59. data/lib/elastic/results/base.rb +13 -0
  60. data/lib/elastic/results/bucket.rb +15 -0
  61. data/lib/elastic/results/bucket_collection.rb +17 -0
  62. data/lib/elastic/results/grouped_result.rb +37 -0
  63. data/lib/elastic/results/hit.rb +25 -0
  64. data/lib/elastic/results/hit_collection.rb +38 -0
  65. data/lib/elastic/results/metric.rb +13 -0
  66. data/lib/elastic/results/result_group.rb +19 -0
  67. data/lib/elastic/results/root.rb +15 -0
  68. data/lib/elastic/shims/base.rb +23 -0
  69. data/lib/elastic/shims/grouping.rb +23 -0
  70. data/lib/elastic/shims/populating.rb +69 -0
  71. data/lib/elastic/shims/reducing.rb +20 -0
  72. data/lib/elastic/support/command.rb +34 -0
  73. data/lib/elastic/support/transform.rb +37 -0
  74. data/lib/elastic/support/traversable.rb +22 -0
  75. data/lib/elastic/type.rb +56 -84
  76. data/lib/elastic/types/base_type.rb +38 -0
  77. data/lib/elastic/types/faceted_type.rb +16 -0
  78. data/lib/elastic/types/nestable_type.rb +14 -0
  79. data/lib/elastic/version.rb +1 -1
  80. data/lib/elastic.rb +72 -30
  81. data/lib/generators/elastic/index_generator.rb +10 -0
  82. data/lib/generators/elastic/templates/index.rb +17 -0
  83. metadata +222 -16
  84. data/lib/elastic/capabilities/aggregation_builder.rb +0 -64
  85. data/lib/elastic/capabilities/bool_query_builder.rb +0 -74
  86. data/lib/elastic/capabilities/context_handler.rb +0 -31
  87. data/lib/elastic/histogram.rb +0 -49
  88. data/lib/elastic/index.rb +0 -113
  89. data/lib/elastic/indexable.rb +0 -25
  90. data/lib/elastic/value_transform.rb +0 -15
@@ -0,0 +1,17 @@
1
+ module Elastic::Results
2
+ class BucketCollection < Base
3
+ extend Forwardable
4
+ include Enumerable
5
+
6
+ def_delegators :@buckets, :last, :first, :count, :[], :each
7
+
8
+ def initialize(_buckets)
9
+ @buckets = _buckets
10
+ end
11
+
12
+ def traverse(&_block)
13
+ super
14
+ @buckets.each { |b| b.traverse(&_block) }
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,37 @@
1
+ module Elastic::Results
2
+ class GroupedResult < Base
3
+ include Enumerable
4
+
5
+ def initialize(_groups)
6
+ @groups = _groups.to_a
7
+ end
8
+
9
+ def each(&_block)
10
+ @groups.map { |g| group_as_pair g }.each(&_block)
11
+ end
12
+
13
+ def last
14
+ return nil if @groups.count == 0
15
+ group_as_pair @groups.last
16
+ end
17
+
18
+ def count
19
+ @groups.count
20
+ end
21
+
22
+ def group_at(_idx)
23
+ @groups[_idx]
24
+ end
25
+
26
+ def traverse(&_block)
27
+ super
28
+ @groups.each { |h| h.traverse(&_block) }
29
+ end
30
+
31
+ private
32
+
33
+ def group_as_pair(_group)
34
+ [_group.keys, _group.as_value]
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,25 @@
1
+ module Elastic::Results
2
+ class Hit < Base
3
+ attr_accessor :raw, :ref
4
+
5
+ def initialize(_raw)
6
+ @raw = _raw
7
+ end
8
+
9
+ def id
10
+ @raw['_id']
11
+ end
12
+
13
+ def type
14
+ @raw['_type']
15
+ end
16
+
17
+ def score
18
+ @raw['_score']
19
+ end
20
+
21
+ def source
22
+ @raw['_source']
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,38 @@
1
+ module Elastic::Results
2
+ class HitCollection < Base
3
+ include Enumerable
4
+
5
+ def initialize(_hits)
6
+ @hits = _hits
7
+ end
8
+
9
+ def count
10
+ @hits.count
11
+ end
12
+
13
+ def [](_idx)
14
+ @hits[_idx].try(:ref)
15
+ end
16
+
17
+ def last
18
+ @hits.last.try(:ref)
19
+ end
20
+
21
+ def each(&_block)
22
+ @hits.map(&:ref).each(&_block)
23
+ end
24
+
25
+ def each_hit(&_block)
26
+ @hits.each(&_block)
27
+ end
28
+
29
+ def each_with_score(&_block)
30
+ @hits.map { |h| [h.ref, h.score] }.each(&_block)
31
+ end
32
+
33
+ def traverse(&_block)
34
+ super
35
+ @hits.each { |h| h.traverse(&_block) }
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,13 @@
1
+ module Elastic::Results
2
+ class Metric < Base
3
+ attr_reader :value
4
+
5
+ def initialize(_value)
6
+ @value = _value
7
+ end
8
+
9
+ def as_value
10
+ @value
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,19 @@
1
+ module Elastic::Results
2
+ class ResultGroup < Base
3
+ attr_reader :keys, :data
4
+
5
+ def initialize(_keys, _data)
6
+ @keys = _keys.freeze
7
+ @data = _data
8
+ end
9
+
10
+ def as_value
11
+ @data.as_value
12
+ end
13
+
14
+ def traverse(&_block)
15
+ super
16
+ @data.traverse(&_block)
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,15 @@
1
+ module Elastic::Results
2
+ class Root < HitCollection
3
+ attr_reader :aggregations
4
+
5
+ def initialize(_hits, _aggs)
6
+ super _hits
7
+ @aggregations = Aggregations.new _aggs
8
+ end
9
+
10
+ def traverse(&_block)
11
+ super
12
+ aggregations.traverse(&_block)
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,23 @@
1
+ module Elastic::Shims
2
+ class Base
3
+ include Elastic::Support::Traversable
4
+
5
+ attr_reader :child
6
+
7
+ def initialize(_child)
8
+ @child = _child
9
+ end
10
+
11
+ def traverse(&_block)
12
+ @child.traverse(&_block)
13
+ end
14
+
15
+ def render
16
+ @child.render
17
+ end
18
+
19
+ def handle_result(_raw)
20
+ @child.handle_result(_raw)
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,23 @@
1
+ module Elastic::Shims
2
+ class Grouping < Base
3
+ def handle_result(_raw)
4
+ groups = []
5
+ group_recursive(super.aggregations, HashWithIndifferentAccess.new, groups)
6
+ Elastic::Results::GroupedResult.new groups
7
+ end
8
+
9
+ private
10
+
11
+ def group_recursive(_agg_context, _keys, _groups)
12
+ name, agg = _agg_context.first
13
+
14
+ if agg.is_a? Elastic::Results::BucketCollection
15
+ agg.each do |bucket|
16
+ group_recursive(bucket, _keys.merge(name => bucket.key), _groups)
17
+ end
18
+ else
19
+ _groups << Elastic::Results::ResultGroup.new(_keys, _agg_context)
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,69 @@
1
+ module Elastic::Shims
2
+ class Populating < Base
3
+ def initialize(_index, _config, _child)
4
+ super _child
5
+ @index = _index
6
+ @config = _config
7
+ end
8
+
9
+ def render
10
+ disable_hits_source if populate_by_id?
11
+ super
12
+ end
13
+
14
+ def handle_result(_raw)
15
+ result = super
16
+ populate result
17
+ result
18
+ end
19
+
20
+ private
21
+
22
+ def disable_hits_source
23
+ child.pick(Elastic::Nodes::Concerns::HitProvider) do |node|
24
+ node.source = false
25
+ end
26
+ end
27
+
28
+ def populate(_result)
29
+ groups = _result.pick(Elastic::Results::Hit).group_by(&:type)
30
+ groups.each { |t, h| populate_group(t, h) }
31
+ end
32
+
33
+ def populate_group(_type_name, _hits)
34
+ target = resolve_target(_type_name)
35
+ raise "Unexpected type name #{_type_name}" if target.nil?
36
+
37
+ if populate_by_id?
38
+ ids = _hits.map(&:id)
39
+ objects = target.find_by_ids(ids, middleware_options)
40
+ objects.each_with_index { |o, i| _hits[i].ref = o }
41
+ else
42
+ _hits.each do |hit|
43
+ hit.ref = target.build_from_data(
44
+ formatter.format(hit.source),
45
+ middleware_options
46
+ )
47
+ end
48
+ end
49
+ end
50
+
51
+ def populate_by_id?
52
+ @index.definition.mode == :index
53
+ end
54
+
55
+ def resolve_target(_type_name)
56
+ @index.definition.targets.find { |t| t.type_name == _type_name }
57
+ end
58
+
59
+ def middleware_options
60
+ @middleware_options ||= begin
61
+ @index.definition.middleware_options.merge(@config.middleware_options).freeze
62
+ end
63
+ end
64
+
65
+ def formatter
66
+ @formatter ||= Elastic::Core::SourceFormatter.new(@index.mapping)
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,20 @@
1
+ module Elastic::Shims
2
+ class Reducing < Base
3
+ def handle_result(_raw)
4
+ result = super
5
+
6
+ case result
7
+ when Elastic::Results::Root
8
+ result.aggregations.first.last.as_value
9
+ when Elastic::Results::GroupedResult
10
+ groups = result.map do |keys, bucket|
11
+ Elastic::Results::ResultGroup.new keys, bucket.first.last
12
+ end
13
+
14
+ Elastic::Results::GroupedResult.new groups
15
+ else
16
+ result
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,34 @@
1
+ module Elastic::Support
2
+ module Command
3
+ def self.new(*_attributes)
4
+ attr_names = []
5
+ attr_defaults = {}
6
+
7
+ _attributes.each do |att|
8
+ if att.is_a? Hash
9
+ attr_defaults.merge! att
10
+ attr_names += att.keys
11
+ else
12
+ attr_names << att
13
+ end
14
+ end
15
+
16
+ Struct.new(*attr_names) do
17
+ def self.for(kwargs = {})
18
+ new(kwargs).perform
19
+ end
20
+
21
+ def perform
22
+ end
23
+
24
+ define_method(:initialize) do |kwargs = {}|
25
+ kwargs = attr_defaults.merge kwargs
26
+ attr_values = attr_names.map { |a| kwargs[a] }
27
+ super(*attr_values)
28
+ end
29
+
30
+ define_method(:perform) {}
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,37 @@
1
+ module Elastic::Support
2
+ class Transform
3
+ def initialize(_transform)
4
+ @transform = _transform
5
+ end
6
+
7
+ def apply(_value)
8
+ case @transform
9
+ when Symbol
10
+ _value.public_send @transform
11
+ when String
12
+ _value.instance_eval(@transform)
13
+ when Proc
14
+ _value.instance_exec(&@transform)
15
+ when nil
16
+ _value
17
+ else
18
+ raise ArgumentError, "invalid transformation type #{@transform.class}"
19
+ end
20
+ end
21
+
22
+ def apply_to_many(_values)
23
+ case @transform
24
+ when Symbol
25
+ _values.map(&@transform)
26
+ when String
27
+ _values.map { |v| v.instance_eval(@transform) }
28
+ when Proc
29
+ _values.map { |v| v.instance_exec(&@transform) }
30
+ when nil
31
+ _values
32
+ else
33
+ raise ArgumentError, "invalid transformation type #{@transform.class}"
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,22 @@
1
+ module Elastic::Support
2
+ module Traversable
3
+ def traverse(&_block)
4
+ raise NotImplementedError, "every traversable tree must implement 'traverse'"
5
+ end
6
+
7
+ def pick(*_types, &_block)
8
+ if _types.empty?
9
+ enum = Enumerator.new do |y|
10
+ traverse { |h| y << h }
11
+ end
12
+ else
13
+ enum = Enumerator.new do |y|
14
+ traverse { |h| y << h if _types.any? { |t| h.is_a? t } }
15
+ end
16
+ end
17
+
18
+ return enum if _block.nil?
19
+ enum.each(&_block)
20
+ end
21
+ end
22
+ end
data/lib/elastic/type.rb CHANGED
@@ -1,121 +1,93 @@
1
1
  module Elastic
2
- class Type
3
- MAPPING_OPTIONS = [ :type, :analyzer, :boost, :coerce, :copy_to, :doc_values, :dynamic,
4
- :enabled, :fielddata, :geohash, :geohash_precision, :geohash_prefix, :format, :ignore_above,
5
- :ignore_malformed, :include_in_all, :index_options, :lat_lon, :index, :fields, :norms,
6
- :null_value, :position_increment_gap, :properties, :search_analyzer, :similarity, :store,
7
- :term_vector ]
2
+ class Type < Types::BaseType
3
+ extend Types::FacetedType
4
+ extend Types::NestableType
8
5
 
9
- def self.connection
10
- @connection ||= Elastic.connect index
11
- end
12
-
13
- def self.index=(_value)
14
- @index = _value
15
- end
6
+ class << self
7
+ extend Forwardable
16
8
 
17
- def self.index
18
- @index
9
+ def_delegators :query, :must, :should, :segment, :stats, :maximum, :minimum, :sum, :average,
10
+ :coord_similarity, :limit, :offset, :pluck, :ids, :total
19
11
  end
20
12
 
21
- def self.type_name=(_value)
22
- @type_name = _value
13
+ def self.suffix
14
+ @suffix || default_suffix
23
15
  end
24
16
 
25
- def self.type_name
26
- @type_name ||= to_s.underscore
17
+ def self.suffix=(_value)
18
+ @suffix = _value
27
19
  end
28
20
 
29
- def self.fields(*_fields)
30
- raise ArgumentError, 'must provide at least a field name' if _fields.length == 0
31
-
32
- options = {}
33
- options = _fields.pop if _fields.last.is_a? Hash
34
-
35
- _fields.each do |name|
36
- register_field(name, options)
37
- register_mapping(name, options)
38
- register_transform(name, options[:transform]) if options.key? :transform
39
- end
21
+ def self.adaptor
22
+ @adaptor ||= Elastic::Core::Adaptor.new(suffix)
40
23
  end
41
24
 
42
- def self.field(_field, _options)
43
- fields(_field, _options)
25
+ def self.mapping
26
+ @mapping ||= load_mapping
44
27
  end
45
28
 
46
- def self.store(_data, _options = {})
47
- connection.index(type_name, new(_data).render, mapping: { type_name => type_mapping })
29
+ def self.reindex(verbose: true)
30
+ drop
31
+ mapping.migrate
32
+ Commands::ImportIndexDocuments.for index: self, verbose: verbose
33
+ ensure_full_mapping
34
+ self
48
35
  end
49
36
 
50
- def self.store_bulk(_collection, _options = {})
51
- # TODO
37
+ def self.import(_collection)
38
+ enforce_mapping!
39
+ Commands::ImportIndexDocuments.for index: self, collection: _collection
40
+ ensure_full_mapping
41
+ self
52
42
  end
53
43
 
54
- def self.query(_query)
55
- connection.query type_name, _query
44
+ def self.index(_object)
45
+ new(_object).save
56
46
  end
57
47
 
58
- def self.clear(_options = {})
59
- connection.clear type_name
48
+ def self.query
49
+ enforce_mapping!
50
+ ensure_full_mapping
51
+ Query.new self
60
52
  end
61
53
 
62
- def self.prepare_field_for_query(_field, _value)
63
- transform = transforms[_field.to_sym]
64
- transform.nil? ? _value : transform.apply(_value)
54
+ def self.drop
55
+ adaptor.drop if adaptor.exists?
56
+ self
65
57
  end
66
58
 
67
- attr_reader :object
68
-
69
- def initialize(_object)
70
- @object = _object
59
+ def self.refresh
60
+ adaptor.refresh
61
+ self
71
62
  end
72
63
 
73
- def render
74
- document = {}
75
- document[:id] = fetch_object_property(:id) if object_has_property?(:id)
76
-
77
- self.class.type_fields.each do |name, options|
78
- document[name] = fetch_object_property(name)
64
+ def self.enforce_mapping!
65
+ if mapping.out_of_sync?
66
+ raise 'elastic mapping out of sync, run `rake es:migrate`'
79
67
  end
80
-
81
- document
82
- end
83
-
84
- private
85
-
86
- def self.type_fields
87
- @type_fields ||= []
88
- end
89
-
90
- def self.type_mapping
91
- @type_mapping ||= { "properties" => { } }
92
- end
93
-
94
- def self.transforms
95
- @transforms ||= { }
96
- end
97
-
98
- def self.register_field(_name, _options)
99
- type_fields << [_name.to_sym, _options]
100
68
  end
101
69
 
102
- def self.register_mapping(_name, _options)
103
- field = _options.slice(*MAPPING_OPTIONS)
104
- field.merge! type: 'string', index: 'not_analyzed' if _options[:type].try(:to_sym) == :term
105
- type_mapping["properties"][_name.to_s] = field if field.length > 0
70
+ def self.ensure_full_mapping
71
+ if mapping.incomplete?
72
+ mapping.fetch
73
+ end
106
74
  end
107
75
 
108
- def self.register_transform(_name, _transform)
109
- transforms[_name.to_sym] = ValueTransform.new self, _transform
76
+ def save
77
+ self.class.tap do |klass|
78
+ klass.enforce_mapping!
79
+ klass.adaptor.index as_es_document
80
+ klass.ensure_full_mapping
81
+ end
110
82
  end
111
83
 
112
- def object_has_property?(_name)
113
- self.respond_to?(_name) || object.respond_to?(_name)
84
+ private_class_method def self.load_mapping
85
+ freeze_index_definition
86
+ Elastic::Core::MappingManager.new(adaptor, definition).tap(&:fetch)
114
87
  end
115
88
 
116
- def fetch_object_property(_name)
117
- value = self.respond_to?(_name) ? public_send(_name) : object.public_send(_name)
118
- self.class.prepare_field_for_query _name, value
89
+ private_class_method def self.default_suffix
90
+ to_s.underscore
119
91
  end
120
92
  end
121
93
  end
@@ -0,0 +1,38 @@
1
+ module Elastic::Types
2
+ class BaseType < Elastic::Core::Serializer
3
+ def self.target=(_name_or_class)
4
+ definition.targets = [_name_or_class]
5
+ end
6
+
7
+ def self.targets=(_names_or_classes)
8
+ definition.targets = _names_or_classes
9
+ end
10
+
11
+ def self.definition
12
+ @definition ||= Elastic::Core::Definition.new.tap do |definition|
13
+ definition.targets = [default_target] unless default_target.nil?
14
+ end
15
+ end
16
+
17
+ def self.freeze_index_definition
18
+ unless definition.frozen?
19
+ definition.fields.each do |field|
20
+ field.disable_mapping_inference if original_value_occluded? field.name
21
+ end
22
+
23
+ definition.freeze
24
+ end
25
+ end
26
+
27
+ def initialize(_object)
28
+ super(self.class.definition, _object)
29
+ end
30
+
31
+ private_class_method def self.default_target
32
+ @default_target ||= begin
33
+ target = to_s.match(/^(.*)Index$/)
34
+ target ? target[1] : nil
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,16 @@
1
+ module Elastic::Types
2
+ module FacetedType
3
+ def fields(*_fields)
4
+ raise ArgumentError, 'must provide at least a field name' if _fields.empty?
5
+
6
+ options = {}
7
+ options = _fields.pop if _fields.last.is_a? Hash
8
+
9
+ _fields.each { |name| field(name, options) }
10
+ end
11
+
12
+ def field(_name, _options = {})
13
+ definition.register_field Elastic::Fields::Value.new(_name, _options)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,14 @@
1
+ module Elastic::Types
2
+ module NestableType
3
+ def nested(_name, using: nil, target: nil, &_block)
4
+ unless _block.nil?
5
+ using = Class.new(Elastic::NestedType, &_block)
6
+ using.target = (target || _name.to_s.singularize.camelize.constantize) rescue nil
7
+ end
8
+
9
+ using = (_name + '_index').camelize.constantize if using.nil?
10
+
11
+ definition.register_field Elastic::Fields::Nested.new(_name, using)
12
+ end
13
+ end
14
+ end
@@ -1,3 +1,3 @@
1
1
  module Elastic
2
- VERSION = "0.1.0"
2
+ VERSION = "0.5.0"
3
3
  end