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