elasticated 2.4.0 → 2.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0c21bce40f279a26bfc18215caed1f0e2869584d
4
- data.tar.gz: b6b33eabf8cb3ea40a848b4ba012201c630c6b2b
3
+ metadata.gz: 6637480a40d6c018f1edc45efa103df9c836f81f
4
+ data.tar.gz: a65c27a00654dd7616e9f8086441f4365f616d24
5
5
  SHA512:
6
- metadata.gz: 1f6b73bf87e1c6da918a9dcbe88ddec3f7cc2a0fa1dbe49133c3170908f58ecf095a197082846506b5dc8e23ef3be5cfd5be7f4a86bbf48f9196f98d6f3d2fd6
7
- data.tar.gz: 51fdff057ce01cce2113d448c7426ec89fb0304e76b7fe646f28071730118b17b5805e1779b0843f153200bcf24d9e0a54e0fc68973a3c8aeba548a2580e765e
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
@@ -32,5 +32,9 @@ module Elasticated
32
32
  end
33
33
  end
34
34
 
35
+ def accept_visitor(visitor)
36
+ visitor.visit_aggregation(self)
37
+ end
38
+
35
39
  end
36
40
  end
@@ -36,5 +36,9 @@ module Elasticated
36
36
  end
37
37
  end
38
38
 
39
+ def accept_visitor(visitor)
40
+ visitor.visit_filter_aggregation(self)
41
+ end
42
+
39
43
  end
40
44
  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)
@@ -14,8 +14,8 @@ module Elasticated
14
14
  body
15
15
  end
16
16
 
17
- def fill_delimiter(field_delimiter)
18
- # nothing to do
17
+ def accept_visitor(visitor)
18
+ visitor.visit_condition(self)
19
19
  end
20
20
 
21
21
  end
@@ -15,11 +15,8 @@ module Elasticated
15
15
  { range: { field => body }.merge(opts) }
16
16
  end
17
17
 
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
18
+ def accept_visitor(visitor)
19
+ visitor.visit_range(self)
23
20
  end
24
21
 
25
22
  end
@@ -17,8 +17,8 @@ module Elasticated
17
17
  { script: body }
18
18
  end
19
19
 
20
- def fill_delimiter(field_delimiter)
21
- # nothing to do
20
+ def accept_visitor(visitor)
21
+ visitor.visit_condition(self)
22
22
  end
23
23
 
24
24
  end
@@ -13,8 +13,8 @@ module Elasticated
13
13
  self.opts = opts
14
14
  end
15
15
 
16
- def fill_delimiter(field_delimiter)
17
- # nothing to do, by default
16
+ def accept_visitor(visitor)
17
+ visitor.visit_condition(self)
18
18
  end
19
19
 
20
20
  end
@@ -13,8 +13,8 @@ module Elasticated
13
13
  { terms: { field => values }.merge(opts) }
14
14
  end
15
15
 
16
- def fill_delimiter(field_delimiter)
17
- values.each{ |value| field_delimiter.add_term field, value }
16
+ def accept_visitor(visitor)
17
+ visitor.visit_terms(self)
18
18
  end
19
19
 
20
20
  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 < TermFieldDelimiter
3
+ class DateFieldDelimiter < StandardFieldDelimiter
4
4
 
5
5
  attr_accessor :date_since, :date_until
6
6
 
7
- def set_minimum(field, date)
8
- return unless applies_to? field
9
- self.date_since = date unless date_since && date < date_since
10
- end
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
- if values.empty?
20
- raise "date_since is higher than date_until (#{date_since} - #{date_until})" \
21
- if date_since && date_until && date_since > date_until
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 :field
12
- self.filter_name = opts.fetch :as, field_name
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 = Array.new
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
- def indices_for_query(query)
12
- strategy_params = strategy_params_for_query query
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