elasticated 2.4.0 → 2.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.
- checksums.yaml +4 -4
- data/lib/elasticated.rb +20 -0
- data/lib/elasticated/aggregation.rb +4 -0
- data/lib/elasticated/aggregations/filter_aggregation.rb +4 -0
- data/lib/elasticated/boolean_clause.rb +8 -0
- data/lib/elasticated/conditions/custom_condition.rb +2 -2
- data/lib/elasticated/conditions/range_condition.rb +2 -5
- data/lib/elasticated/conditions/script_condition.rb +2 -2
- data/lib/elasticated/conditions/standard_condition.rb +2 -2
- data/lib/elasticated/conditions/terms_condition.rb +2 -2
- data/lib/elasticated/date_delimiter_factory.rb +123 -0
- data/lib/elasticated/delimiter_visitor.rb +51 -0
- data/lib/elasticated/delimiters/date_field_delimiter.rb +14 -19
- data/lib/elasticated/delimiters/standard_field_delimiter.rb +2 -18
- data/lib/elasticated/delimiters/term_field_delimiter.rb +5 -6
- data/lib/elasticated/index_selector.rb +10 -12
- data/lib/elasticated/partitioned_repository.rb +9 -4
- data/lib/elasticated/query.rb +4 -5
- data/lib/elasticated/query_aggregations.rb +5 -1
- data/lib/elasticated/query_conditions.rb +2 -4
- data/lib/elasticated/strategy_params_for_query_service.rb +14 -0
- data/lib/elasticated/term_delimiter_factory.rb +71 -0
- data/lib/version.rb +5 -1
- data/spec/date_field_delimiter_spec.rb +4 -43
- data/spec/delimiter_factory_spec.rb +366 -0
- data/spec/query_conditions_spec.rb +0 -59
- data/spec/strategy_params_for_query_service_spec.rb +328 -0
- data/spec/term_field_delimiter_spec.rb +8 -8
- metadata +28 -20
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6637480a40d6c018f1edc45efa103df9c836f81f
|
4
|
+
data.tar.gz: a65c27a00654dd7616e9f8086441f4365f616d24
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1cda536b17d2dddb5d62be83cb2f2ae15555569df1fe7086574f1605c379897f12f9952e0047be486d4fc5b59f35f891544d7d466975b87ab4068a57b1b4b553
|
7
|
+
data.tar.gz: 904e56da96d375422ac0951ffababf82f262e7afb68dd6a2cde125f1f9b2954bcc6d4eabb41bf4b3448132e352fcd451c462db4975cb597a5d9050acb07f396b
|
data/lib/elasticated.rb
CHANGED
@@ -30,6 +30,10 @@ require_relative 'elasticated/conditions/custom_condition'
|
|
30
30
|
require_relative 'elasticated/delimiters/standard_field_delimiter'
|
31
31
|
require_relative 'elasticated/delimiters/term_field_delimiter'
|
32
32
|
require_relative 'elasticated/delimiters/date_field_delimiter'
|
33
|
+
require_relative 'elasticated/term_delimiter_factory'
|
34
|
+
require_relative 'elasticated/date_delimiter_factory'
|
35
|
+
require_relative 'elasticated/delimiter_visitor'
|
36
|
+
require_relative 'elasticated/strategy_params_for_query_service'
|
33
37
|
|
34
38
|
# query components
|
35
39
|
|
@@ -112,4 +116,20 @@ module Elasticated
|
|
112
116
|
block.call Configuration
|
113
117
|
end
|
114
118
|
|
119
|
+
def self.date_delimiter_factory
|
120
|
+
@date_delimiter_factory ||= DateDelimiterFactory.new
|
121
|
+
end
|
122
|
+
|
123
|
+
def self.term_delimiter_factory
|
124
|
+
@term_delimiter_factory ||= TermDelimiterFactory.new
|
125
|
+
end
|
126
|
+
|
127
|
+
def self.delimiter_visitor
|
128
|
+
@delimiter_visitor ||= DelimiterVisitor.new
|
129
|
+
end
|
130
|
+
|
131
|
+
def self.strategy_params_for_query_service
|
132
|
+
@strategy_params_for_query_service ||= StrategyParamsForQueryService.new
|
133
|
+
end
|
134
|
+
|
115
135
|
end
|
@@ -11,10 +11,18 @@ module Elasticated
|
|
11
11
|
|
12
12
|
# delimiters
|
13
13
|
|
14
|
+
def accept_visitor(visitor)
|
15
|
+
visitor.visit_boolean_clause(self)
|
16
|
+
end
|
17
|
+
|
14
18
|
def fill_delimiter(field_delimiter)
|
15
19
|
conditions.each{ |condition| condition.fill_delimiter field_delimiter }
|
16
20
|
end
|
17
21
|
|
22
|
+
def delimiters
|
23
|
+
conditions.map(&:delimiter)
|
24
|
+
end
|
25
|
+
|
18
26
|
# conditions
|
19
27
|
|
20
28
|
def add(condition)
|
@@ -15,11 +15,8 @@ module Elasticated
|
|
15
15
|
{ range: { field => body }.merge(opts) }
|
16
16
|
end
|
17
17
|
|
18
|
-
def
|
19
|
-
|
20
|
-
field_delimiter.set_minimum field, minimum_value
|
21
|
-
maximum_value = body[:lt] || body[:lte]
|
22
|
-
field_delimiter.set_maximum field, maximum_value
|
18
|
+
def accept_visitor(visitor)
|
19
|
+
visitor.visit_range(self)
|
23
20
|
end
|
24
21
|
|
25
22
|
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
module Elasticated
|
2
|
+
class DateDelimiterFactory
|
3
|
+
|
4
|
+
def create(empty_delimiter, query_delimiters, opts={})
|
5
|
+
klass = Delimiters::DateFieldDelimiter
|
6
|
+
field = empty_delimiter.field_name
|
7
|
+
filter_name = empty_delimiter.filter_name
|
8
|
+
field_since = "#{field}_since".to_sym
|
9
|
+
field_until = "#{field}_until".to_sym
|
10
|
+
filter_since = "#{filter_name}_since".to_sym
|
11
|
+
filter_until = "#{filter_name}_until".to_sym
|
12
|
+
field_term = field.to_sym
|
13
|
+
delimit_by = opts.fetch(:delimit_by, [:conditions])
|
14
|
+
|
15
|
+
case delimit_by
|
16
|
+
when []
|
17
|
+
_since = nil
|
18
|
+
_until = nil
|
19
|
+
when [:conditions]
|
20
|
+
if has_terms?(query_delimiters, :conditions, field_term)
|
21
|
+
_since = since_condition_delimiters(query_delimiters.fetch(:conditions, []), field_term)
|
22
|
+
_until = until_condition_delimiters(query_delimiters.fetch(:conditions, []), field_term)
|
23
|
+
else
|
24
|
+
_since = since_condition_delimiters(query_delimiters.fetch(:conditions, []), field_since)
|
25
|
+
_until = until_condition_delimiters(query_delimiters.fetch(:conditions, []), field_until)
|
26
|
+
end
|
27
|
+
when [:aggregations]
|
28
|
+
if has_terms?(query_delimiters, :aggregations, field_term)
|
29
|
+
_since = since_aggregation_delimiters(query_delimiters.fetch(:aggregations, []), field_term)
|
30
|
+
_until = until_aggregation_delimiters(query_delimiters.fetch(:aggregations, []), field_term)
|
31
|
+
else
|
32
|
+
_since = since_aggregation_delimiters(query_delimiters.fetch(:aggregations, []), field_since)
|
33
|
+
_until = until_aggregation_delimiters(query_delimiters.fetch(:aggregations, []), field_until)
|
34
|
+
end
|
35
|
+
when [:conditions, :aggregations]
|
36
|
+
if has_terms?(query_delimiters, :conditions, field_term)
|
37
|
+
_since = since_condition_delimiters(query_delimiters.fetch(:conditions, []), field_term)
|
38
|
+
_until = until_condition_delimiters(query_delimiters.fetch(:conditions, []), field_term)
|
39
|
+
_since = since_aggregation_delimiters(query_delimiters.fetch(:aggregations, []), field_term) if _since.empty?
|
40
|
+
_until = until_aggregation_delimiters(query_delimiters.fetch(:aggregations, []), field_term) if _until.empty?
|
41
|
+
else
|
42
|
+
condition_since = since_condition_delimiters(query_delimiters.fetch(:conditions, []), field_since)
|
43
|
+
condition_until = until_condition_delimiters(query_delimiters.fetch(:conditions, []), field_until)
|
44
|
+
aggregation_since = since_aggregation_delimiters(query_delimiters.fetch(:aggregations, []), field_since)
|
45
|
+
aggregation_until = until_aggregation_delimiters(query_delimiters.fetch(:aggregations, []), field_until)
|
46
|
+
_since = condition_since || aggregation_since
|
47
|
+
_until = condition_until || aggregation_until
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
filtered_empty_delimiter = {
|
52
|
+
filter_since => _since,
|
53
|
+
filter_until => _until
|
54
|
+
}.select { |_, v| not v.nil? }
|
55
|
+
|
56
|
+
klass.new(filtered_empty_delimiter.merge(field: field, as: filter_name))
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def since_aggregation_delimiters(all_aggregation_delimiters, field_since)
|
62
|
+
return nil if missing_field?(all_aggregation_delimiters, field_since)
|
63
|
+
return min_since_delimiter(all_aggregation_delimiters, field_since) if all_aggregation_delimiters.any? { |delimiter| delimiter[field_since].is_a? Array }
|
64
|
+
since_delimiters = all_aggregation_delimiters.min_by { |delimiter| delimiter[field_since] }
|
65
|
+
since_delimiters.nil? ? nil : since_delimiters[field_since]
|
66
|
+
end
|
67
|
+
|
68
|
+
def since_condition_delimiters(all_condition_delimiters, field_since)
|
69
|
+
condition_delimiterts_with_field = all_condition_delimiters.select { |delimiter| delimiter[field_since] }
|
70
|
+
return min_since_delimiter(condition_delimiterts_with_field, field_since) if condition_delimiterts_with_field.any? { |delimiter| delimiter[field_since].is_a? Array }
|
71
|
+
since_delimiters = condition_delimiterts_with_field.min_by { |delimiter| delimiter[field_since] }
|
72
|
+
since_delimiters.nil? ? nil : since_delimiters[field_since]
|
73
|
+
end
|
74
|
+
|
75
|
+
def min_since_delimiter(delimiters, field)
|
76
|
+
array_delimiters = delimiters.select { |delimiter| delimiter[field].is_a? Array }
|
77
|
+
min_array_delimiter = array_delimiters.min_by { |delimiter| delimiter[field].min }
|
78
|
+
individual_delimiters = delimiters.select { |delimiter| not delimiter[field].is_a? Array }
|
79
|
+
min_individual_delimiter = individual_delimiters.min_by { |delimiter| delimiter[field] }
|
80
|
+
if not (min_array_delimiter.nil? or min_individual_delimiter.nil?)
|
81
|
+
min_array_delimiter > min_individual_delimiter ? min_individual_delimiter : min_array_delimiter
|
82
|
+
else
|
83
|
+
return min_array_delimiter[field].min if min_array_delimiter and min_array_delimiter[field].min
|
84
|
+
min_individual_delimiter
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def until_aggregation_delimiters(all_aggregation_delimiters, field_until)
|
89
|
+
return nil if missing_field?(all_aggregation_delimiters, field_until)
|
90
|
+
return max_until_delimiter(all_aggregation_delimiters, field_until) if all_aggregation_delimiters.any? { |delimiter| delimiter[field_until].is_a? Array }
|
91
|
+
until_delimiters = all_aggregation_delimiters.max_by { |delimiter| delimiter[field_until] }
|
92
|
+
until_delimiters.nil? ? nil : until_delimiters[field_until]
|
93
|
+
end
|
94
|
+
|
95
|
+
def until_condition_delimiters(all_condition_delimiters, field_until)
|
96
|
+
condition_delimiterts_with_field = all_condition_delimiters.select { |delimiter| delimiter[field_until] }
|
97
|
+
return max_until_delimiter(condition_delimiterts_with_field, field_until) if condition_delimiterts_with_field.any? { |delimiter| delimiter[field_until].is_a? Array }
|
98
|
+
until_delimiters = condition_delimiterts_with_field.max_by { |delimiter| delimiter[field_until] }
|
99
|
+
until_delimiters.nil? ? nil : until_delimiters[field_until]
|
100
|
+
end
|
101
|
+
|
102
|
+
def max_until_delimiter(delimiters, field)
|
103
|
+
array_delimiters = delimiters.select { |delimiter| delimiter[field].is_a? Array }
|
104
|
+
max_array_delimiter = array_delimiters.max_by { |delimiter| delimiter[field].max }
|
105
|
+
individual_delimiters = delimiters.select { |delimiter| not delimiter[field].is_a? Array }
|
106
|
+
max_individual_delimiter = individual_delimiters.max_by { |delimiter| delimiter[field] }
|
107
|
+
if not (max_array_delimiter.nil? or max_individual_delimiter.nil?)
|
108
|
+
max_array_delimiter > max_individual_delimiter ? max_individual_delimiter : max_array_delimiter
|
109
|
+
else
|
110
|
+
return max_array_delimiter[field].max if max_array_delimiter and max_array_delimiter[field].max
|
111
|
+
max_individual_delimiter
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def missing_field?(delimiters, field)
|
116
|
+
delimiters.any? { |delimiter| not delimiter.has_key?(field) }
|
117
|
+
end
|
118
|
+
|
119
|
+
def has_terms?(delimiters, condition_or_agg, field)
|
120
|
+
delimiters.fetch(condition_or_agg, []).any? { |delimiter| delimiter[field] }
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Elasticated
|
2
|
+
class DelimiterVisitor
|
3
|
+
|
4
|
+
def visit_query(query)
|
5
|
+
{
|
6
|
+
conditions: query._conditions.accept_visitor(self) + query._filter_conditions.accept_visitor(self),
|
7
|
+
aggregations: query._aggregations.accept_visitor(self)
|
8
|
+
}
|
9
|
+
end
|
10
|
+
|
11
|
+
def visit_query_conditions(query_conditions)
|
12
|
+
query_conditions._must.accept_visitor(self)
|
13
|
+
end
|
14
|
+
|
15
|
+
def visit_boolean_clause(boolean_clause)
|
16
|
+
boolean_clause.conditions.map { |c| c.accept_visitor(self) }
|
17
|
+
end
|
18
|
+
|
19
|
+
def visit_condition(condition)
|
20
|
+
{}
|
21
|
+
end
|
22
|
+
|
23
|
+
def visit_terms(terms_condition)
|
24
|
+
{ terms_condition.field => terms_condition.values }
|
25
|
+
end
|
26
|
+
|
27
|
+
def visit_range(range_condition)
|
28
|
+
field = range_condition.field
|
29
|
+
minimum_value = range_condition.body[:gt] || range_condition.body[:gte]
|
30
|
+
maximum_value = range_condition.body[:lt] || range_condition.body[:lte]
|
31
|
+
|
32
|
+
{}.tap do |h|
|
33
|
+
h["#{field}_since".to_sym] = minimum_value if minimum_value
|
34
|
+
h["#{field}_until".to_sym] = maximum_value if maximum_value
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def visit_query_aggregations(query_aggregations)
|
39
|
+
query_aggregations._aggregations.flat_map { |agg| agg.accept_visitor(self) }
|
40
|
+
end
|
41
|
+
|
42
|
+
def visit_aggregation(aggregation)
|
43
|
+
[]
|
44
|
+
end
|
45
|
+
|
46
|
+
def visit_filter_aggregation(filter_aggregation)
|
47
|
+
filter_aggregation._subaggregations._conditions.accept_visitor(self)
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
@@ -1,37 +1,32 @@
|
|
1
1
|
module Elasticated
|
2
2
|
module Delimiters
|
3
|
-
class DateFieldDelimiter <
|
3
|
+
class DateFieldDelimiter < StandardFieldDelimiter
|
4
4
|
|
5
5
|
attr_accessor :date_since, :date_until
|
6
6
|
|
7
|
-
def
|
8
|
-
|
9
|
-
self.date_since =
|
10
|
-
|
11
|
-
|
12
|
-
def set_maximum(field, date)
|
13
|
-
return unless applies_to? field
|
14
|
-
self.date_until = date unless date_until && date > date_until
|
7
|
+
def initialize(opts={})
|
8
|
+
super
|
9
|
+
self.date_since = opts[:date_since]
|
10
|
+
self.date_until = opts[:date_until]
|
15
11
|
end
|
16
12
|
|
17
13
|
def build_strategy_params
|
18
14
|
params = Hash.new
|
19
|
-
|
20
|
-
|
21
|
-
|
15
|
+
raise "date_since is higher than date_until (#{date_since} - #{date_until})" \
|
16
|
+
if date_since && date_until && date_since > date_until
|
17
|
+
if date_since == date_until and not date_since.nil?
|
18
|
+
params.merge! date: date_since
|
19
|
+
else
|
22
20
|
params.merge! date_since: date_since if date_since
|
23
21
|
params.merge! date_until: date_until if date_until
|
24
|
-
else
|
25
|
-
if values.count > 1
|
26
|
-
params.merge! date_since: values.min
|
27
|
-
params.merge! date_until: values.max
|
28
|
-
else
|
29
|
-
params.merge! date: values.first
|
30
|
-
end
|
31
22
|
end
|
32
23
|
params
|
33
24
|
end
|
34
25
|
|
26
|
+
def completed_with(delimiters, opts={})
|
27
|
+
Elasticated.date_delimiter_factory.create(self, delimiters, opts)
|
28
|
+
end
|
29
|
+
|
35
30
|
end
|
36
31
|
end
|
37
32
|
end
|
@@ -8,24 +8,8 @@ module Elasticated
|
|
8
8
|
attr_accessor :field_name, :filter_name
|
9
9
|
|
10
10
|
def initialize(opts={})
|
11
|
-
self.field_name = opts.fetch
|
12
|
-
self.filter_name = opts.fetch
|
13
|
-
end
|
14
|
-
|
15
|
-
def applies_to?(condition_field)
|
16
|
-
field_name.to_s == condition_field.to_s
|
17
|
-
end
|
18
|
-
|
19
|
-
def add_term(field, value)
|
20
|
-
# nothing to do, by default
|
21
|
-
end
|
22
|
-
|
23
|
-
def set_minimum(field, value)
|
24
|
-
# nothing to do, by default
|
25
|
-
end
|
26
|
-
|
27
|
-
def set_maximum(field, value)
|
28
|
-
# nothing to do, by default
|
11
|
+
self.field_name = opts.fetch(:field)
|
12
|
+
self.filter_name = opts.fetch(:as, field_name)
|
29
13
|
end
|
30
14
|
|
31
15
|
end
|
@@ -6,12 +6,7 @@ module Elasticated
|
|
6
6
|
|
7
7
|
def initialize(opts={})
|
8
8
|
super
|
9
|
-
self.values =
|
10
|
-
end
|
11
|
-
|
12
|
-
def add_term(field, value)
|
13
|
-
return unless applies_to? field
|
14
|
-
values << value
|
9
|
+
self.values = opts[:values] || []
|
15
10
|
end
|
16
11
|
|
17
12
|
def build_strategy_params
|
@@ -19,6 +14,10 @@ module Elasticated
|
|
19
14
|
{ filter_name => values.uniq }
|
20
15
|
end
|
21
16
|
|
17
|
+
def completed_with(delimiters, opts={})
|
18
|
+
Elasticated.term_delimiter_factory.create(self, delimiters, opts)
|
19
|
+
end
|
20
|
+
|
22
21
|
end
|
23
22
|
end
|
24
23
|
end
|
@@ -1,15 +1,20 @@
|
|
1
1
|
module Elasticated
|
2
2
|
class IndexSelector
|
3
3
|
|
4
|
-
# abstract class
|
5
|
-
# child must implement 'delimiters()'
|
6
|
-
# child must implement 'strategy()'
|
7
4
|
# child can override 'strategy_params_for(document)'
|
8
5
|
|
9
6
|
include BlockEvaluation
|
10
7
|
|
11
|
-
|
12
|
-
|
8
|
+
attr_reader :strategy, :delimiters
|
9
|
+
|
10
|
+
# params will not be optionals in the next version
|
11
|
+
def initialize(strategy=nil, delimiters=nil)
|
12
|
+
@strategy = strategy
|
13
|
+
@delimiters = delimiters
|
14
|
+
end
|
15
|
+
|
16
|
+
def indices_for_query(query, opts={})
|
17
|
+
strategy_params = Elasticated.strategy_params_for_query_service.strategy_params_for_query delimiters, query, opts
|
13
18
|
indices = strategy.call strategy_params
|
14
19
|
raise "At least one index should be affected for a search" if indices.count < 1
|
15
20
|
indices
|
@@ -41,13 +46,6 @@ module Elasticated
|
|
41
46
|
end
|
42
47
|
end
|
43
48
|
|
44
|
-
def strategy_params_for_query(query)
|
45
|
-
delimiters.inject Hash.new do |params, delimiter|
|
46
|
-
query.fill_delimiter delimiter
|
47
|
-
params.merge delimiter.build_strategy_params
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
49
|
def strategy_params_for_percolator(query)
|
52
50
|
{ date: DateTime.now.iso8601 }
|
53
51
|
end
|