elasticated 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (83) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +35 -0
  3. data/Gemfile +4 -0
  4. data/README.md +3 -0
  5. data/Rakefile +6 -0
  6. data/elasticated.gemspec +29 -0
  7. data/lib/elasticated.rb +102 -0
  8. data/lib/elasticated/aggregation.rb +36 -0
  9. data/lib/elasticated/aggregations/cardinality_aggregation.rb +15 -0
  10. data/lib/elasticated/aggregations/count_aggregation.rb +15 -0
  11. data/lib/elasticated/aggregations/count_distinct_aggregation.rb +15 -0
  12. data/lib/elasticated/aggregations/count_filtered_aggregation.rb +29 -0
  13. data/lib/elasticated/aggregations/custom_aggregation.rb +25 -0
  14. data/lib/elasticated/aggregations/date_histogram_aggregation.rb +35 -0
  15. data/lib/elasticated/aggregations/filter_aggregation.rb +33 -0
  16. data/lib/elasticated/aggregations/filter_aggregation_evaluator.rb +22 -0
  17. data/lib/elasticated/aggregations/group_aggregation.rb +29 -0
  18. data/lib/elasticated/aggregations/histogram_aggregation.rb +34 -0
  19. data/lib/elasticated/aggregations/nested_aggregation.rb +30 -0
  20. data/lib/elasticated/aggregations/range_aggregation.rb +35 -0
  21. data/lib/elasticated/aggregations/range_aggregation_evaluator.rb +22 -0
  22. data/lib/elasticated/aggregations/ranges_builder.rb +35 -0
  23. data/lib/elasticated/aggregations/single_value_aggregation.rb +47 -0
  24. data/lib/elasticated/aggregations/subaggregated.rb +27 -0
  25. data/lib/elasticated/aggregations/sum_distinct_aggregation.rb +20 -0
  26. data/lib/elasticated/aggregations/terms_aggregation.rb +63 -0
  27. data/lib/elasticated/aggregations/top_hits_aggregation.rb +25 -0
  28. data/lib/elasticated/block_evaluation.rb +15 -0
  29. data/lib/elasticated/boolean_clause.rb +43 -0
  30. data/lib/elasticated/client.rb +84 -0
  31. data/lib/elasticated/clonable.rb +58 -0
  32. data/lib/elasticated/conditions/custom_condition.rb +19 -0
  33. data/lib/elasticated/conditions/exists_condition.rb +11 -0
  34. data/lib/elasticated/conditions/missing_condition.rb +11 -0
  35. data/lib/elasticated/conditions/nested_condition.rb +19 -0
  36. data/lib/elasticated/conditions/range_condition.rb +27 -0
  37. data/lib/elasticated/conditions/script_condition.rb +22 -0
  38. data/lib/elasticated/conditions/standard_condition.rb +26 -0
  39. data/lib/elasticated/conditions/terms_condition.rb +22 -0
  40. data/lib/elasticated/conditions/wildcard_condition.rb +18 -0
  41. data/lib/elasticated/conditions_builder.rb +75 -0
  42. data/lib/elasticated/configurable.rb +9 -0
  43. data/lib/elasticated/configuration.rb +9 -0
  44. data/lib/elasticated/default_logger.rb +27 -0
  45. data/lib/elasticated/delimiters/date_field_delimiter.rb +33 -0
  46. data/lib/elasticated/delimiters/standard_field_delimiter.rb +33 -0
  47. data/lib/elasticated/delimiters/term_field_delimiter.rb +24 -0
  48. data/lib/elasticated/document.rb +46 -0
  49. data/lib/elasticated/helpers.rb +28 -0
  50. data/lib/elasticated/index_selector.rb +44 -0
  51. data/lib/elasticated/inspectionable.rb +9 -0
  52. data/lib/elasticated/mapping.rb +19 -0
  53. data/lib/elasticated/mapping/builder.rb +36 -0
  54. data/lib/elasticated/mapping/fields_builder.rb +148 -0
  55. data/lib/elasticated/mapping/nested_builder.rb +15 -0
  56. data/lib/elasticated/mapping/object_builder.rb +15 -0
  57. data/lib/elasticated/mapping/partial.rb +11 -0
  58. data/lib/elasticated/mapping/type_builder.rb +14 -0
  59. data/lib/elasticated/partitioned_repository.rb +27 -0
  60. data/lib/elasticated/query.rb +159 -0
  61. data/lib/elasticated/query_aggregations.rb +71 -0
  62. data/lib/elasticated/query_conditions.rb +89 -0
  63. data/lib/elasticated/repositories/monthly_partitioned_repository.rb +96 -0
  64. data/lib/elasticated/repository.rb +139 -0
  65. data/lib/elasticated/results.rb +43 -0
  66. data/lib/version.rb +92 -0
  67. data/spec/aggregation_spec.rb +587 -0
  68. data/spec/date_field_delimiter_spec.rb +67 -0
  69. data/spec/document_spec.rb +44 -0
  70. data/spec/elasticsearch_hit_1.json +14 -0
  71. data/spec/elasticsearch_response_1.json +29 -0
  72. data/spec/elasticsearch_response_2.json +44 -0
  73. data/spec/elasticsearch_top_hits_response.json +20 -0
  74. data/spec/integration_spec.rb +184 -0
  75. data/spec/mapping_spec.rb +219 -0
  76. data/spec/monthly_partitioned_repository_spec.rb +99 -0
  77. data/spec/query_aggregations_spec.rb +44 -0
  78. data/spec/query_conditions_spec.rb +314 -0
  79. data/spec/query_spec.rb +265 -0
  80. data/spec/results_spec.rb +69 -0
  81. data/spec/spec_helper.rb +2 -0
  82. data/spec/term_field_delimiter_spec.rb +39 -0
  83. metadata +225 -0
@@ -0,0 +1,58 @@
1
+ module Elasticated
2
+ module Clonable
3
+
4
+ def clone
5
+ ret = super
6
+ instance_variables.each do |instance_variable|
7
+ value = instance_variable_get instance_variable
8
+ value = case value.class
9
+ when Array
10
+ clone_array value
11
+ when Hash
12
+ Helpers.hash_deep_dup value
13
+ else
14
+ value.clone
15
+ end
16
+ ret.instance_variable_set instance_variable, value
17
+ end
18
+ ret
19
+ end
20
+
21
+ def ==(other_entity)
22
+ other_entity.class == self.class &&
23
+ instance_variables.all? do |instance_variable|
24
+ next true if instance_variable == :@_subaggregations # Subaggregated
25
+ value = instance_variable_get instance_variable
26
+ other_value = other_entity.instance_variable_get instance_variable
27
+ case other_value.class
28
+ when Array
29
+ compare_arrays value, other_value
30
+ else
31
+ other_value == value
32
+ end
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ def clone_array(array)
39
+ array.map do |element|
40
+ case element.class
41
+ when Hash
42
+ Helpers.hash_deep_dup element
43
+ when Array
44
+ clone_array element
45
+ else
46
+ element.clone
47
+ end
48
+ end
49
+ end
50
+
51
+ def compare_arrays(array_a, array_b)
52
+ array_a.all? do |element|
53
+ array_b.include? element
54
+ end && array_a.size == array_b.size
55
+ end
56
+
57
+ end
58
+ end
@@ -0,0 +1,19 @@
1
+ module Elasticated
2
+ module Conditions
3
+ class CustomCondition
4
+
5
+ include Inspectionable
6
+
7
+ attr_accessor :body
8
+
9
+ def initialize(body)
10
+ self.body = body
11
+ end
12
+
13
+ def build
14
+ body
15
+ end
16
+
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,11 @@
1
+ module Elasticated
2
+ module Conditions
3
+ class ExistsCondition < StandardCondition
4
+
5
+ def build
6
+ { exists: { field: field }.merge(opts) }
7
+ end
8
+
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module Elasticated
2
+ module Conditions
3
+ class MissingCondition < StandardCondition
4
+
5
+ def build
6
+ { missing: { field: field }.merge(opts) }
7
+ end
8
+
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,19 @@
1
+ module Elasticated
2
+ module Conditions
3
+ class NestedCondition < StandardCondition
4
+
5
+ attr_accessor :inner_conditions
6
+
7
+ def initialize(field, inner_conditions, opts={})
8
+ super(field, opts)
9
+ self.inner_conditions = inner_conditions
10
+ end
11
+
12
+ def build
13
+ body = inner_conditions.build
14
+ { nested: { path: field, filter: body }.merge(opts) }
15
+ end
16
+
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,27 @@
1
+ module Elasticated
2
+ module Conditions
3
+ class RangeCondition < StandardCondition
4
+
5
+ # example: RangeCondition.new :age, gte: 18, lt: 40
6
+
7
+ attr_accessor :body
8
+
9
+ def initialize(field, body, opts={})
10
+ super(field, opts)
11
+ self.body = Hash::Indifferent.new body
12
+ end
13
+
14
+ def build
15
+ { range: { field => body }.merge(opts) }
16
+ end
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
23
+ end
24
+
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,22 @@
1
+ module Elasticated
2
+ module Conditions
3
+ class ScriptCondition
4
+
5
+ include Inspectionable
6
+
7
+ attr_accessor :script, :params
8
+
9
+ def initialize(script, params={})
10
+ self.script = script
11
+ self.params = params
12
+ end
13
+
14
+ def build
15
+ body = { script: script }
16
+ body.merge! params: params unless params.empty?
17
+ { script: body }
18
+ end
19
+
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,26 @@
1
+ module Elasticated
2
+ module Conditions
3
+ class StandardCondition
4
+
5
+ include Inspectionable
6
+
7
+ include Clonable
8
+
9
+ attr_accessor :field, :opts
10
+
11
+ def initialize(field, opts={})
12
+ self.field = field
13
+ self.opts = opts
14
+ end
15
+
16
+ def fill_date_delimiter(dfd)
17
+ # nothing to do, by default
18
+ end
19
+
20
+ def fill_term_delimiter(tfd)
21
+ # nothing to do, by default
22
+ end
23
+
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,22 @@
1
+ module Elasticated
2
+ module Conditions
3
+ class TermsCondition < StandardCondition
4
+
5
+ attr_accessor :values
6
+
7
+ def initialize(field, values, opts={})
8
+ super(field, opts)
9
+ self.values = values
10
+ end
11
+
12
+ def build
13
+ { terms: { field => values }.merge(opts) }
14
+ end
15
+
16
+ def fill_delimiter(field_delimiter)
17
+ values.each{ |value| field_delimiter.add_term field, value }
18
+ end
19
+
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,18 @@
1
+ module Elasticated
2
+ module Conditions
3
+ class WildcardCondition < StandardCondition
4
+
5
+ attr_accessor :regex
6
+
7
+ def initialize(field, regex, opts={})
8
+ super(field, opts)
9
+ self.regex = regex
10
+ end
11
+
12
+ def build
13
+ { wildcard: { field => regex }.merge(opts) }
14
+ end
15
+
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,75 @@
1
+ module Elasticated
2
+ module ConditionsBuilder
3
+
4
+ include BlockEvaluation
5
+
6
+ def custom(body)
7
+ add Conditions::CustomCondition.new body
8
+ end
9
+
10
+ def equal(field, values, opts={})
11
+ add Conditions::TermsCondition.new field, [*values], opts
12
+ end
13
+ alias_method :terms, :equal
14
+
15
+ def wildcard(field, value, opts={})
16
+ add Conditions::WildcardCondition.new field, value, opts
17
+ end
18
+
19
+ def with(field, opts={})
20
+ add Conditions::WildcardCondition.new field, '*', opts
21
+ end
22
+
23
+ def exists(field, opts={})
24
+ add Conditions::ExistsCondition.new field, opts
25
+ end
26
+
27
+ def missing(field, opts={})
28
+ add Conditions::MissingCondition.new field, opts
29
+ end
30
+
31
+ def between(field, min_value, max_value, opts={})
32
+ add Conditions::RangeCondition.new field, { lte: max_value, gte: min_value }, opts
33
+ end
34
+
35
+ def greater_than(field, value, opts={})
36
+ add Conditions::RangeCondition.new field, { gt: value }, opts
37
+ end
38
+ alias_method :gt, :greater_than
39
+
40
+ def greater_equal(field, value, opts={})
41
+ add Conditions::RangeCondition.new field, { gte: value }, opts
42
+ end
43
+ alias_method :ge, :greater_equal
44
+ alias_method :gte, :greater_equal
45
+
46
+ def less_than(field, value, opts={})
47
+ add Conditions::RangeCondition.new field, { lt: value }, opts
48
+ end
49
+ alias_method :lt, :less_than
50
+
51
+ def less_equal(field, value, opts={})
52
+ add Conditions::RangeCondition.new field, { lte: value }, opts
53
+ end
54
+ alias_method :le, :less_equal
55
+ alias_method :lte, :less_equal
56
+
57
+ def nested(path, opts={}, &block)
58
+ inner_conditions = self.class.new
59
+ inner_conditions.evaluate block
60
+ add Conditions::NestedCondition.new path, inner_conditions, opts
61
+ end
62
+
63
+ def script(script, params={})
64
+ add Conditions::ScriptCondition.new script, params
65
+ end
66
+
67
+ def boolean(&block)
68
+ boolean_children = QueryConditions.new
69
+ boolean_children.evaluate block
70
+ add boolean_children
71
+ end
72
+ alias_method :bool, :boolean
73
+
74
+ end
75
+ end
@@ -0,0 +1,9 @@
1
+ module Elasticated
2
+ module Configurable
3
+
4
+ def log
5
+ Configuration.logger ||= DefaultLogger.new
6
+ end
7
+
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Elasticated
2
+ class Configuration
3
+
4
+ class << self
5
+ attr_accessor :logger
6
+ end
7
+
8
+ end
9
+ end
@@ -0,0 +1,27 @@
1
+ module Elasticated
2
+ class DefaultLogger
3
+
4
+ # interface
5
+
6
+ def trace(message)
7
+ puts "TRACE #{message}"
8
+ end
9
+
10
+ def debug(message)
11
+ puts "DEBUG #{message}"
12
+ end
13
+
14
+ def info(message)
15
+ puts "INFO #{message}"
16
+ end
17
+
18
+ def warn(message)
19
+ puts "WARN #{message}"
20
+ end
21
+
22
+ def error(message)
23
+ puts "ERROR #{message}"
24
+ end
25
+
26
+ end
27
+ end
@@ -0,0 +1,33 @@
1
+ module Elasticated
2
+ module Delimiters
3
+ class DateFieldDelimiter < TermFieldDelimiter
4
+
5
+ attr_accessor :date_since, :date_until
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
15
+ end
16
+
17
+ def build_strategy_params
18
+ 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
22
+ params.merge! date_since: date_since if date_since
23
+ params.merge! date_until: date_until if date_until
24
+ else
25
+ raise "Only one 'term' filter is allowed over the '#{field_name}' field" if values.count > 1
26
+ params.merge! date: values.first
27
+ end
28
+ params
29
+ end
30
+
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,33 @@
1
+ module Elasticated
2
+ module Delimiters
3
+ class StandardFieldDelimiter
4
+
5
+ # abstract class
6
+ # child must implement 'build_strategy_params()'
7
+
8
+ attr_accessor :field_name, :filter_name
9
+
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
29
+ end
30
+
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,24 @@
1
+ module Elasticated
2
+ module Delimiters
3
+ class TermFieldDelimiter < StandardFieldDelimiter
4
+
5
+ attr_accessor :values
6
+
7
+ def initialize(opts={})
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
15
+ end
16
+
17
+ def build_strategy_params
18
+ return Hash.new if values.empty?
19
+ { filter_name => values.uniq }
20
+ end
21
+
22
+ end
23
+ end
24
+ end