elasticated 2.5.5 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +35 -2
- data/Rakefile +52 -1
- data/elasticated.gemspec +3 -1
- data/lib/elasticated.rb +20 -24
- data/lib/elasticated/aggregation.rb +3 -6
- data/lib/elasticated/aggregations/date_histogram_aggregation.rb +6 -1
- data/lib/elasticated/aggregations/filter_aggregation.rb +8 -12
- data/lib/elasticated/aggregations/filter_aggregation_evaluator.rb +1 -1
- data/lib/elasticated/aggregations/group_aggregation.rb +14 -11
- data/lib/elasticated/aggregations/range_aggregation.rb +10 -11
- data/lib/elasticated/aggregations/range_aggregation_evaluator.rb +1 -1
- data/lib/elasticated/aggregations/ranges_builder.rb +2 -2
- data/lib/elasticated/aggregations/safe_date_histogram_aggregation.rb +7 -2
- data/lib/elasticated/aggregations/subaggregated.rb +1 -1
- data/lib/elasticated/boolean_clause.rb +4 -3
- data/lib/elasticated/bulk_actions/create_action.rb +14 -0
- data/lib/elasticated/bulk_actions/delete_action.rb +30 -0
- data/lib/elasticated/bulk_actions/index_action.rb +35 -0
- data/lib/elasticated/bulk_actions/standard_action.rb +22 -0
- data/lib/elasticated/bulk_actions/update_action.rb +44 -0
- data/lib/elasticated/bulk_actions/upsert_action.rb +14 -0
- data/lib/elasticated/bulk_request.rb +58 -0
- data/lib/elasticated/bulk_request/response.rb +32 -0
- data/lib/elasticated/bulk_request/response_item.rb +39 -0
- data/lib/elasticated/client.rb +27 -3
- data/lib/elasticated/conditions/custom_condition.rb +3 -3
- data/lib/elasticated/conditions/range_condition.rb +5 -2
- data/lib/elasticated/conditions/script_condition.rb +3 -3
- data/lib/elasticated/conditions/standard_condition.rb +4 -5
- data/lib/elasticated/conditions/term_condition.rb +22 -0
- data/lib/elasticated/conditions/terms_condition.rb +2 -2
- data/lib/elasticated/conditions_builder.rb +19 -4
- data/lib/elasticated/delimiters/date_field_delimiter.rb +21 -12
- data/lib/elasticated/delimiters/standard_field_delimiter.rb +18 -2
- data/lib/elasticated/delimiters/term_field_delimiter.rb +6 -5
- data/lib/elasticated/document.rb +20 -1
- data/lib/elasticated/enum.rb +17 -0
- data/lib/elasticated/index_selector.rb +26 -25
- data/lib/elasticated/mapping.rb +2 -4
- data/lib/elasticated/mapping/builder.rb +3 -2
- data/lib/elasticated/mapping/fields_builder.rb +13 -9
- data/lib/elasticated/mapping/object_builder.rb +38 -4
- data/lib/elasticated/mapping/type_builder.rb +3 -5
- data/lib/elasticated/mixins/block_evaluation.rb +17 -0
- data/lib/elasticated/mixins/clonable.rb +60 -0
- data/lib/elasticated/mixins/configurable.rb +22 -0
- data/lib/elasticated/mixins/inspectionable.rb +16 -0
- data/lib/elasticated/partitioned_repository.rb +24 -18
- data/lib/elasticated/query.rb +27 -21
- data/lib/elasticated/query_aggregations.rb +5 -7
- data/lib/elasticated/query_conditions.rb +6 -3
- data/lib/elasticated/quick.rb +7 -0
- data/lib/elasticated/repository.rb +184 -40
- data/lib/elasticated/repository/intelligent_search.rb +3 -3
- data/lib/elasticated/repository/normal_search.rb +2 -2
- data/lib/elasticated/repository/resumable_search.rb +5 -5
- data/lib/elasticated/repository/scan_scroll_search.rb +4 -4
- data/lib/elasticated/repository/scroll_search.rb +3 -3
- data/lib/elasticated/repository/search.rb +7 -0
- data/lib/elasticated/repository/single_page_search.rb +1 -1
- data/lib/elasticated/results.rb +14 -0
- data/lib/version.rb +18 -25
- data/spec/aggregation_spec.rb +95 -16
- data/spec/bulk_request_spec.rb +158 -0
- data/spec/date_field_delimiter_spec.rb +50 -6
- data/spec/document_spec.rb +1 -5
- data/spec/integration_spec.rb +7 -7
- data/spec/mapping_spec.rb +128 -8
- data/spec/partitioned_repository_spec.rb +218 -0
- data/spec/query_conditions_spec.rb +98 -45
- data/spec/query_spec.rb +21 -28
- data/spec/repository_spec.rb +245 -0
- data/spec/results_spec.rb +0 -4
- data/spec/sample_responses/elasticsearch_bulk_response_1.json +35 -0
- data/spec/sample_responses/elasticsearch_bulk_response_2.json +20 -0
- data/spec/sample_responses/elasticsearch_count_1.json +8 -0
- data/spec/sample_responses/elasticsearch_count_2.json +8 -0
- data/spec/sample_responses/elasticsearch_get_response_1.json +10 -0
- data/spec/sample_responses/elasticsearch_get_response_2.json +6 -0
- data/spec/{elasticsearch_hit_1.json → sample_responses/elasticsearch_hit_1.json} +0 -0
- data/spec/sample_responses/elasticsearch_mget_response_1.json +25 -0
- data/spec/{elasticsearch_response_1.json → sample_responses/elasticsearch_response_1.json} +0 -0
- data/spec/{elasticsearch_response_2.json → sample_responses/elasticsearch_response_2.json} +0 -0
- data/spec/{elasticsearch_top_hits_response.json → sample_responses/elasticsearch_top_hits_response.json} +0 -0
- data/spec/spec_helper.rb +47 -0
- data/spec/spec_helper/fake_index_selector.rb +27 -0
- data/spec/term_field_delimiter_spec.rb +8 -8
- metadata +80 -26
- data/lib/elasticated/block_evaluation.rb +0 -15
- data/lib/elasticated/clonable.rb +0 -58
- data/lib/elasticated/configurable.rb +0 -20
- data/lib/elasticated/date_delimiter_factory.rb +0 -123
- data/lib/elasticated/delimiter_visitor.rb +0 -53
- data/lib/elasticated/inspectionable.rb +0 -9
- data/lib/elasticated/strategy_params_for_query_service.rb +0 -14
- data/lib/elasticated/term_delimiter_factory.rb +0 -73
- data/spec/delimiter_factory_spec.rb +0 -399
- data/spec/strategy_params_for_query_service_spec.rb +0 -387
@@ -1,7 +1,7 @@
|
|
1
1
|
module Elasticated
|
2
2
|
class Repository
|
3
3
|
class IntelligentSearch < Search
|
4
|
-
include Configurable
|
4
|
+
include Mixins::Configurable
|
5
5
|
|
6
6
|
# INTELLIGENT SEARCH CASES
|
7
7
|
# ------------ without sorting
|
@@ -15,14 +15,14 @@ module Elasticated
|
|
15
15
|
# without size, with offset => normal_pagination
|
16
16
|
# with size, with offset => single_page or normal_pagination
|
17
17
|
|
18
|
-
# if the query is aggregated and the search strategy is
|
18
|
+
# if the query is aggregated and the search strategy is a
|
19
19
|
# scroll-like alternative, we must do a 2-step search process
|
20
20
|
|
21
21
|
def best_search_method
|
22
22
|
if query.limited? && !query.heavy_for?(repository)
|
23
23
|
SinglePageSearch.new repository, query, aggregated, opts
|
24
24
|
else
|
25
|
-
if query.
|
25
|
+
if query.offset?
|
26
26
|
NormalSearch.new repository, query, aggregated, opts
|
27
27
|
else
|
28
28
|
if query.sorted?
|
@@ -10,7 +10,7 @@ module Elasticated
|
|
10
10
|
|
11
11
|
override! body, size, offset
|
12
12
|
response = client.search body, opts
|
13
|
-
results =
|
13
|
+
results = parse_and_prepare_results response, query
|
14
14
|
|
15
15
|
target_size = query.limited? ? query._size : (results.hits.total - offset)
|
16
16
|
total_pages = (target_size / size.to_f).ceil
|
@@ -25,7 +25,7 @@ module Elasticated
|
|
25
25
|
override! body, size, offset
|
26
26
|
|
27
27
|
response = client.search body, opts
|
28
|
-
new_results =
|
28
|
+
new_results = parse_and_prepare_results response
|
29
29
|
results.append new_results
|
30
30
|
break if new_results.count < size
|
31
31
|
|
@@ -2,8 +2,8 @@ module Elasticated
|
|
2
2
|
class Repository
|
3
3
|
class ResumableSearch < Search
|
4
4
|
|
5
|
-
def self.from_scroll_id(
|
6
|
-
search = new
|
5
|
+
def self.from_scroll_id(repository, scroll_id)
|
6
|
+
search = new repository, nil
|
7
7
|
search.scroll_id = scroll_id
|
8
8
|
search
|
9
9
|
end
|
@@ -15,12 +15,12 @@ module Elasticated
|
|
15
15
|
aggregation_results = if aggregated
|
16
16
|
body = query.build_for_aggregations
|
17
17
|
response = client.search body, opts
|
18
|
-
|
18
|
+
parse_and_prepare_results response, query
|
19
19
|
end
|
20
20
|
# search
|
21
21
|
body = query.build_for_search
|
22
22
|
response = client.search body, opts.merge(scroll: scroll_expiration_time, size: scroll_page_size)
|
23
|
-
results =
|
23
|
+
results = parse_and_prepare_results response
|
24
24
|
results.append aggregation_results if aggregation_results
|
25
25
|
self.scroll_id = results.scroll_id
|
26
26
|
mark_completed! if results.documents.count < scroll_page_size
|
@@ -31,7 +31,7 @@ module Elasticated
|
|
31
31
|
raise "No scroll_id present" unless scroll_id
|
32
32
|
raise "No more information to fetch: scroll completed" if completed?
|
33
33
|
response = client.scroll scroll_id, scroll: scroll_expiration_time
|
34
|
-
results =
|
34
|
+
results = parse_and_prepare_results response
|
35
35
|
self.scroll_id = results.scroll_id
|
36
36
|
mark_completed! if results.documents.empty?
|
37
37
|
results
|
@@ -5,7 +5,7 @@ module Elasticated
|
|
5
5
|
def fetch_aggregations
|
6
6
|
body = query.build_for_aggregations
|
7
7
|
response = client.search body, opts
|
8
|
-
|
8
|
+
parse_and_prepare_results response, query
|
9
9
|
end
|
10
10
|
|
11
11
|
def execute
|
@@ -14,17 +14,17 @@ module Elasticated
|
|
14
14
|
if aggregated
|
15
15
|
body = query.build_for_aggregations
|
16
16
|
response = client.search body, opts
|
17
|
-
results =
|
17
|
+
results = parse_and_prepare_results response, query
|
18
18
|
end
|
19
19
|
# search
|
20
20
|
body = query.build_for_search
|
21
21
|
response = client.search body, opts.merge(search_type: 'scan', scroll: scroll_expiration_time, size: scroll_page_size)
|
22
|
-
results =
|
22
|
+
results = parse_and_prepare_results response
|
23
23
|
results.append fetch_aggregations if aggregated
|
24
24
|
doc_count = 0
|
25
25
|
loop do
|
26
26
|
response = client.scroll results.scroll_id, scroll: scroll_expiration_time
|
27
|
-
new_results =
|
27
|
+
new_results = parse_and_prepare_results response
|
28
28
|
hits = new_results.documents
|
29
29
|
break if hits.empty?
|
30
30
|
if query.limited? && (doc_count + hits.count > query._size)
|
@@ -5,7 +5,7 @@ module Elasticated
|
|
5
5
|
def fetch_aggregations
|
6
6
|
body = query.build_for_aggregations
|
7
7
|
response = client.search body, opts
|
8
|
-
|
8
|
+
parse_and_prepare_results response, query
|
9
9
|
end
|
10
10
|
|
11
11
|
def execute
|
@@ -14,7 +14,7 @@ module Elasticated
|
|
14
14
|
|
15
15
|
override! body
|
16
16
|
response = client.search body, opts.merge(scroll: scroll_expiration_time, size: scroll_page_size)
|
17
|
-
results =
|
17
|
+
results = parse_and_prepare_results response, query
|
18
18
|
results.append fetch_aggregations if aggregated
|
19
19
|
|
20
20
|
target_size = query.limited? ? query._size : results.hits.total
|
@@ -26,7 +26,7 @@ module Elasticated
|
|
26
26
|
break if current_page >= total_pages
|
27
27
|
|
28
28
|
response = client.scroll results.scroll_id, scroll: scroll_expiration_time
|
29
|
-
new_results =
|
29
|
+
new_results = parse_and_prepare_results response
|
30
30
|
hits = new_results.documents
|
31
31
|
doc_count = results.documents.count
|
32
32
|
new_results.documents = hits.first(target_size - doc_count) if query.limited? && (doc_count + hits.count > target_size)
|
@@ -40,6 +40,13 @@ module Elasticated
|
|
40
40
|
repository.scroll_page_size
|
41
41
|
end
|
42
42
|
|
43
|
+
# results preparation
|
44
|
+
|
45
|
+
def parse_and_prepare_results(response, query=nil)
|
46
|
+
results = Results.parse response, query
|
47
|
+
repository.send :prepare_served_results, results # TODO fixme
|
48
|
+
end
|
49
|
+
|
43
50
|
end
|
44
51
|
end
|
45
52
|
end
|
data/lib/elasticated/results.rb
CHANGED
@@ -29,6 +29,8 @@ module Elasticated
|
|
29
29
|
alias_method :from_elasticsearch_response, :parse
|
30
30
|
end
|
31
31
|
|
32
|
+
include Mixins::Inspectionable
|
33
|
+
|
32
34
|
attr_accessor :scroll_id
|
33
35
|
attr_accessor :took, :timed_out
|
34
36
|
attr_accessor :shards # methods: total, successful, failed
|
@@ -58,5 +60,17 @@ module Elasticated
|
|
58
60
|
documents.count
|
59
61
|
end
|
60
62
|
|
63
|
+
def text_for_inspect
|
64
|
+
text = "#{hits.total} hits"
|
65
|
+
text = case documents.count
|
66
|
+
when 0; "#{text}, no documents"
|
67
|
+
when 1; "#{text}, 1 document"
|
68
|
+
else; "#{text}, #{documents.count} documents"
|
69
|
+
end
|
70
|
+
text = aggregations ? "#{text}, with aggregations" : "#{text}, no aggregations"
|
71
|
+
text = "#{text}, including scroll_id" if scroll_id
|
72
|
+
text
|
73
|
+
end
|
74
|
+
|
61
75
|
end
|
62
76
|
end
|
data/lib/version.rb
CHANGED
@@ -1,33 +1,26 @@
|
|
1
1
|
module Elasticated
|
2
|
-
VERSION = '
|
2
|
+
VERSION = '3.0.0'
|
3
3
|
end
|
4
4
|
|
5
5
|
# Changelog
|
6
6
|
|
7
|
-
#
|
8
|
-
# Se
|
9
|
-
|
10
|
-
#
|
11
|
-
#
|
12
|
-
|
13
|
-
#
|
14
|
-
#
|
15
|
-
|
16
|
-
#
|
17
|
-
# Se
|
18
|
-
|
19
|
-
#
|
20
|
-
#
|
21
|
-
|
22
|
-
#
|
23
|
-
# Ahora
|
24
|
-
# Se puede delimitar por aggregations
|
25
|
-
|
26
|
-
# 2.4.0
|
27
|
-
# Ahora se puede ordenar un search por un campo, script o hash custom
|
28
|
-
|
29
|
-
# 2.3.0
|
30
|
-
# Ahora DateFieldDelimiter admite multiples fechas declaradas en un TermsCondition
|
7
|
+
# Ahora Repository#execute_aggregated_search puede definir automaticamente si ejecutar las aggregations o no
|
8
|
+
# Se agrega el alias 'range' para la condicion 'between'
|
9
|
+
# Se agrega el alias 'terms' para la condicion 'equal'
|
10
|
+
# Se agregan get, delete, y mget a Repository
|
11
|
+
# Ahora el GroupAggregation se puede invocar como 'terms' ademas de 'group'
|
12
|
+
# Se elimina la opcion 'include_count' de todas las aggregations que la utilizaban
|
13
|
+
# Ya no se permite pasar la opcion 'compact' a aggregations que posean subaggregations
|
14
|
+
# Ahora se puede llamar a bloque de aggregations por medio del alias 'aggs'
|
15
|
+
# Ahora Repository#update_document actualiza parcialmente el documento
|
16
|
+
# Cambian los pre-action y post-action preparation methods
|
17
|
+
# Se incluye la extension 'test cluster' y las tareas rake para administrarlo
|
18
|
+
# ResumableSearch ahora hace 'restore' de los documentos que devuelve
|
19
|
+
# Se agregan mejores vistas de inspeccion para Query, Results y Document
|
20
|
+
# Ahora se pueden pedir los documentos sin source
|
21
|
+
# Ahora el PartitionedRepository soporta :now
|
22
|
+
# Se agrega TermCondition
|
23
|
+
# Ahora se puede especificar si el mapping es dinamico
|
31
24
|
|
32
25
|
# 2.2.0
|
33
26
|
# Se agrega la funcionalidad para especificar un orden aleatorio en las queries
|
data/spec/aggregation_spec.rb
CHANGED
@@ -147,9 +147,9 @@ module Elasticated
|
|
147
147
|
it "should map a group aggregation response" do
|
148
148
|
agg = GroupAggregation.new :field
|
149
149
|
response = { 'buckets' => [
|
150
|
-
{ 'key' => 'value1', 'doc_count' => 'count1' },
|
151
|
-
{ 'key' => 'value2', 'doc_count' => 'count2' },
|
152
|
-
{ 'key' => 'value3', 'doc_count' => 'count3' }
|
150
|
+
{ 'key' => 'value1', 'doc_count' => 'count1', 'key_as_string' => 'value1str' },
|
151
|
+
{ 'key' => 'value2', 'doc_count' => 'count2', 'key_as_string' => 'value2str' },
|
152
|
+
{ 'key' => 'value3', 'doc_count' => 'count3', 'key_as_string' => 'value3str' }
|
153
153
|
] }
|
154
154
|
expect(agg.parse(response)).to eq({
|
155
155
|
'value1' => { 'count' => 'count1' },
|
@@ -158,12 +158,26 @@ module Elasticated
|
|
158
158
|
})
|
159
159
|
end
|
160
160
|
|
161
|
+
it "should map a group aggregation response including the 'key_as_string' value" do
|
162
|
+
agg = GroupAggregation.new :field, key_as_string: true
|
163
|
+
response = { 'buckets' => [
|
164
|
+
{ 'key' => 'value1', 'doc_count' => 'count1', 'key_as_string' => 'value1str' },
|
165
|
+
{ 'key' => 'value2', 'doc_count' => 'count2', 'key_as_string' => 'value2str' },
|
166
|
+
{ 'key' => 'value3', 'doc_count' => 'count3', 'key_as_string' => 'value3str' }
|
167
|
+
] }
|
168
|
+
expect(agg.parse(response)).to eq({
|
169
|
+
'value1' => { 'count' => 'count1', 'key_as_string' => 'value1str' },
|
170
|
+
'value2' => { 'count' => 'count2', 'key_as_string' => 'value2str' },
|
171
|
+
'value3' => { 'count' => 'count3', 'key_as_string' => 'value3str' }
|
172
|
+
})
|
173
|
+
end
|
174
|
+
|
161
175
|
it "should map a group aggregation response compacted" do
|
162
176
|
agg = GroupAggregation.new :field, compact: true
|
163
177
|
response = { 'buckets' => [
|
164
|
-
{ 'key' => 'value1', 'doc_count' => 'count1' },
|
165
|
-
{ 'key' => 'value2', 'doc_count' => 'count2' },
|
166
|
-
{ 'key' => 'value3', 'doc_count' => 'count3' }
|
178
|
+
{ 'key' => 'value1', 'doc_count' => 'count1', 'key_as_string' => 'value1str' },
|
179
|
+
{ 'key' => 'value2', 'doc_count' => 'count2', 'key_as_string' => 'value2str' },
|
180
|
+
{ 'key' => 'value3', 'doc_count' => 'count3', 'key_as_string' => 'value3str' }
|
167
181
|
] }
|
168
182
|
expect(agg.parse(response)).to eq({
|
169
183
|
'value1' => 'count1',
|
@@ -172,6 +186,16 @@ module Elasticated
|
|
172
186
|
})
|
173
187
|
end
|
174
188
|
|
189
|
+
it "should raise if a group aggregation is compacted but has subaggregations" do
|
190
|
+
agg = GroupAggregation.new(:field, compact: true){ max :other_field }
|
191
|
+
response = { 'buckets' => [
|
192
|
+
{ 'key' => 'value1', 'doc_count' => 'count1', 'key_as_string' => 'value1str' },
|
193
|
+
{ 'key' => 'value2', 'doc_count' => 'count2', 'key_as_string' => 'value2str' },
|
194
|
+
{ 'key' => 'value3', 'doc_count' => 'count3', 'key_as_string' => 'value3str' }
|
195
|
+
] }
|
196
|
+
expect{ agg.parse(response) }.to raise_error RuntimeError
|
197
|
+
end
|
198
|
+
|
175
199
|
end
|
176
200
|
|
177
201
|
describe ValueCountAggregation do
|
@@ -251,12 +275,6 @@ module Elasticated
|
|
251
275
|
expect(agg.build).to eq expected_result
|
252
276
|
end
|
253
277
|
|
254
|
-
it "should build a date histogram aggregation with offset for date" do
|
255
|
-
agg = DateHistogramAggregation.new :date, offset: '+6h'
|
256
|
-
expected_result = { date_histogram: { field: :date, interval: 'day', format: 'yyyy-MM-dd', offset: '+6h' } }
|
257
|
-
expect(agg.build).to eq expected_result
|
258
|
-
end
|
259
|
-
|
260
278
|
it "should build a date histogram aggregation with subaggregations" do
|
261
279
|
agg = DateHistogramAggregation.new :date do |docs|
|
262
280
|
docs.max :numeric_field
|
@@ -474,6 +492,42 @@ module Elasticated
|
|
474
492
|
})
|
475
493
|
end
|
476
494
|
|
495
|
+
it "should map a 'range' response with subaggregations" do
|
496
|
+
agg = RangeAggregation.new :a_field do |a|
|
497
|
+
a.ranges do |r|
|
498
|
+
r.greater_equal :max_value, 'high_values'
|
499
|
+
r.less_equal :min_value
|
500
|
+
r.between :min_value, :max_value
|
501
|
+
end
|
502
|
+
a.max :other_field
|
503
|
+
end
|
504
|
+
response = {
|
505
|
+
'buckets' => {
|
506
|
+
'high_values' => {
|
507
|
+
'from' => 'max_value',
|
508
|
+
'doc_count' => 5,
|
509
|
+
'max_other_field' => { 'value' => 15 }
|
510
|
+
},
|
511
|
+
'less_equal_min_value' => {
|
512
|
+
'to' => 'min_value',
|
513
|
+
'doc_count' => 3,
|
514
|
+
'max_other_field' => { 'value' => 15 }
|
515
|
+
},
|
516
|
+
'between_min_value_and_max_value' => {
|
517
|
+
'from' => 'min_value',
|
518
|
+
'to' => 'max_value',
|
519
|
+
'doc_count' => 9,
|
520
|
+
'max_other_field' => { 'value' => 15 }
|
521
|
+
}
|
522
|
+
}
|
523
|
+
}
|
524
|
+
expect(agg.parse(response)).to eq({
|
525
|
+
'high_values' => { 'count' => 5, 'max_other_field' => 15 },
|
526
|
+
'less_equal_min_value' => { 'count' => 3, 'max_other_field' => 15 },
|
527
|
+
'between_min_value_and_max_value' => { 'count' => 9, 'max_other_field' => 15 }
|
528
|
+
})
|
529
|
+
end
|
530
|
+
|
477
531
|
it "should map a 'range' response compacted" do
|
478
532
|
agg = RangeAggregation.new :a_field, compact: true do |a|
|
479
533
|
a.ranges do |r|
|
@@ -506,6 +560,35 @@ module Elasticated
|
|
506
560
|
})
|
507
561
|
end
|
508
562
|
|
563
|
+
it "should raise on a subaggregated and compacted 'range'" do
|
564
|
+
agg = RangeAggregation.new :a_field, compact: true do |a|
|
565
|
+
a.ranges do |r|
|
566
|
+
r.greater_equal :max_value, 'high_values'
|
567
|
+
r.less_equal :min_value
|
568
|
+
r.between :min_value, :max_value
|
569
|
+
end
|
570
|
+
a.max :other_field
|
571
|
+
end
|
572
|
+
response = {
|
573
|
+
'buckets' => {
|
574
|
+
'high_values' => {
|
575
|
+
'from' => 'max_value',
|
576
|
+
'doc_count' => 5
|
577
|
+
},
|
578
|
+
'less_equal_min_value' => {
|
579
|
+
'to' => 'min_value',
|
580
|
+
'doc_count' => 3
|
581
|
+
},
|
582
|
+
'between_min_value_and_max_value' => {
|
583
|
+
'from' => 'min_value',
|
584
|
+
'to' => 'max_value',
|
585
|
+
'doc_count' => 9
|
586
|
+
}
|
587
|
+
}
|
588
|
+
}
|
589
|
+
expect{ agg.parse(response) }.to raise_error RuntimeError
|
590
|
+
end
|
591
|
+
|
509
592
|
end
|
510
593
|
|
511
594
|
describe SumDistinctAggregation do
|
@@ -550,10 +633,6 @@ module Elasticated
|
|
550
633
|
|
551
634
|
describe TopHitsAggregation do
|
552
635
|
|
553
|
-
def open_response(name)
|
554
|
-
JSON.parse File.read "spec/#{name}.json"
|
555
|
-
end
|
556
|
-
|
557
636
|
it "should build a 'top hits' aggregation" do
|
558
637
|
agg = TopHitsAggregation.new :some_name do |q|
|
559
638
|
q.size 5
|
@@ -0,0 +1,158 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
|
3
|
+
module Elasticated
|
4
|
+
describe BulkRequest do
|
5
|
+
|
6
|
+
let :repository do
|
7
|
+
Repository.new
|
8
|
+
end
|
9
|
+
|
10
|
+
context "in the index-like actions" do
|
11
|
+
|
12
|
+
let :document do
|
13
|
+
Document.create do |doc|
|
14
|
+
doc.id = '2'
|
15
|
+
doc.type = 'post'
|
16
|
+
doc.index = 'insights'
|
17
|
+
doc.source = { some_field: 'some_value' }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should build an index action (with only a doc)" do
|
22
|
+
action = BulkActions::IndexAction.new repository, document
|
23
|
+
expect(action.build).to eq [
|
24
|
+
{ index: { _index: "insights", _type: "post", _id: "2" } },
|
25
|
+
{ some_field: "some_value" }
|
26
|
+
]
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should build an index action (with a doc and other params)" do
|
30
|
+
action = BulkActions::IndexAction.new repository, document, id: "5", type: 'faketype', index: 'fakeindex'
|
31
|
+
expect(action.build).to eq [
|
32
|
+
{ index: { _index: "fakeindex", _type: "faketype", _id: "5" } },
|
33
|
+
{ some_field: "some_value" }
|
34
|
+
]
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should build an create action (with only a doc)" do
|
38
|
+
action = BulkActions::CreateAction.new repository, document
|
39
|
+
expect(action.build).to eq [
|
40
|
+
{ create: { _index: "insights", _type: "post", _id: "2" } },
|
41
|
+
{ some_field: "some_value" }
|
42
|
+
]
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should build an create action (with a doc and other params)" do
|
46
|
+
action = BulkActions::CreateAction.new repository, document, id: "5", type: 'faketype', index: 'fakeindex'
|
47
|
+
expect(action.build).to eq [
|
48
|
+
{ create: { _index: "fakeindex", _type: "faketype", _id: "5" } },
|
49
|
+
{ some_field: "some_value" }
|
50
|
+
]
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
context "in the update-like actions" do
|
56
|
+
|
57
|
+
let(:source){ { some_field: 'some_value' } }
|
58
|
+
|
59
|
+
it "should build an update action" do
|
60
|
+
action = BulkActions::UpdateAction.new repository, "2", type: "post", index: "insights", source: source
|
61
|
+
expect(action.build).to eq [
|
62
|
+
{ update: { _index: "insights", _type: "post", _id: "2" } },
|
63
|
+
{ doc: { some_field: "some_value" } }
|
64
|
+
]
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should build an upsert action" do
|
68
|
+
action = BulkActions::UpsertAction.new repository, "2", type: "post", index: "insights", source: source
|
69
|
+
expect(action.build).to eq [
|
70
|
+
{ update: { _index: "insights", _type: "post", _id: "2" } },
|
71
|
+
{ doc: { some_field: "some_value" }, doc_as_upsert: true }
|
72
|
+
]
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
context "in the delete-like actions" do
|
78
|
+
|
79
|
+
it "should build a delete action" do
|
80
|
+
action = BulkActions::DeleteAction.new repository, '2', index: 'insights', type: 'post'
|
81
|
+
expect(action.build).to eq [
|
82
|
+
{ delete: { _index: "insights", _type: "post", _id: "2" } }
|
83
|
+
]
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
|
88
|
+
context "the bulk request" do
|
89
|
+
|
90
|
+
let :source do
|
91
|
+
{ some_field: 'some_value' }
|
92
|
+
end
|
93
|
+
|
94
|
+
let :document do
|
95
|
+
Document.create do |doc|
|
96
|
+
doc.id = '2'
|
97
|
+
doc.type = 'post'
|
98
|
+
doc.index = 'insights'
|
99
|
+
doc.source = source
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
it "should build a serie of actions correctly" do
|
104
|
+
bulk_request = BulkRequest.build_over repository do |r|
|
105
|
+
r.delete_document "2", type: 'post', index: 'insights'
|
106
|
+
r.create_document document
|
107
|
+
r.update_document "2", type: 'post', index: 'insights', source: source
|
108
|
+
r.index_document document
|
109
|
+
end
|
110
|
+
expect(bulk_request.to_text).to eq \
|
111
|
+
'{"delete":{"_index":"insights","_type":"post","_id":"2"}}' + "\n" +
|
112
|
+
'{"create":{"_index":"insights","_type":"post","_id":"2"}}' + "\n" +
|
113
|
+
'{"some_field":"some_value"}' + "\n" +
|
114
|
+
'{"update":{"_index":"insights","_type":"post","_id":"2"}}' + "\n" +
|
115
|
+
'{"doc":{"some_field":"some_value"}}' + "\n" +
|
116
|
+
'{"index":{"_index":"insights","_type":"post","_id":"2"}}' + "\n" +
|
117
|
+
'{"some_field":"some_value"}'
|
118
|
+
end
|
119
|
+
|
120
|
+
it "should parse a simple response" do
|
121
|
+
elasticsearch_response = open_response 'elasticsearch_bulk_response_1'
|
122
|
+
bulk_request = BulkRequest.build_over repository # actions actually doesnt matter
|
123
|
+
response = bulk_request.parse elasticsearch_response
|
124
|
+
expect(response.errors?).to be false
|
125
|
+
expect(response.items.count).to eql 4
|
126
|
+
item1 = response.items[0]
|
127
|
+
expect(item1.action).to eq 'delete'
|
128
|
+
expect(item1.index).to eq 'website'
|
129
|
+
expect(item1.type).to eq 'blog'
|
130
|
+
expect(item1.id).to eq '123'
|
131
|
+
expect(item1.version).to eql 2
|
132
|
+
expect(item1.status).to eq 200
|
133
|
+
expect(item1.found).to be true
|
134
|
+
expect(item1.error?).to be false
|
135
|
+
expect(item1.completed?).to be true
|
136
|
+
end
|
137
|
+
|
138
|
+
it "should parse a simple response with errors" do
|
139
|
+
elasticsearch_response = open_response 'elasticsearch_bulk_response_2'
|
140
|
+
bulk_request = BulkRequest.build_over repository # actions actually doesnt matter
|
141
|
+
response = bulk_request.parse elasticsearch_response
|
142
|
+
expect(response.errors?).to be true
|
143
|
+
expect(response.items.count).to eql 2
|
144
|
+
item1 = response.items[0]
|
145
|
+
expect(item1.action).to eq 'create'
|
146
|
+
expect(item1.index).to eq 'website'
|
147
|
+
expect(item1.type).to eq 'blog'
|
148
|
+
expect(item1.id).to eq '123'
|
149
|
+
expect(item1.status).to eq 409
|
150
|
+
expect(item1.error).to eq 'DocumentAlreadyExistsException[[website][4] [blog][123]: document already exists]'
|
151
|
+
expect(item1.error?).to be true
|
152
|
+
expect(item1.completed?).to be false
|
153
|
+
end
|
154
|
+
|
155
|
+
end
|
156
|
+
|
157
|
+
end
|
158
|
+
end
|