elasticated 1.0.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 +7 -0
- data/.gitignore +35 -0
- data/Gemfile +4 -0
- data/README.md +3 -0
- data/Rakefile +6 -0
- data/elasticated.gemspec +29 -0
- data/lib/elasticated.rb +102 -0
- data/lib/elasticated/aggregation.rb +36 -0
- data/lib/elasticated/aggregations/cardinality_aggregation.rb +15 -0
- data/lib/elasticated/aggregations/count_aggregation.rb +15 -0
- data/lib/elasticated/aggregations/count_distinct_aggregation.rb +15 -0
- data/lib/elasticated/aggregations/count_filtered_aggregation.rb +29 -0
- data/lib/elasticated/aggregations/custom_aggregation.rb +25 -0
- data/lib/elasticated/aggregations/date_histogram_aggregation.rb +35 -0
- data/lib/elasticated/aggregations/filter_aggregation.rb +33 -0
- data/lib/elasticated/aggregations/filter_aggregation_evaluator.rb +22 -0
- data/lib/elasticated/aggregations/group_aggregation.rb +29 -0
- data/lib/elasticated/aggregations/histogram_aggregation.rb +34 -0
- data/lib/elasticated/aggregations/nested_aggregation.rb +30 -0
- data/lib/elasticated/aggregations/range_aggregation.rb +35 -0
- data/lib/elasticated/aggregations/range_aggregation_evaluator.rb +22 -0
- data/lib/elasticated/aggregations/ranges_builder.rb +35 -0
- data/lib/elasticated/aggregations/single_value_aggregation.rb +47 -0
- data/lib/elasticated/aggregations/subaggregated.rb +27 -0
- data/lib/elasticated/aggregations/sum_distinct_aggregation.rb +20 -0
- data/lib/elasticated/aggregations/terms_aggregation.rb +63 -0
- data/lib/elasticated/aggregations/top_hits_aggregation.rb +25 -0
- data/lib/elasticated/block_evaluation.rb +15 -0
- data/lib/elasticated/boolean_clause.rb +43 -0
- data/lib/elasticated/client.rb +84 -0
- data/lib/elasticated/clonable.rb +58 -0
- data/lib/elasticated/conditions/custom_condition.rb +19 -0
- data/lib/elasticated/conditions/exists_condition.rb +11 -0
- data/lib/elasticated/conditions/missing_condition.rb +11 -0
- data/lib/elasticated/conditions/nested_condition.rb +19 -0
- data/lib/elasticated/conditions/range_condition.rb +27 -0
- data/lib/elasticated/conditions/script_condition.rb +22 -0
- data/lib/elasticated/conditions/standard_condition.rb +26 -0
- data/lib/elasticated/conditions/terms_condition.rb +22 -0
- data/lib/elasticated/conditions/wildcard_condition.rb +18 -0
- data/lib/elasticated/conditions_builder.rb +75 -0
- data/lib/elasticated/configurable.rb +9 -0
- data/lib/elasticated/configuration.rb +9 -0
- data/lib/elasticated/default_logger.rb +27 -0
- data/lib/elasticated/delimiters/date_field_delimiter.rb +33 -0
- data/lib/elasticated/delimiters/standard_field_delimiter.rb +33 -0
- data/lib/elasticated/delimiters/term_field_delimiter.rb +24 -0
- data/lib/elasticated/document.rb +46 -0
- data/lib/elasticated/helpers.rb +28 -0
- data/lib/elasticated/index_selector.rb +44 -0
- data/lib/elasticated/inspectionable.rb +9 -0
- data/lib/elasticated/mapping.rb +19 -0
- data/lib/elasticated/mapping/builder.rb +36 -0
- data/lib/elasticated/mapping/fields_builder.rb +148 -0
- data/lib/elasticated/mapping/nested_builder.rb +15 -0
- data/lib/elasticated/mapping/object_builder.rb +15 -0
- data/lib/elasticated/mapping/partial.rb +11 -0
- data/lib/elasticated/mapping/type_builder.rb +14 -0
- data/lib/elasticated/partitioned_repository.rb +27 -0
- data/lib/elasticated/query.rb +159 -0
- data/lib/elasticated/query_aggregations.rb +71 -0
- data/lib/elasticated/query_conditions.rb +89 -0
- data/lib/elasticated/repositories/monthly_partitioned_repository.rb +96 -0
- data/lib/elasticated/repository.rb +139 -0
- data/lib/elasticated/results.rb +43 -0
- data/lib/version.rb +92 -0
- data/spec/aggregation_spec.rb +587 -0
- data/spec/date_field_delimiter_spec.rb +67 -0
- data/spec/document_spec.rb +44 -0
- data/spec/elasticsearch_hit_1.json +14 -0
- data/spec/elasticsearch_response_1.json +29 -0
- data/spec/elasticsearch_response_2.json +44 -0
- data/spec/elasticsearch_top_hits_response.json +20 -0
- data/spec/integration_spec.rb +184 -0
- data/spec/mapping_spec.rb +219 -0
- data/spec/monthly_partitioned_repository_spec.rb +99 -0
- data/spec/query_aggregations_spec.rb +44 -0
- data/spec/query_conditions_spec.rb +314 -0
- data/spec/query_spec.rb +265 -0
- data/spec/results_spec.rb +69 -0
- data/spec/spec_helper.rb +2 -0
- data/spec/term_field_delimiter_spec.rb +39 -0
- metadata +225 -0
@@ -0,0 +1,71 @@
|
|
1
|
+
module Elasticated
|
2
|
+
class QueryAggregations
|
3
|
+
|
4
|
+
include Clonable
|
5
|
+
include BlockEvaluation
|
6
|
+
|
7
|
+
attr_accessor :_aggregations
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
self._aggregations = Array.new
|
11
|
+
end
|
12
|
+
|
13
|
+
def build
|
14
|
+
_aggregations.inject({}) do |ret, aggregation|
|
15
|
+
ret.merge aggregation.name => aggregation.build
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def parse(response)
|
20
|
+
_aggregations.inject({}) do |hash, aggregation|
|
21
|
+
name = aggregation.name.to_s
|
22
|
+
original_name = aggregation.original_name.to_s
|
23
|
+
hash.merge original_name => aggregation.parse(response[name])
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def merge! other_query_aggs
|
28
|
+
other_query_aggs._aggregations.each do |other_aggregation|
|
29
|
+
add_aggregation other_aggregation
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def empty?
|
34
|
+
_aggregations.empty?
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def get_aggregation_class(agg_name)
|
40
|
+
camel_case_name = Helpers.string_to_camel_case agg_name.to_s
|
41
|
+
self.class.const_get("::Elasticated::#{camel_case_name}Aggregation") rescue nil
|
42
|
+
end
|
43
|
+
|
44
|
+
def method_missing(method_name, *args, &block)
|
45
|
+
agg_class = get_aggregation_class method_name
|
46
|
+
if agg_class
|
47
|
+
aggregation = agg_class.new(*args, &block)
|
48
|
+
add_aggregation aggregation
|
49
|
+
else
|
50
|
+
super
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def respond_to_missing?(name, include_private=false)
|
55
|
+
get_aggregation_class(name) || super
|
56
|
+
end
|
57
|
+
|
58
|
+
def add_aggregation(aggregation)
|
59
|
+
equivalent_agg = _aggregations.select do |previous_agg|
|
60
|
+
previous_agg == aggregation
|
61
|
+
end.first
|
62
|
+
if !equivalent_agg
|
63
|
+
_aggregations << aggregation
|
64
|
+
aggregation
|
65
|
+
else
|
66
|
+
equivalent_agg._subaggregations.merge! aggregation._subaggregations if aggregation.is_a? Subaggregated
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
module Elasticated
|
2
|
+
class QueryConditions
|
3
|
+
|
4
|
+
include Clonable
|
5
|
+
|
6
|
+
attr_accessor :_must, :_must_not, :_should, :_minimum_should_match, :_cache
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
self._must = BooleanClause.new
|
10
|
+
self._must_not = BooleanClause.new
|
11
|
+
self._should = BooleanClause.new
|
12
|
+
end
|
13
|
+
|
14
|
+
# delimiters
|
15
|
+
|
16
|
+
def fill_delimiter(field_delimiter)
|
17
|
+
_must.fill_delimiter field_delimiter
|
18
|
+
end
|
19
|
+
|
20
|
+
# conditions
|
21
|
+
|
22
|
+
def add(condition)
|
23
|
+
_must.add condition
|
24
|
+
end
|
25
|
+
|
26
|
+
include ConditionsBuilder
|
27
|
+
|
28
|
+
def must(&block)
|
29
|
+
_must.evaluate block
|
30
|
+
end
|
31
|
+
|
32
|
+
def must_not(&block)
|
33
|
+
_must_not.evaluate block
|
34
|
+
end
|
35
|
+
|
36
|
+
def should(&block)
|
37
|
+
_should.evaluate block
|
38
|
+
end
|
39
|
+
|
40
|
+
# 'must_not' conditions
|
41
|
+
|
42
|
+
def not_equal(*args)
|
43
|
+
_must_not.equal *args
|
44
|
+
end
|
45
|
+
|
46
|
+
def without(*args)
|
47
|
+
_must_not.with *args
|
48
|
+
end
|
49
|
+
|
50
|
+
def not_between(*args)
|
51
|
+
_must_not.between *args
|
52
|
+
end
|
53
|
+
|
54
|
+
# cache
|
55
|
+
|
56
|
+
def cache(value=true)
|
57
|
+
self._cache = value
|
58
|
+
end
|
59
|
+
|
60
|
+
# other methods
|
61
|
+
|
62
|
+
def minimum_should_match(value)
|
63
|
+
self._minimum_should_match = value
|
64
|
+
end
|
65
|
+
|
66
|
+
def build
|
67
|
+
if empty?
|
68
|
+
{ match_all: {} }
|
69
|
+
elsif _must_not.empty? && _should.empty? && _must.count == 1
|
70
|
+
_must.build_first
|
71
|
+
else
|
72
|
+
bool = {}
|
73
|
+
bool.merge! must: _must.build unless _must.empty?
|
74
|
+
bool.merge! must_not: _must_not.build unless _must_not.empty?
|
75
|
+
if !_should.empty?
|
76
|
+
bool.merge! should: _should.build
|
77
|
+
bool.merge! minimum_should_match: _minimum_should_match if _minimum_should_match
|
78
|
+
end
|
79
|
+
bool.merge! _cache: _cache if _cache
|
80
|
+
{ bool: bool }
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def empty?
|
85
|
+
_must.empty? && _must_not.empty? && _should.empty?
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
module Elasticated
|
2
|
+
class MonthlyPartitionedRepository < Repository
|
3
|
+
include Configurable
|
4
|
+
|
5
|
+
attr_accessor :_index_name, :_index_alias, :_general_alias
|
6
|
+
attr_accessor :date_field
|
7
|
+
attr_accessor :dynamic_creation, :index_options
|
8
|
+
|
9
|
+
def initialize(opts={})
|
10
|
+
super opts
|
11
|
+
self._index_name = opts[:index_name] || raise('An index prefix should be specified')
|
12
|
+
self._index_alias = opts[:index_alias] || raise('An index alias prefix should be specified')
|
13
|
+
self._general_alias = opts[:general_alias] || _index_alias
|
14
|
+
self.date_field = opts[:date_field] || :date
|
15
|
+
self.index_options = opts[:index_options] # hash with mapping, shards info, etc or nil
|
16
|
+
self.dynamic_creation = opts[:dynamic_creation] || false
|
17
|
+
end
|
18
|
+
|
19
|
+
def execute(action, query, opts={})
|
20
|
+
index_alias = index_alias_for query
|
21
|
+
super action, query, opts.merge(index: index_alias)
|
22
|
+
# rescue Elasticsearch::Transport::Transport::Errors::NotFound => e
|
23
|
+
# action == :count ? 0 : nil
|
24
|
+
end
|
25
|
+
|
26
|
+
def prepare(action, document, opts={})
|
27
|
+
date = date_from document
|
28
|
+
raise("The document has not a valid '#{date_field}' field") unless date
|
29
|
+
check_or_create_index! date
|
30
|
+
super action, document, opts.merge(index: index_alias_for(date))
|
31
|
+
end
|
32
|
+
|
33
|
+
def date_from(document)
|
34
|
+
str = document.source[date_field.to_s]
|
35
|
+
str && Date.parse(str)
|
36
|
+
end
|
37
|
+
|
38
|
+
def check_or_create_index! date
|
39
|
+
index_alias = index_alias_for date
|
40
|
+
return if client.index_exists? index_alias
|
41
|
+
raise("Index '#{index_alias}' not found (dynamic per-month index creation is disabled)") unless dynamic_creation
|
42
|
+
index_name = index_name_for date
|
43
|
+
create_index index_name
|
44
|
+
create_alias index_name, index_alias
|
45
|
+
end
|
46
|
+
|
47
|
+
def create_index! date
|
48
|
+
create_index index_name_for date
|
49
|
+
end
|
50
|
+
|
51
|
+
def create_alias! date
|
52
|
+
index_name = index_name_for date
|
53
|
+
index_alias = index_alias_for date
|
54
|
+
create_alias index_name, index_alias
|
55
|
+
end
|
56
|
+
|
57
|
+
def index_name_for(object)
|
58
|
+
object.is_a?(Query) ? index_alias_for_query(object) : index_name_for_date(object)
|
59
|
+
end
|
60
|
+
|
61
|
+
def index_alias_for(object)
|
62
|
+
object.is_a?(Query) ? index_alias_for_query(object) : index_alias_for_date(object)
|
63
|
+
end
|
64
|
+
|
65
|
+
protected
|
66
|
+
|
67
|
+
def create_index(index_name)
|
68
|
+
client.create_index index_name, index_options
|
69
|
+
log.info "Index #{index_name} created"
|
70
|
+
end
|
71
|
+
|
72
|
+
def create_alias(index_name, index_alias)
|
73
|
+
client.create_alias index_name, index_alias
|
74
|
+
client.create_alias index_name, _general_alias
|
75
|
+
log.info "Alias #{index_alias} created over index #{index_name}"
|
76
|
+
end
|
77
|
+
|
78
|
+
def index_alias_for_query(query)
|
79
|
+
_general_alias # TODO
|
80
|
+
end
|
81
|
+
|
82
|
+
def index_alias_for_date(date)
|
83
|
+
generate_name _index_alias, date
|
84
|
+
end
|
85
|
+
|
86
|
+
def index_name_for_date(date)
|
87
|
+
generate_name _index_name, date
|
88
|
+
end
|
89
|
+
|
90
|
+
def generate_name(prefix, date)
|
91
|
+
str = date.strftime '%Y-%m'
|
92
|
+
"#{prefix}-#{str}" # prefix-YYYY-MM
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,139 @@
|
|
1
|
+
module Elasticated
|
2
|
+
class Repository
|
3
|
+
|
4
|
+
# child can implement 'execute(action, query, opts)'
|
5
|
+
# child can implement 'prepare(action, document, opts)'
|
6
|
+
|
7
|
+
attr_accessor :client
|
8
|
+
|
9
|
+
def initialize(opts={})
|
10
|
+
self.client = Client.new opts
|
11
|
+
end
|
12
|
+
|
13
|
+
def execute_search(query, opts={})
|
14
|
+
execute :search, query, opts
|
15
|
+
end
|
16
|
+
|
17
|
+
def execute_aggregations(query, opts={})
|
18
|
+
execute :aggregations, query, opts
|
19
|
+
end
|
20
|
+
|
21
|
+
def execute_count(query, opts={})
|
22
|
+
execute :count, query, opts
|
23
|
+
end
|
24
|
+
|
25
|
+
def execute_aggregated_search(query, opts={})
|
26
|
+
execute :aggregated_search, query, opts
|
27
|
+
end
|
28
|
+
|
29
|
+
def delete_by(query, opts={})
|
30
|
+
execute :delete, query, opts
|
31
|
+
end
|
32
|
+
|
33
|
+
def exists?(query, opts={})
|
34
|
+
execute_count(query, opts) > 0
|
35
|
+
end
|
36
|
+
|
37
|
+
def index_document(document, opts={})
|
38
|
+
prepare :index, document, opts
|
39
|
+
end
|
40
|
+
|
41
|
+
def update_document(document, opts={})
|
42
|
+
prepare :update, document, opts
|
43
|
+
end
|
44
|
+
|
45
|
+
protected
|
46
|
+
|
47
|
+
# write actions
|
48
|
+
|
49
|
+
def _exec_index(document, opts={})
|
50
|
+
_exec_upsert :index, document, opts
|
51
|
+
end
|
52
|
+
|
53
|
+
def _exec_update(document, opts={})
|
54
|
+
_exec_upsert :update, document, opts
|
55
|
+
end
|
56
|
+
|
57
|
+
def _exec_upsert(method, document, opts={})
|
58
|
+
opts.merge! id: document.id if document.id
|
59
|
+
opts.merge! type: document.type unless opts[:type]
|
60
|
+
opts.merge! index: document.index unless opts[:index]
|
61
|
+
document.index = opts[:index]
|
62
|
+
document.type = opts[:type]
|
63
|
+
client.send "#{method}_document", document.source, opts
|
64
|
+
end
|
65
|
+
|
66
|
+
# read actions
|
67
|
+
|
68
|
+
def _exec_aggregations(query, opts={})
|
69
|
+
body = query.build_for_aggregations
|
70
|
+
response = client.search body, opts
|
71
|
+
query.parse_aggregations response['aggregations']
|
72
|
+
end
|
73
|
+
|
74
|
+
def _exec_count(query, opts={})
|
75
|
+
body = query.build_for_count
|
76
|
+
response = client.count body, opts
|
77
|
+
response['count']
|
78
|
+
end
|
79
|
+
|
80
|
+
def _exec_search(query, opts={})
|
81
|
+
_exec_paginated_search query, false, opts
|
82
|
+
end
|
83
|
+
|
84
|
+
def _exec_aggregated_search(query, opts={})
|
85
|
+
_exec_paginated_search query, true, opts
|
86
|
+
end
|
87
|
+
|
88
|
+
def _exec_delete(query, opts={})
|
89
|
+
client.delete query, opts
|
90
|
+
end
|
91
|
+
|
92
|
+
def _exec_paginated_search(query, aggregated, opts={})
|
93
|
+
scroll_interval = '3m'
|
94
|
+
body = aggregated ? query.build_for_aggregated_search : query.build_for_search
|
95
|
+
if query.limited?
|
96
|
+
response = client.search body, opts
|
97
|
+
Results.from_elasticsearch_response response, query
|
98
|
+
elsif query.sorted? || query.aggregated?
|
99
|
+
# normal pagination
|
100
|
+
page_size = 50
|
101
|
+
current_page = 1
|
102
|
+
loop do
|
103
|
+
offset = page_size * (current_page - 1)
|
104
|
+
response = client.search body, opts.merge(size: page_size, from: offset)
|
105
|
+
if current_page == 1
|
106
|
+
results = Results.from_elasticsearch_response response, query
|
107
|
+
else
|
108
|
+
results.append_results_from response
|
109
|
+
end
|
110
|
+
total_pages = (response['hits']['total'] / page_size.to_f).ceil
|
111
|
+
break if current_page >= total_pages
|
112
|
+
current_page += 1
|
113
|
+
body = query.build_for_search if aggregated
|
114
|
+
end
|
115
|
+
results
|
116
|
+
else
|
117
|
+
# scan & scroll
|
118
|
+
response = client.search body, opts.merge(search_type: 'scan', scroll: scroll_interval, size: 1000)
|
119
|
+
while response = client.scroll(response['_scroll_id'], scroll: scroll_interval) and not response['hits']['hits'].empty? do
|
120
|
+
results = results ? results.append_results_from(response) : Results.from_elasticsearch_response(response, query)
|
121
|
+
end
|
122
|
+
results ? results : Results.from_elasticsearch_response(response, query)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
# abstract methods
|
127
|
+
|
128
|
+
def execute(action, query, opts={})
|
129
|
+
# child's implementation here
|
130
|
+
send "_exec_#{action}", query, opts
|
131
|
+
end
|
132
|
+
|
133
|
+
def prepare(action, document, opts={})
|
134
|
+
# child's implementation here
|
135
|
+
send "_exec_#{action}", document, opts
|
136
|
+
end
|
137
|
+
|
138
|
+
end
|
139
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Elasticated
|
2
|
+
|
3
|
+
ShardsInfo = Struct.new :total, :successful, :failed
|
4
|
+
HitsInfo = Struct.new :total, :max_score
|
5
|
+
|
6
|
+
class Results < Array
|
7
|
+
|
8
|
+
def self.from_elasticsearch_response(elasticsearch_response, query=nil)
|
9
|
+
documents = elasticsearch_response['hits']['hits'].map{ |hit| Document.from_elasticsearch_hit hit }
|
10
|
+
results = new documents
|
11
|
+
results.documents = documents
|
12
|
+
# cluster metadata
|
13
|
+
results.took = elasticsearch_response['took']
|
14
|
+
results.timed_out = elasticsearch_response['timed_out']
|
15
|
+
# shards metadata
|
16
|
+
shards = elasticsearch_response['_shards']
|
17
|
+
results.shards = ShardsInfo.new shards['total'], shards['successful'], shards['failed']
|
18
|
+
# search metadata
|
19
|
+
hits = elasticsearch_response['hits']
|
20
|
+
results.hits = HitsInfo.new hits['total'], hits['max_score']
|
21
|
+
# aggregations results
|
22
|
+
aggregations = elasticsearch_response['aggregations']
|
23
|
+
results.aggregations = query.parse_aggregations aggregations if query && aggregations
|
24
|
+
results
|
25
|
+
end
|
26
|
+
|
27
|
+
attr_accessor :took, :timed_out
|
28
|
+
attr_accessor :shards # methods: total, successful, failed
|
29
|
+
attr_accessor :hits # methods: total, max_score
|
30
|
+
attr_accessor :documents, :aggregations
|
31
|
+
|
32
|
+
def append_results_from(elasticsearch_response)
|
33
|
+
elasticsearch_response['hits']['hits'].each do |hit|
|
34
|
+
documents.push Document.from_elasticsearch_hit hit
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def sources
|
39
|
+
documents.map &:source
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
data/lib/version.rb
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
module Elasticated
|
2
|
+
VERSION = '1.0.0'
|
3
|
+
end
|
4
|
+
|
5
|
+
# Changelog
|
6
|
+
|
7
|
+
# 1.0.0
|
8
|
+
# Cambios en Repository
|
9
|
+
# Se elimina InsightsRepository y sus hijos
|
10
|
+
# Cambios en MonthlyPartitionedRepository
|
11
|
+
# Ahora las queries pueden devolver resultados y aggregations en un solo pedido
|
12
|
+
# Se agrega la clase Document
|
13
|
+
# Se agrega la clase Results
|
14
|
+
# Se eliminan SocialContentRepository y ConversationsRepository
|
15
|
+
# El Terms Filter ahora acepta parametros opcionales (execution y cache)
|
16
|
+
# El Nested Filter ahora acepta el parametro opcional cache
|
17
|
+
# Ahora se puede setear el parametro cache para el Bool Filter
|
18
|
+
# El Range Filter ahora acepta parametros opcionales (execution y cache)
|
19
|
+
# Ahora se admite post_filter en la query
|
20
|
+
# Ahora se admiten bools anidados
|
21
|
+
|
22
|
+
# 0.8.2
|
23
|
+
# Ahora se puede ordenar por multiples criterios en una TermsAggregation
|
24
|
+
|
25
|
+
# 0.8.1
|
26
|
+
# Se agrego la posibilidad de recibir post_zone y time_zone al DateHistogramAggregation
|
27
|
+
|
28
|
+
# 0.8.0
|
29
|
+
# Se agrego un repositorio de conversaciones
|
30
|
+
|
31
|
+
# 0.7.2
|
32
|
+
# Se agregan las metricas ads_actions y ads_post_engagement a FacebookInsightsRepository
|
33
|
+
|
34
|
+
# 0.7.1
|
35
|
+
# Se agrega el campo sub_type al mapping de post de FacebookInsightsRepository
|
36
|
+
|
37
|
+
# 0.7.0
|
38
|
+
# Agregado YoutubeInsightsRepository
|
39
|
+
# Agregado InstagramInsightsRepository
|
40
|
+
# Agregada opcion para configurar todos los repositorios al mismo tiempo
|
41
|
+
# Agregadas las condiciones greater_than, greater_equal, less_than y lower_or_equals
|
42
|
+
# Agregada RangeAggregation
|
43
|
+
|
44
|
+
# 0.6.0
|
45
|
+
# Agregado el campo business_ads al mapping de FacebookInsightsRepository
|
46
|
+
# Agregados los campos de la marketing api a los tipos de FacebookInsightsRepository
|
47
|
+
# Agregadas las metricas 'embedded_media_views' y 'video_views' a TwitterInsightsRepository
|
48
|
+
|
49
|
+
# 0.5.2
|
50
|
+
# Ahora se puede "no compactar" los resultados de una AggregatedQuery
|
51
|
+
# Fix critico al metodo '==' de FilterAggregation
|
52
|
+
# Agregadas las metricas del tipo 'video_retention' a FacebookInsightsRepository
|
53
|
+
# Agregada la opcion :offset a DateHistogramAggregation
|
54
|
+
|
55
|
+
# 0.5.1
|
56
|
+
# Fix critico a FacebookInsightsRepository#update
|
57
|
+
# Actualizada la dependencia keepcon_utils a la version 0.3
|
58
|
+
|
59
|
+
# 0.5.0
|
60
|
+
# Agregadas metricas faltantes de video al mapping de FacebookInsightsRepository
|
61
|
+
# Fix critico al metodo '==' de QueryConditions
|
62
|
+
# Agregado MappingBuilder
|
63
|
+
# Agregada la clase Client, wrapper de Elasticsearch::Client
|
64
|
+
# Se elimina la dependencia de Repository hacia Elasticsearch::Client, ahora pasa por Client
|
65
|
+
# Ahora el TermsAggregation se construye con size 0 por default
|
66
|
+
# Se elimina AbstractQuery#over_repository
|
67
|
+
# La opcion 'include_id' de repository.execute_query pasa a llamarse 'metadata'
|
68
|
+
|
69
|
+
# 0.4.1
|
70
|
+
# Ahora los valores numericos de InsightsRepository son del tipo long
|
71
|
+
|
72
|
+
# 0.4.0
|
73
|
+
# Agregado metodo update_document en InsightsRepository
|
74
|
+
# Agregadas las key tipo 'calc' ademas de las preexistentes 'gen' a InsightsRepository
|
75
|
+
# Contemplados los pares key-value de tercer nivel en InsightsRepository#prepare,restore
|
76
|
+
# Ahora repository.execute_query acepta la opcion 'include_id'
|
77
|
+
|
78
|
+
# 0.3.0
|
79
|
+
# Agregado metodo create_test_index en SocialContentRepository
|
80
|
+
|
81
|
+
# 0.2.0
|
82
|
+
# Se agrega NestedAggregation
|
83
|
+
# Ahora las aggregations que adminen subaggregations se "auto-mergean"
|
84
|
+
# Agregado el filtro 'nested'
|
85
|
+
# Agregado 'min' aggregation
|
86
|
+
# Agregado 'page_fans_country' al mapping de fb insights
|
87
|
+
# Agregado 'page_fans_gender_age' al mapping de fb insights
|
88
|
+
# Los metodos 'create_index_for' y 'put_alias_for' de 'facebook_insights_repository' ahora son publicos
|
89
|
+
# Se agrega HistogramAggregation
|
90
|
+
# Se agrega MonthlyPartitionedRepository
|
91
|
+
# Se agrega InsightsRepository
|
92
|
+
# Se agrega InsightsMappingGenerator
|