elasticated 2.5.5 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (99) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +35 -2
  3. data/Rakefile +52 -1
  4. data/elasticated.gemspec +3 -1
  5. data/lib/elasticated.rb +20 -24
  6. data/lib/elasticated/aggregation.rb +3 -6
  7. data/lib/elasticated/aggregations/date_histogram_aggregation.rb +6 -1
  8. data/lib/elasticated/aggregations/filter_aggregation.rb +8 -12
  9. data/lib/elasticated/aggregations/filter_aggregation_evaluator.rb +1 -1
  10. data/lib/elasticated/aggregations/group_aggregation.rb +14 -11
  11. data/lib/elasticated/aggregations/range_aggregation.rb +10 -11
  12. data/lib/elasticated/aggregations/range_aggregation_evaluator.rb +1 -1
  13. data/lib/elasticated/aggregations/ranges_builder.rb +2 -2
  14. data/lib/elasticated/aggregations/safe_date_histogram_aggregation.rb +7 -2
  15. data/lib/elasticated/aggregations/subaggregated.rb +1 -1
  16. data/lib/elasticated/boolean_clause.rb +4 -3
  17. data/lib/elasticated/bulk_actions/create_action.rb +14 -0
  18. data/lib/elasticated/bulk_actions/delete_action.rb +30 -0
  19. data/lib/elasticated/bulk_actions/index_action.rb +35 -0
  20. data/lib/elasticated/bulk_actions/standard_action.rb +22 -0
  21. data/lib/elasticated/bulk_actions/update_action.rb +44 -0
  22. data/lib/elasticated/bulk_actions/upsert_action.rb +14 -0
  23. data/lib/elasticated/bulk_request.rb +58 -0
  24. data/lib/elasticated/bulk_request/response.rb +32 -0
  25. data/lib/elasticated/bulk_request/response_item.rb +39 -0
  26. data/lib/elasticated/client.rb +27 -3
  27. data/lib/elasticated/conditions/custom_condition.rb +3 -3
  28. data/lib/elasticated/conditions/range_condition.rb +5 -2
  29. data/lib/elasticated/conditions/script_condition.rb +3 -3
  30. data/lib/elasticated/conditions/standard_condition.rb +4 -5
  31. data/lib/elasticated/conditions/term_condition.rb +22 -0
  32. data/lib/elasticated/conditions/terms_condition.rb +2 -2
  33. data/lib/elasticated/conditions_builder.rb +19 -4
  34. data/lib/elasticated/delimiters/date_field_delimiter.rb +21 -12
  35. data/lib/elasticated/delimiters/standard_field_delimiter.rb +18 -2
  36. data/lib/elasticated/delimiters/term_field_delimiter.rb +6 -5
  37. data/lib/elasticated/document.rb +20 -1
  38. data/lib/elasticated/enum.rb +17 -0
  39. data/lib/elasticated/index_selector.rb +26 -25
  40. data/lib/elasticated/mapping.rb +2 -4
  41. data/lib/elasticated/mapping/builder.rb +3 -2
  42. data/lib/elasticated/mapping/fields_builder.rb +13 -9
  43. data/lib/elasticated/mapping/object_builder.rb +38 -4
  44. data/lib/elasticated/mapping/type_builder.rb +3 -5
  45. data/lib/elasticated/mixins/block_evaluation.rb +17 -0
  46. data/lib/elasticated/mixins/clonable.rb +60 -0
  47. data/lib/elasticated/mixins/configurable.rb +22 -0
  48. data/lib/elasticated/mixins/inspectionable.rb +16 -0
  49. data/lib/elasticated/partitioned_repository.rb +24 -18
  50. data/lib/elasticated/query.rb +27 -21
  51. data/lib/elasticated/query_aggregations.rb +5 -7
  52. data/lib/elasticated/query_conditions.rb +6 -3
  53. data/lib/elasticated/quick.rb +7 -0
  54. data/lib/elasticated/repository.rb +184 -40
  55. data/lib/elasticated/repository/intelligent_search.rb +3 -3
  56. data/lib/elasticated/repository/normal_search.rb +2 -2
  57. data/lib/elasticated/repository/resumable_search.rb +5 -5
  58. data/lib/elasticated/repository/scan_scroll_search.rb +4 -4
  59. data/lib/elasticated/repository/scroll_search.rb +3 -3
  60. data/lib/elasticated/repository/search.rb +7 -0
  61. data/lib/elasticated/repository/single_page_search.rb +1 -1
  62. data/lib/elasticated/results.rb +14 -0
  63. data/lib/version.rb +18 -25
  64. data/spec/aggregation_spec.rb +95 -16
  65. data/spec/bulk_request_spec.rb +158 -0
  66. data/spec/date_field_delimiter_spec.rb +50 -6
  67. data/spec/document_spec.rb +1 -5
  68. data/spec/integration_spec.rb +7 -7
  69. data/spec/mapping_spec.rb +128 -8
  70. data/spec/partitioned_repository_spec.rb +218 -0
  71. data/spec/query_conditions_spec.rb +98 -45
  72. data/spec/query_spec.rb +21 -28
  73. data/spec/repository_spec.rb +245 -0
  74. data/spec/results_spec.rb +0 -4
  75. data/spec/sample_responses/elasticsearch_bulk_response_1.json +35 -0
  76. data/spec/sample_responses/elasticsearch_bulk_response_2.json +20 -0
  77. data/spec/sample_responses/elasticsearch_count_1.json +8 -0
  78. data/spec/sample_responses/elasticsearch_count_2.json +8 -0
  79. data/spec/sample_responses/elasticsearch_get_response_1.json +10 -0
  80. data/spec/sample_responses/elasticsearch_get_response_2.json +6 -0
  81. data/spec/{elasticsearch_hit_1.json → sample_responses/elasticsearch_hit_1.json} +0 -0
  82. data/spec/sample_responses/elasticsearch_mget_response_1.json +25 -0
  83. data/spec/{elasticsearch_response_1.json → sample_responses/elasticsearch_response_1.json} +0 -0
  84. data/spec/{elasticsearch_response_2.json → sample_responses/elasticsearch_response_2.json} +0 -0
  85. data/spec/{elasticsearch_top_hits_response.json → sample_responses/elasticsearch_top_hits_response.json} +0 -0
  86. data/spec/spec_helper.rb +47 -0
  87. data/spec/spec_helper/fake_index_selector.rb +27 -0
  88. data/spec/term_field_delimiter_spec.rb +8 -8
  89. metadata +80 -26
  90. data/lib/elasticated/block_evaluation.rb +0 -15
  91. data/lib/elasticated/clonable.rb +0 -58
  92. data/lib/elasticated/configurable.rb +0 -20
  93. data/lib/elasticated/date_delimiter_factory.rb +0 -123
  94. data/lib/elasticated/delimiter_visitor.rb +0 -53
  95. data/lib/elasticated/inspectionable.rb +0 -9
  96. data/lib/elasticated/strategy_params_for_query_service.rb +0 -14
  97. data/lib/elasticated/term_delimiter_factory.rb +0 -73
  98. data/spec/delimiter_factory_spec.rb +0 -399
  99. data/spec/strategy_params_for_query_service_spec.rb +0 -387
@@ -20,7 +20,7 @@ module Elasticated
20
20
  end
21
21
 
22
22
  def parse_subaggregations(response)
23
- if compact and _subaggregations.one?
23
+ if compact and _subaggregations.count == 1
24
24
  single_subaggregation = _subaggregations.first
25
25
  single_subaggregation.parse(response[single_subaggregation.name.to_s])
26
26
  else
@@ -1,7 +1,8 @@
1
1
  module Elasticated
2
2
  class BooleanClause
3
3
 
4
- include Clonable
4
+ include Mixins::Clonable
5
+ include Mixins::Inspectionable
5
6
 
6
7
  attr_accessor :conditions
7
8
 
@@ -11,8 +12,8 @@ module Elasticated
11
12
 
12
13
  # delimiters
13
14
 
14
- def accept_visitor(visitor)
15
- visitor.visit_boolean_clause(self)
15
+ def fill_delimiter(field_delimiter)
16
+ conditions.each{ |condition| condition.fill_delimiter field_delimiter }
16
17
  end
17
18
 
18
19
  # conditions
@@ -0,0 +1,14 @@
1
+ module Elasticated
2
+ module BulkActions
3
+ class CreateAction < IndexAction
4
+
5
+ protected
6
+
7
+ # override
8
+ def command_name
9
+ :create
10
+ end
11
+
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,30 @@
1
+ module Elasticated
2
+ module BulkActions
3
+ class DeleteAction < StandardAction
4
+
5
+ attr_accessor :document_id, :params
6
+
7
+ def initialize(repository, document_id, params={})
8
+ super repository
9
+ self.document_id = document_id
10
+ self.params = params
11
+ end
12
+
13
+ def build
14
+ original_params = Helpers.hash_deep_dup params
15
+ # preparations
16
+ prepared_params = repository.params_for_ids [document_id], original_params
17
+ # verifications
18
+ prepared_params[:index] || raise("A target index should be specified in a delete")
19
+ prepared_params[:type] || raise("A target type should be specified in a delete")
20
+ # the final command
21
+ prepared_params[:_index] = prepared_params.delete :index
22
+ prepared_params[:_type] = prepared_params.delete :type
23
+ prepared_params[:_id] = document_id
24
+ command = { delete: prepared_params }
25
+ [command]
26
+ end
27
+
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,35 @@
1
+ module Elasticated
2
+ module BulkActions
3
+ class IndexAction < StandardAction
4
+
5
+ attr_accessor :document, :params
6
+
7
+ def initialize(repository, document, params={})
8
+ super repository
9
+ self.document = document
10
+ self.params = params
11
+ end
12
+
13
+ def build
14
+ original_params = Helpers.hash_deep_dup params
15
+ # preparations
16
+ prepared_document = repository.prepare_document document
17
+ prepared_params = repository.params_for_document document, original_params
18
+ # the final command
19
+ prepared_params[:_index] = prepared_params.delete(:index) || prepared_document.index || raise("An index name is required for a document indexation")
20
+ prepared_params[:_type] = prepared_params.delete(:type) || prepared_document.type || raise("A type name is required for a document indexation")
21
+ prepared_params[:_id] = prepared_params.delete(:id) || prepared_document.id
22
+ command = { command_name => prepared_params }
23
+ prepared_source = prepared_document.source
24
+ [command, prepared_source]
25
+ end
26
+
27
+ protected
28
+
29
+ def command_name
30
+ :index
31
+ end
32
+
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,22 @@
1
+ module Elasticated
2
+ module BulkActions
3
+ class StandardAction
4
+
5
+ # abstract class
6
+ # child must implement 'build()' => Hash
7
+
8
+ attr_accessor :repository
9
+
10
+ def initialize(repository)
11
+ self.repository = repository
12
+ end
13
+
14
+ # def build
15
+ # command = build_command
16
+ # body = build_body
17
+ # [command, body]
18
+ # end
19
+
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,44 @@
1
+ module Elasticated
2
+ module BulkActions
3
+ class UpdateAction < StandardAction
4
+
5
+ attr_accessor :document_id, :params
6
+
7
+ def initialize(repository, document_id, params={})
8
+ super repository
9
+ self.document_id = document_id
10
+ self.params = params
11
+ end
12
+
13
+ def build
14
+ original_params = Helpers.hash_deep_dup params
15
+ # verifications
16
+ source = original_params.delete(:source) || raise("No body specified for partial update")
17
+ # preparations
18
+ prepared_source = repository.prepare_source Helpers.hash_deep_dup source
19
+ prepared_params = repository.params_for_source source, original_params
20
+ # more verifications
21
+ prepared_params[:index] || raise("A target index should be specified in a partial update")
22
+ prepared_params[:type] || raise("A target type should be specified in a partial update")
23
+ # the final command
24
+ prepared_params[:_index] = prepared_params.delete :index
25
+ prepared_params[:_type] = prepared_params.delete :type
26
+ prepared_params[:_id] = document_id
27
+ command = { command_name => prepared_params }
28
+ body = build_body_from prepared_source
29
+ [command, body]
30
+ end
31
+
32
+ protected
33
+
34
+ def command_name
35
+ :update
36
+ end
37
+
38
+ def build_body_from(prepared_source)
39
+ { doc: prepared_source }
40
+ end
41
+
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,14 @@
1
+ module Elasticated
2
+ module BulkActions
3
+ class UpsertAction < UpdateAction
4
+
5
+ protected
6
+
7
+ # override
8
+ def build_body_from(prepared_source)
9
+ { doc: prepared_source, doc_as_upsert: true }
10
+ end
11
+
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,58 @@
1
+ module Elasticated
2
+ class BulkRequest
3
+
4
+ def self.build_over(repository, &block)
5
+ request = new repository
6
+ request.evaluate block
7
+ request
8
+ end
9
+
10
+ include Mixins::Inspectionable
11
+ include Mixins::BlockEvaluation
12
+
13
+ attr_accessor :repository, :actions
14
+ attr_accessor :errors, :items
15
+
16
+ def initialize(repository)
17
+ self.repository = repository
18
+ self.actions = Array.new
19
+ end
20
+
21
+ def add(action)
22
+ actions << action
23
+ end
24
+
25
+ def build
26
+ actions.map(&:build).flatten
27
+ end
28
+
29
+ def to_text
30
+ build.map(&:to_json)*"\n"
31
+ end
32
+
33
+ def get_action_class(action_name)
34
+ return nil unless action_name.to_s.end_with? '_document'
35
+ camel_case_name = Helpers.string_to_camel_case action_name.to_s.gsub /\_document$/, ''
36
+ self.class.const_get("::Elasticated::BulkActions::#{camel_case_name}Action") rescue nil
37
+ end
38
+
39
+ def method_missing(method_name, *args, &block)
40
+ action_class = get_action_class method_name
41
+ if action_class
42
+ action = action_class.new(repository, *args, &block)
43
+ add action
44
+ else
45
+ super
46
+ end
47
+ end
48
+
49
+ def respond_to_missing?(name, include_private=false)
50
+ get_action_class(name) || super
51
+ end
52
+
53
+ def parse(result)
54
+ Response.parse result
55
+ end
56
+
57
+ end
58
+ end
@@ -0,0 +1,32 @@
1
+ module Elasticated
2
+ class BulkRequest
3
+ class Response
4
+
5
+ include Mixins::Inspectionable
6
+
7
+ def self.parse(elasticsearch_response)
8
+ response = new
9
+ response.took = elasticsearch_response['took']
10
+ response.errors = elasticsearch_response['errors']
11
+ response.items = elasticsearch_response['items'].map do |elasticsearch_item|
12
+ ResponseItem.parse elasticsearch_item
13
+ end
14
+ response
15
+ end
16
+
17
+ attr_accessor :took, :errors, :items
18
+
19
+ def errors?
20
+ !!errors
21
+ end
22
+ alias_method :error?, :errors?
23
+
24
+ def text_for_inspect
25
+ text = (items.count == 1) ? "#{items.count} item" : "#{items.count} items"
26
+ text = errors? ? "#{text}, with errors" : "#{text}, no errors"
27
+ text
28
+ end
29
+
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,39 @@
1
+ module Elasticated
2
+ class BulkRequest
3
+ class ResponseItem
4
+
5
+ include Mixins::Inspectionable
6
+
7
+ def self.parse(partial_response)
8
+ item = new
9
+ item.action = partial_response.first.first
10
+ data = partial_response.first.last
11
+ item.index = data['_index']
12
+ item.type = data['_type']
13
+ item.id = data['_id']
14
+ item.version = data['_version']
15
+ item.status = data['status']
16
+ item.found = data['found']
17
+ item.error = data['error']
18
+ item
19
+ end
20
+
21
+ attr_accessor :action, :index, :type, :id, :version, :status, :found, :error
22
+
23
+ def error?
24
+ !!error
25
+ end
26
+
27
+ def completed?
28
+ !error?
29
+ end
30
+
31
+ def text_for_inspect
32
+ text = "#{action} #{index}/#{type}/#{id} (status #{status})"
33
+ text = "#{text}, with error" if error?
34
+ text
35
+ end
36
+
37
+ end
38
+ end
39
+ end
@@ -1,6 +1,6 @@
1
1
  module Elasticated
2
2
  class Client
3
- include Configurable
3
+ include Mixins::Configurable
4
4
 
5
5
  attr_accessor :transport
6
6
 
@@ -41,7 +41,7 @@ module Elasticated
41
41
  mapping = opts[:mapping]
42
42
  body = Hash.new
43
43
  body.merge!(settings: { number_of_shards: shards }) if shards
44
- body.merge!(mappings: mapping) if mapping
44
+ body.merge!(mappings: mapping.to_h) if mapping # both Hash and Mapping::Builder responds to 'to_h'
45
45
  args.merge! body: body unless body.empty?
46
46
  log.info "Creating index '#{index_name}'"
47
47
  transport.indices.create args
@@ -65,6 +65,10 @@ module Elasticated
65
65
  log.info "Alias '#{index_alias}' removed from index '#{index_name}'"
66
66
  end
67
67
 
68
+ def update_mapping(index_name, type_name, mapping, opts={})
69
+ transport.indices.put_mapping opts.merge(index: index_name, type: type_name, body: mapping)
70
+ end
71
+
68
72
  def refresh_index(index_name)
69
73
  transport.indices.refresh index: index_name
70
74
  log.debug "Index '#{index_name}' refreshed"
@@ -95,11 +99,31 @@ module Elasticated
95
99
  transport.scroll opts.merge scroll_id: scroll_id
96
100
  end
97
101
 
98
- def delete(body, opts={})
102
+ def delete_by_query(body, opts={})
99
103
  log_query :delete, body.to_json, opts
100
104
  transport.delete_by_query opts.merge body: body
101
105
  end
102
106
 
107
+ def get_document(document_id, opts={})
108
+ log_query :get, document_id, opts
109
+ transport.get opts.merge id: document_id
110
+ end
111
+
112
+ def get_documents(documents_ids, opts={})
113
+ log_query :mget, documents_ids, opts
114
+ transport.mget opts.merge body: { ids: documents_ids }
115
+ end
116
+
117
+ def delete_document(document_id, opts={})
118
+ log_query :delete, document_id, opts
119
+ transport.delete opts.merge id: document_id
120
+ end
121
+
122
+ def bulk(bulk_body, opts={})
123
+ log_query :bulk, bulk_body, opts
124
+ transport.bulk opts.merge body: bulk_body
125
+ end
126
+
103
127
  protected
104
128
 
105
129
  def log_query(query_type, message_body, query_opts={})
@@ -2,7 +2,7 @@ module Elasticated
2
2
  module Conditions
3
3
  class CustomCondition
4
4
 
5
- include Inspectionable
5
+ include Mixins::Inspectionable
6
6
 
7
7
  attr_accessor :body
8
8
 
@@ -14,8 +14,8 @@ module Elasticated
14
14
  body
15
15
  end
16
16
 
17
- def accept_visitor(visitor)
18
- visitor.visit_condition(self)
17
+ def fill_delimiter(field_delimiter)
18
+ # nothing to do
19
19
  end
20
20
 
21
21
  end
@@ -15,8 +15,11 @@ module Elasticated
15
15
  { range: { field => body }.merge(opts) }
16
16
  end
17
17
 
18
- def accept_visitor(visitor)
19
- visitor.visit_range(self)
18
+ def fill_delimiter(field_delimiter)
19
+ minimum_value = body[:gt] || body[:gte]
20
+ field_delimiter.set_minimum field, minimum_value
21
+ maximum_value = body[:lt] || body[:lte]
22
+ field_delimiter.set_maximum field, maximum_value
20
23
  end
21
24
 
22
25
  end
@@ -2,7 +2,7 @@ module Elasticated
2
2
  module Conditions
3
3
  class ScriptCondition
4
4
 
5
- include Inspectionable
5
+ include Mixins::Inspectionable
6
6
 
7
7
  attr_accessor :script, :params
8
8
 
@@ -17,8 +17,8 @@ module Elasticated
17
17
  { script: body }
18
18
  end
19
19
 
20
- def accept_visitor(visitor)
21
- visitor.visit_condition(self)
20
+ def fill_delimiter(field_delimiter)
21
+ # nothing to do
22
22
  end
23
23
 
24
24
  end