elasticband 0.1.2 → 0.1.3
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 +13 -5
- data/.travis.yml +16 -6
- data/lib/elasticband.rb +3 -2
- data/lib/elasticband/aggregation.rb +55 -12
- data/lib/elasticband/aggregation/field_based.rb +27 -0
- data/lib/elasticband/aggregation/max.rb +9 -0
- data/lib/elasticband/aggregation/nested.rb +10 -4
- data/lib/elasticband/aggregation/terms.rb +3 -17
- data/lib/elasticband/aggregation/top_hits.rb +3 -6
- data/lib/elasticband/query.rb +2 -1
- data/lib/elasticband/version.rb +1 -1
- data/spec/aggregation/field_based_spec.rb +35 -0
- data/spec/aggregation/max_spec.rb +9 -0
- data/spec/aggregation/nested_spec.rb +39 -14
- data/spec/aggregation/terms_spec.rb +3 -11
- data/spec/aggregation/top_hits_spec.rb +7 -16
- data/spec/aggregation_spec.rb +55 -5
- data/spec/query_spec.rb +29 -9
- metadata +24 -20
checksums.yaml
CHANGED
@@ -1,7 +1,15 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
MWNjYjdlNWNlYzIwZWRhMzg5M2YwOGNkNGI3MzE5ZjAwZjkxYjM1NA==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
M2ViMmE2ZDNiY2VkOTg4ZGE2ODgyNTA0MjY1OGNkOGRjMDI3ZDUwMA==
|
5
7
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
YzI3NDFiOGQ3ZTUxNDI1ZTY4ZjdmZDNkOTJiOGI1NmM0NTlmODFjYTk2NGM2
|
10
|
+
NTRkNTA3N2VjYTNlNTE1NjIzYTNiM2Q4ZDhhMGMyMWIwMGI0ODUwM2NiMzY5
|
11
|
+
MWI3NDBmY2YwMWNkZWE5NmExNzFhOTBlNjlkOTdiM2I4OTQ3MDA=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
NDkyYjZkNzVlMTEwOTcwNzgxZTAxYTM1MDQzMzY2ZjZjYTcxMTI4YzgxZTJi
|
14
|
+
ODM2NzhiMjg3OTZhN2RhNjE0OGU0MGRmN2VlYzM5YTcwNGU1ZTA3OTBkYTVk
|
15
|
+
ZmI2ZWY1MTVlN2IyZWRiNzk3ZjY4ZTRjN2FiZmMwNzQzZmRiN2E=
|
data/.travis.yml
CHANGED
@@ -1,13 +1,23 @@
|
|
1
1
|
language: ruby
|
2
2
|
cache: bundler
|
3
3
|
rvm:
|
4
|
-
|
5
|
-
|
4
|
+
- 2.2
|
5
|
+
- ruby-head
|
6
6
|
git:
|
7
7
|
depth: 1
|
8
8
|
script:
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
- bundle exec rspec
|
10
|
+
- bundle exec rubocop
|
11
|
+
add_ons:
|
12
12
|
code_climate:
|
13
|
-
repo_token:
|
13
|
+
repo_token:
|
14
|
+
secure: J7KZY6qcRup/D/m1v4dau0UZ4S1UQ5aW+PYago1jMvTZ/KqyPP36rAiRZhzCROjVaodbkwxhGfp+V9eLPGZG+CF3yFAZWCa+YaOR4ihbx7PI+o1KB5Rvo/LfoXTZ2ietGLSHf43ae617pp5uu6IF7scl5NQqaXraE/zQYce4wOWAYTQvxi+lnYHYbPWtAtsBoCNTyFdscHT5LPSGIINaGsPVwVp5WSoOe770vNLqnoPD/FAlB71scCfO5oOrPu1jeQf7kHXNuJGFeVCauSrC23oAcYs15RO8F5LZIH5ikR7wBpaK3TEv98GR27xZaMiP07IGiaXXG0AOWM1wxk4kUuy7jE7Rgd/Q5DU9HlO7pf1RWKRKeJTBocez2SmtGVQjQ1cIqhzmZI/QXipkYuSKUB4HZsKhQMCIZqW5dR9OomviJbrOHSQRNcGhtKWSzgxHAlhC8Fel57jgU/CTZyFoiaFL/qFvddo98CJriPsKGbQFtsXdOE2r5GyS0VOZW8XKpyhvH9E1RKaxnsopfL2Gh/BOZAh7ZI1XWTS7QJQMYHPLsxkf1gQa29T1GV+lo53fuv55HDrJHZ3dphAAngjCQRs6hNdB/m2KgqognwNXrnVRrpSlMq4yvyRHSmfiatXl10bw7iFzQ+h227PP+CzXtRwJlHj5FpUc/voNE0oOaeA=
|
15
|
+
deploy:
|
16
|
+
provider: rubygems
|
17
|
+
api_key:
|
18
|
+
secure: GuPR9kqmSoQKhgh/SBpa2+zysNHv3n92hsuA7MyZ0ezgdN41qdZqYJb/w5hZLBuGyDJO8f+Ib1deKw8+3gQO6rsiFwlVW6nrPEcxCRjg/QQSxNk2FuPxh2FF7/n9Ce3ePeVhnmkCAw7++B7OLUo5Un8cR35WHPzChrprQ1RLpbSB6Qg8nwcW92aju6WqUkHrdYEyP/Q94oqzA09gamth8flCPYw8XKeklR8aQ6KkdD4w96Bu3AwBOYbUkIlNNXXj1CCvWwcJf5DQ+DR6JMk0KkaniLxrsSmiTBkVlUIJfEIJMUUuPiAUZ0tvwFtc5Puys987YwpNmqq4eqB3Hxp85FLDEEgxECtlBz5Ab8/rgUuJxlHI6kLPgOw6sseTmTYLG4NJkGj/icjP7LaQYSIry+LVnncM48YIC9nzuBNsF6XfFXfLAAq+u51FFJVF0SihqWYKFSk96d+UHuOtitVQ6Smte4ir+7ifclMgtxgYqBzX50Pv39uysvSpmFYpVkGXiGnVjHAffWhNOVJDJdF2K0BllJP2PyNF4fDrheFNS6lQj394aewCGkvLzyHIht903KC8+IvD4u4KQktA7q/ctn6dODfjXUn6eIaS5lXYeLNI7OHUR8fsMDJyiNEleBHKVs9KAVqjKJFsaH/ZY90VuAQ/3U/J3a3PsCHUZ2iDuTU=
|
19
|
+
gem: elasticband
|
20
|
+
on:
|
21
|
+
tags: true
|
22
|
+
repo: LoveMondays/elasticband
|
23
|
+
branch: master
|
data/lib/elasticband.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
|
-
require 'active_support'
|
2
|
-
require 'active_support/core_ext/object'
|
3
1
|
require 'active_support/core_ext/array'
|
2
|
+
require 'active_support/core_ext/hash'
|
3
|
+
require 'active_support/core_ext/object'
|
4
|
+
require 'active_support/json'
|
4
5
|
|
5
6
|
require 'elasticband/aggregation'
|
6
7
|
require 'elasticband/filter'
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'elasticband/aggregation/field_based'
|
2
|
+
require 'elasticband/aggregation/max'
|
1
3
|
require 'elasticband/aggregation/nested'
|
2
4
|
require 'elasticband/aggregation/terms'
|
3
5
|
require 'elasticband/aggregation/top_hits'
|
@@ -7,7 +9,7 @@ module Elasticband
|
|
7
9
|
attr_accessor :name
|
8
10
|
|
9
11
|
def initialize(name)
|
10
|
-
self.name = name.to_sym
|
12
|
+
self.name = name.to_s.gsub(/\W/, '_').to_sym
|
11
13
|
end
|
12
14
|
|
13
15
|
def to_h(aggregation_hash = {})
|
@@ -15,40 +17,81 @@ module Elasticband
|
|
15
17
|
end
|
16
18
|
|
17
19
|
class << self
|
18
|
-
|
20
|
+
PARSE_AGGREGATIONS = %i(group_by group_max top_hits)
|
21
|
+
|
22
|
+
# Parses some options to a Elasticsearch syntax, aggregations can be nested in another.
|
19
23
|
#
|
20
24
|
# #### Options
|
21
25
|
#
|
22
26
|
# * `group_by:` Count results by the value of an attribute using `terms` filter.
|
23
27
|
# It can receive an array with some attributes:
|
24
|
-
# * `top_hits:` A number of results that should be return inside the group ranked by score.
|
25
28
|
# * `size:` Size of the results calculated in each shard (https://www.elastic.co/guide/en/elasticsearch/reference/1.x/search-aggregations-bucket-terms-aggregation.html#_size)
|
29
|
+
# * `script:` Generates terms defined by the script
|
30
|
+
# * `group_max:` Group results by maximum value of a field
|
31
|
+
# It can receive an array with some attributes:
|
32
|
+
# * `script:` Generates max defined by the script
|
33
|
+
# * `top_hits:` A number of results that should be return inside the group ranked by score.
|
26
34
|
#
|
27
35
|
# #### Examples
|
28
36
|
# ```
|
29
37
|
# Aggregation.parse(group_by: :status)
|
30
38
|
# => { status: { terms: { field: :status } } }
|
31
39
|
#
|
40
|
+
# Aggregation.parse(group_max: :contents_count)
|
41
|
+
# => { status: { max: { field: :contents_count } } }
|
42
|
+
#
|
32
43
|
# Aggregation.parse(group_by: [:status, size: 5, top_hits: 3])
|
33
44
|
# => { status: { terms: { field: :status, size: 5 }, aggs: { top_status: { top_hits: 3 } } } }
|
34
45
|
def parse(options)
|
35
|
-
|
46
|
+
merge(*parse_aggregations(options))
|
47
|
+
end
|
48
|
+
|
49
|
+
def merge(*aggregations)
|
50
|
+
aggregations.each_with_object({}) { |a, h| h.merge!(a.to_h) }
|
36
51
|
end
|
37
52
|
|
38
53
|
private
|
39
54
|
|
40
|
-
def
|
41
|
-
|
55
|
+
def parse_aggregations(options, root_aggregation = nil)
|
56
|
+
parse_options = options.slice(*PARSE_AGGREGATIONS)
|
57
|
+
return root_aggregation if parse_options.blank?
|
42
58
|
|
43
|
-
|
44
|
-
|
59
|
+
aggregations = parse_options.map do |aggregation_name, aggregation_options|
|
60
|
+
parse_singular_aggregation(root_aggregation, aggregation_name, aggregation_options)
|
61
|
+
end
|
62
|
+
|
63
|
+
aggregations = Aggregation::Nested.new(root_aggregation, aggregations) if root_aggregation
|
64
|
+
aggregations
|
65
|
+
end
|
45
66
|
|
46
|
-
|
47
|
-
|
48
|
-
|
67
|
+
def parse_singular_aggregation(root_aggregation, aggregation_name, aggregation_options)
|
68
|
+
case aggregation_name
|
69
|
+
when :group_by then parse_field_aggregation(Aggregation::Terms, :by, aggregation_options)
|
70
|
+
when :group_max then parse_field_aggregation(Aggregation::Max, :max, aggregation_options)
|
71
|
+
when :top_hits then parse_top_hits(root_aggregation, aggregation_options)
|
49
72
|
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def parse_field_aggregation(aggregation_class, prefix, options_aggregation)
|
76
|
+
return {} if options_aggregation.blank?
|
77
|
+
|
78
|
+
field, options = options_aggregation
|
79
|
+
options ||= {}
|
80
|
+
|
81
|
+
name = :"#{prefix}_#{field}"
|
82
|
+
aggregation = aggregation_class.new(name, field, options.except(*PARSE_AGGREGATIONS))
|
83
|
+
parse_aggregations(options, aggregation)
|
84
|
+
end
|
85
|
+
|
86
|
+
def parse_top_hits(root_aggregation, options_top_hits)
|
87
|
+
return {} if options_top_hits.blank?
|
88
|
+
|
89
|
+
size, options = options_top_hits
|
90
|
+
options ||= {}
|
50
91
|
|
51
|
-
|
92
|
+
name = :"top_#{root_aggregation.name}"
|
93
|
+
aggregation = Aggregation::TopHits.new(name, size, options.except(*PARSE_AGGREGATIONS))
|
94
|
+
parse_aggregations(options, aggregation)
|
52
95
|
end
|
53
96
|
end
|
54
97
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Elasticband
|
2
|
+
class Aggregation
|
3
|
+
class FieldBased < Aggregation
|
4
|
+
attr_accessor :field, :options
|
5
|
+
|
6
|
+
def initialize(name, field, options = {})
|
7
|
+
super(name)
|
8
|
+
self.field = field && field.to_sym
|
9
|
+
self.options = options
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_h
|
13
|
+
super(aggregation_hash)
|
14
|
+
end
|
15
|
+
|
16
|
+
def type
|
17
|
+
fail NotImplementedError
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def aggregation_hash
|
23
|
+
{ type => { field: field }.merge!(options).compact }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -1,18 +1,24 @@
|
|
1
1
|
module Elasticband
|
2
2
|
class Aggregation
|
3
3
|
class Nested < Aggregation
|
4
|
-
attr_accessor :root_aggregation, :
|
4
|
+
attr_accessor :root_aggregation, :nested_aggregations
|
5
5
|
|
6
|
-
def initialize(root_aggregation,
|
6
|
+
def initialize(root_aggregation, nested_aggregations)
|
7
7
|
self.root_aggregation = root_aggregation
|
8
|
-
self.
|
8
|
+
self.nested_aggregations = Array.wrap(nested_aggregations)
|
9
9
|
end
|
10
10
|
|
11
11
|
def to_h
|
12
12
|
root_aggregation.to_h.tap do |h|
|
13
|
-
h[root_aggregation.name].merge!(aggs:
|
13
|
+
h[root_aggregation.name].merge!(aggs: nested_hash)
|
14
14
|
end
|
15
15
|
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def nested_hash
|
20
|
+
self.class.merge(*nested_aggregations)
|
21
|
+
end
|
16
22
|
end
|
17
23
|
end
|
18
24
|
end
|
@@ -1,22 +1,8 @@
|
|
1
1
|
module Elasticband
|
2
2
|
class Aggregation
|
3
|
-
class Terms <
|
4
|
-
|
5
|
-
|
6
|
-
def initialize(name, field, options = {})
|
7
|
-
super(name)
|
8
|
-
self.field = field.to_sym
|
9
|
-
self.options = options
|
10
|
-
end
|
11
|
-
|
12
|
-
def to_h
|
13
|
-
super(aggregation_hash)
|
14
|
-
end
|
15
|
-
|
16
|
-
private
|
17
|
-
|
18
|
-
def aggregation_hash
|
19
|
-
{ terms: { field: field }.merge!(options) }
|
3
|
+
class Terms < FieldBased
|
4
|
+
def type
|
5
|
+
:terms
|
20
6
|
end
|
21
7
|
end
|
22
8
|
end
|
@@ -1,19 +1,16 @@
|
|
1
1
|
module Elasticband
|
2
2
|
class Aggregation
|
3
3
|
class TopHits < Aggregation
|
4
|
-
attr_accessor :
|
4
|
+
attr_accessor :size, :options
|
5
5
|
|
6
|
-
def initialize(name,
|
6
|
+
def initialize(name, size, options = {})
|
7
7
|
super(name)
|
8
|
-
self.root_aggregation = root_aggregation
|
9
8
|
self.size = size
|
10
9
|
self.options = options
|
11
10
|
end
|
12
11
|
|
13
12
|
def to_h
|
14
|
-
|
15
|
-
h[root_aggregation.name].merge!(aggs: super(top_hits_hash))
|
16
|
-
end
|
13
|
+
super(top_hits_hash)
|
17
14
|
end
|
18
15
|
|
19
16
|
private
|
data/lib/elasticband/query.rb
CHANGED
@@ -139,7 +139,8 @@ module Elasticband
|
|
139
139
|
filter = join_filters(parse_filters(boost_options[:boost_where]))
|
140
140
|
ScoreFunction::Filtered.new(filter, ScoreFunction::BoostFactor.new(1_000))
|
141
141
|
else
|
142
|
-
|
142
|
+
boost_function, boost_function_params = boost_options[:boost_function]
|
143
|
+
ScoreFunction::ScriptScore.new(boost_function, boost_function_params || {})
|
143
144
|
end
|
144
145
|
end
|
145
146
|
end
|
data/lib/elasticband/version.rb
CHANGED
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe Elasticband::Aggregation::FieldBased do
|
4
|
+
describe '#type' do
|
5
|
+
subject { described_class.new(:aggregation_name, :field_name).type }
|
6
|
+
|
7
|
+
it { expect { subject }.to raise_error(NotImplementedError) }
|
8
|
+
end
|
9
|
+
|
10
|
+
describe '#to_h' do
|
11
|
+
subject { aggregation.to_h }
|
12
|
+
|
13
|
+
before { allow(aggregation).to receive(:type) { :aggregation_type } }
|
14
|
+
|
15
|
+
context 'without options' do
|
16
|
+
let(:aggregation) { described_class.new(:aggregation_name, :field_name) }
|
17
|
+
|
18
|
+
it { is_expected.to eq(aggregation_name: { aggregation_type: { field: :field_name } }) }
|
19
|
+
end
|
20
|
+
|
21
|
+
context 'with options' do
|
22
|
+
context 'with field' do
|
23
|
+
let(:aggregation) { described_class.new(:aggregation_name, :field_name, size: 1) }
|
24
|
+
|
25
|
+
it { is_expected.to eq(aggregation_name: { aggregation_type: { field: :field_name, size: 1 } }) }
|
26
|
+
end
|
27
|
+
|
28
|
+
context 'without field' do
|
29
|
+
let(:aggregation) { described_class.new(:aggregation_name, nil, script: "doc['price'].value") }
|
30
|
+
|
31
|
+
it { is_expected.to eq(aggregation_name: { aggregation_type: { script: "doc['price'].value" } }) }
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -2,27 +2,52 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
RSpec.describe Elasticband::Aggregation::Nested do
|
4
4
|
describe '#to_h' do
|
5
|
-
subject { described_class.new(root_aggregation, nested_aggregation).to_h }
|
6
|
-
|
7
5
|
let(:root_aggregation) { Elasticband::Aggregation.new(:root_aggregation) }
|
8
|
-
let(:
|
6
|
+
let(:nested_aggregation_1) { Elasticband::Aggregation.new(:nested_aggregation_1) }
|
7
|
+
let(:nested_aggregation_2) { Elasticband::Aggregation.new(:nested_aggregation_2) }
|
8
|
+
let(:nested_aggregations) { [nested_aggregation_1, nested_aggregation_2] }
|
9
9
|
|
10
10
|
before do
|
11
|
-
allow(
|
12
|
-
allow(
|
11
|
+
allow(nested_aggregation_1).to receive(:to_h) { { nested_aggregation_1: { key_1: :value_1 } } }
|
12
|
+
allow(nested_aggregation_2).to receive(:to_h) { { nested_aggregation_2: { key_2: :value_2 } } }
|
13
|
+
allow(root_aggregation).to receive(:to_h) { { root_aggregation: { key: :value } } }
|
13
14
|
end
|
14
15
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
16
|
+
context 'with one aggregation' do
|
17
|
+
subject { described_class.new(root_aggregation, nested_aggregation_1).to_h }
|
18
|
+
|
19
|
+
it 'returns a nested aggreagation hash' do
|
20
|
+
is_expected.to eq(
|
21
|
+
root_aggregation: {
|
22
|
+
key: :value,
|
23
|
+
aggs: {
|
24
|
+
nested_aggregation_1: {
|
25
|
+
key_1: :value_1
|
26
|
+
}
|
27
|
+
}
|
28
|
+
}
|
29
|
+
)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'with two aggregations' do
|
34
|
+
subject { described_class.new(root_aggregation, nested_aggregations).to_h }
|
35
|
+
|
36
|
+
it 'returns a nested aggreagation hash' do
|
37
|
+
is_expected.to eq(
|
38
|
+
root_aggregation: {
|
39
|
+
key: :value,
|
40
|
+
aggs: {
|
41
|
+
nested_aggregation_1: {
|
42
|
+
key_1: :value_1
|
43
|
+
},
|
44
|
+
nested_aggregation_2: {
|
45
|
+
key_2: :value_2
|
46
|
+
}
|
22
47
|
}
|
23
48
|
}
|
24
|
-
|
25
|
-
|
49
|
+
)
|
50
|
+
end
|
26
51
|
end
|
27
52
|
end
|
28
53
|
end
|
@@ -1,17 +1,9 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
RSpec.describe Elasticband::Aggregation::Terms do
|
4
|
-
describe '#
|
5
|
-
|
6
|
-
subject { described_class.new(:aggregation_name, :field_name).to_h }
|
4
|
+
describe '#type' do
|
5
|
+
subject { described_class.new(:aggregation_name, :field_name).type }
|
7
6
|
|
8
|
-
|
9
|
-
end
|
10
|
-
|
11
|
-
context 'with options' do
|
12
|
-
subject { described_class.new(:aggregation_name, :field_name, size: 1).to_h }
|
13
|
-
|
14
|
-
it { is_expected.to eq(aggregation_name: { terms: { field: :field_name, size: 1 } }) }
|
15
|
-
end
|
7
|
+
it { is_expected.to eq(:terms) }
|
16
8
|
end
|
17
9
|
end
|
@@ -2,25 +2,16 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
RSpec.describe Elasticband::Aggregation::TopHits do
|
4
4
|
describe '#to_h' do
|
5
|
-
|
5
|
+
context 'without options' do
|
6
|
+
subject { described_class.new(:top_hits_aggregation, 3).to_h }
|
6
7
|
|
7
|
-
|
8
|
-
|
9
|
-
before do
|
10
|
-
allow(root_aggregation).to receive(:to_h) { { root_aggregation: { terms: { field: :field_name } } } }
|
8
|
+
it { is_expected.to eq(top_hits_aggregation: { top_hits: { size: 3 } }) }
|
11
9
|
end
|
12
10
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
aggs: {
|
18
|
-
top_hits_aggregation: {
|
19
|
-
top_hits: { size: 3 }
|
20
|
-
}
|
21
|
-
}
|
22
|
-
}
|
23
|
-
)
|
11
|
+
context 'with options' do
|
12
|
+
subject { described_class.new(:top_hits_aggregation, 3, cache: true).to_h }
|
13
|
+
|
14
|
+
it { is_expected.to eq(top_hits_aggregation: { top_hits: { size: 3, cache: true } }) }
|
24
15
|
end
|
25
16
|
end
|
26
17
|
end
|
data/spec/aggregation_spec.rb
CHANGED
@@ -13,6 +13,12 @@ RSpec.describe Elasticband::Aggregation do
|
|
13
13
|
|
14
14
|
it { is_expected.to eq(aggregation_name: { key: :value }) }
|
15
15
|
end
|
16
|
+
|
17
|
+
context 'with special chars' do
|
18
|
+
subject { described_class.new('aggregation.name').to_h }
|
19
|
+
|
20
|
+
it { is_expected.to eq(aggregation_name: {}) }
|
21
|
+
end
|
16
22
|
end
|
17
23
|
|
18
24
|
describe '.parse' do
|
@@ -22,17 +28,17 @@ RSpec.describe Elasticband::Aggregation do
|
|
22
28
|
context 'with the field_name' do
|
23
29
|
let(:options) { { group_by: :status } }
|
24
30
|
|
25
|
-
it { is_expected.to eq(
|
31
|
+
it { is_expected.to eq(by_status: { terms: { field: :status } }) }
|
26
32
|
end
|
27
33
|
|
28
|
-
context 'with an array with field_name and
|
34
|
+
context 'with an array with field_name and other aggregation' do
|
29
35
|
let(:options) { { group_by: [:status, top_hits: 3] } }
|
30
36
|
|
31
37
|
it 'returns the `terms` aggregation with a `top_hits` nested' do
|
32
38
|
is_expected.to eq(
|
33
|
-
|
39
|
+
by_status: {
|
34
40
|
terms: { field: :status },
|
35
|
-
aggs: {
|
41
|
+
aggs: { top_by_status: { top_hits: { size: 3 } } }
|
36
42
|
}
|
37
43
|
)
|
38
44
|
end
|
@@ -41,8 +47,52 @@ RSpec.describe Elasticband::Aggregation do
|
|
41
47
|
context 'with an array with field_name and other options' do
|
42
48
|
let(:options) { { group_by: [:status, size: 3] } }
|
43
49
|
|
44
|
-
it { is_expected.to eq(
|
50
|
+
it { is_expected.to eq(by_status: { terms: { field: :status, size: 3 } }) }
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
context 'with `:group_max` option' do
|
55
|
+
context 'with the field_name' do
|
56
|
+
let(:options) { { group_max: :price } }
|
57
|
+
|
58
|
+
it { is_expected.to eq(max_price: { max: { field: :price } }) }
|
59
|
+
end
|
60
|
+
|
61
|
+
context 'with an array with field_name and options' do
|
62
|
+
let(:options) { { group_max: [:price, script: '_value * 1.2'] } }
|
63
|
+
|
64
|
+
it { is_expected.to eq(max_price: { max: { field: :price, script: '_value * 1.2' } }) }
|
45
65
|
end
|
46
66
|
end
|
67
|
+
|
68
|
+
context 'with more than one aggregation' do
|
69
|
+
let(:options) { { group_by: :status, group_max: :price } }
|
70
|
+
|
71
|
+
it 'returns a hash with all aggregations' do
|
72
|
+
is_expected.to eq(
|
73
|
+
by_status: { terms: { field: :status } },
|
74
|
+
max_price: { max: { field: :price } }
|
75
|
+
)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
describe '.merge' do
|
81
|
+
subject { described_class.merge(aggregation_1, aggregation_2) }
|
82
|
+
|
83
|
+
let(:aggregation_1) { Elasticband::Aggregation.new(:aggregation_1) }
|
84
|
+
let(:aggregation_2) { Elasticband::Aggregation.new(:aggregation_2) }
|
85
|
+
|
86
|
+
before do
|
87
|
+
allow(aggregation_1).to receive(:to_h) { { aggregation_1: { key_1: :value_1 } } }
|
88
|
+
allow(aggregation_2).to receive(:to_h) { { aggregation_2: { key_2: :value_2 } } }
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'returns a hash with all aggregations' do
|
92
|
+
is_expected.to eq(
|
93
|
+
aggregation_1: { key_1: :value_1 },
|
94
|
+
aggregation_2: { key_2: :value_2 }
|
95
|
+
)
|
96
|
+
end
|
47
97
|
end
|
48
98
|
end
|
data/spec/query_spec.rb
CHANGED
@@ -219,17 +219,37 @@ RSpec.describe Elasticband::Query do
|
|
219
219
|
end
|
220
220
|
|
221
221
|
context 'with `:boost_function` option' do
|
222
|
-
|
222
|
+
context 'without params' do
|
223
|
+
let(:options) { { boost_function: "_score * doc['users_count'].value" } }
|
223
224
|
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
225
|
+
it 'returns a function score query with a `script_score` function' do
|
226
|
+
is_expected.to eq(
|
227
|
+
function_score: {
|
228
|
+
query: { match: { _all: 'foo' } },
|
229
|
+
script_score: {
|
230
|
+
script: "_score * doc['users_count'].value"
|
231
|
+
}
|
230
232
|
}
|
231
|
-
|
232
|
-
|
233
|
+
)
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
context 'with params' do
|
238
|
+
let(:options) { { boost_function: ['_score * test_param', params: { test_param: 1 }] } }
|
239
|
+
|
240
|
+
it 'returns a function score query with a `script_score` function and params' do
|
241
|
+
is_expected.to eq(
|
242
|
+
function_score: {
|
243
|
+
query: { match: { _all: 'foo' } },
|
244
|
+
script_score: {
|
245
|
+
script: '_score * test_param',
|
246
|
+
params: {
|
247
|
+
test_param: 1
|
248
|
+
}
|
249
|
+
}
|
250
|
+
}
|
251
|
+
)
|
252
|
+
end
|
233
253
|
end
|
234
254
|
end
|
235
255
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: elasticband
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Glauber Campinho
|
@@ -15,84 +15,84 @@ dependencies:
|
|
15
15
|
name: activesupport
|
16
16
|
requirement: !ruby/object:Gem::Requirement
|
17
17
|
requirements:
|
18
|
-
- -
|
18
|
+
- - ! '>='
|
19
19
|
- !ruby/object:Gem::Version
|
20
20
|
version: '0'
|
21
21
|
type: :runtime
|
22
22
|
prerelease: false
|
23
23
|
version_requirements: !ruby/object:Gem::Requirement
|
24
24
|
requirements:
|
25
|
-
- -
|
25
|
+
- - ! '>='
|
26
26
|
- !ruby/object:Gem::Version
|
27
27
|
version: '0'
|
28
28
|
- !ruby/object:Gem::Dependency
|
29
29
|
name: dotenv
|
30
30
|
requirement: !ruby/object:Gem::Requirement
|
31
31
|
requirements:
|
32
|
-
- -
|
32
|
+
- - ! '>='
|
33
33
|
- !ruby/object:Gem::Version
|
34
34
|
version: '0'
|
35
35
|
type: :development
|
36
36
|
prerelease: false
|
37
37
|
version_requirements: !ruby/object:Gem::Requirement
|
38
38
|
requirements:
|
39
|
-
- -
|
39
|
+
- - ! '>='
|
40
40
|
- !ruby/object:Gem::Version
|
41
41
|
version: '0'
|
42
42
|
- !ruby/object:Gem::Dependency
|
43
43
|
name: rake
|
44
44
|
requirement: !ruby/object:Gem::Requirement
|
45
45
|
requirements:
|
46
|
-
- -
|
46
|
+
- - ! '>='
|
47
47
|
- !ruby/object:Gem::Version
|
48
48
|
version: '0'
|
49
49
|
type: :development
|
50
50
|
prerelease: false
|
51
51
|
version_requirements: !ruby/object:Gem::Requirement
|
52
52
|
requirements:
|
53
|
-
- -
|
53
|
+
- - ! '>='
|
54
54
|
- !ruby/object:Gem::Version
|
55
55
|
version: '0'
|
56
56
|
- !ruby/object:Gem::Dependency
|
57
57
|
name: rspec
|
58
58
|
requirement: !ruby/object:Gem::Requirement
|
59
59
|
requirements:
|
60
|
-
- -
|
60
|
+
- - ~>
|
61
61
|
- !ruby/object:Gem::Version
|
62
62
|
version: 3.3.0
|
63
63
|
type: :development
|
64
64
|
prerelease: false
|
65
65
|
version_requirements: !ruby/object:Gem::Requirement
|
66
66
|
requirements:
|
67
|
-
- -
|
67
|
+
- - ~>
|
68
68
|
- !ruby/object:Gem::Version
|
69
69
|
version: 3.3.0
|
70
70
|
- !ruby/object:Gem::Dependency
|
71
71
|
name: rubocop
|
72
72
|
requirement: !ruby/object:Gem::Requirement
|
73
73
|
requirements:
|
74
|
-
- -
|
74
|
+
- - ! '>='
|
75
75
|
- !ruby/object:Gem::Version
|
76
76
|
version: '0'
|
77
77
|
type: :development
|
78
78
|
prerelease: false
|
79
79
|
version_requirements: !ruby/object:Gem::Requirement
|
80
80
|
requirements:
|
81
|
-
- -
|
81
|
+
- - ! '>='
|
82
82
|
- !ruby/object:Gem::Version
|
83
83
|
version: '0'
|
84
84
|
- !ruby/object:Gem::Dependency
|
85
85
|
name: codeclimate-test-reporter
|
86
86
|
requirement: !ruby/object:Gem::Requirement
|
87
87
|
requirements:
|
88
|
-
- -
|
88
|
+
- - ! '>='
|
89
89
|
- !ruby/object:Gem::Version
|
90
90
|
version: '0'
|
91
91
|
type: :development
|
92
92
|
prerelease: false
|
93
93
|
version_requirements: !ruby/object:Gem::Requirement
|
94
94
|
requirements:
|
95
|
-
- -
|
95
|
+
- - ! '>='
|
96
96
|
- !ruby/object:Gem::Version
|
97
97
|
version: '0'
|
98
98
|
description:
|
@@ -103,10 +103,10 @@ executables: []
|
|
103
103
|
extensions: []
|
104
104
|
extra_rdoc_files: []
|
105
105
|
files:
|
106
|
-
-
|
107
|
-
-
|
108
|
-
-
|
109
|
-
-
|
106
|
+
- .gitignore
|
107
|
+
- .rspec
|
108
|
+
- .rubocop.yml
|
109
|
+
- .travis.yml
|
110
110
|
- CODE_OF_CONDUCT.md
|
111
111
|
- Gemfile
|
112
112
|
- LICENSE
|
@@ -115,6 +115,8 @@ files:
|
|
115
115
|
- elasticband.gemspec
|
116
116
|
- lib/elasticband.rb
|
117
117
|
- lib/elasticband/aggregation.rb
|
118
|
+
- lib/elasticband/aggregation/field_based.rb
|
119
|
+
- lib/elasticband/aggregation/max.rb
|
118
120
|
- lib/elasticband/aggregation/nested.rb
|
119
121
|
- lib/elasticband/aggregation/terms.rb
|
120
122
|
- lib/elasticband/aggregation/top_hits.rb
|
@@ -136,6 +138,8 @@ files:
|
|
136
138
|
- lib/elasticband/query/score_function/script_score.rb
|
137
139
|
- lib/elasticband/search.rb
|
138
140
|
- lib/elasticband/version.rb
|
141
|
+
- spec/aggregation/field_based_spec.rb
|
142
|
+
- spec/aggregation/max_spec.rb
|
139
143
|
- spec/aggregation/nested_spec.rb
|
140
144
|
- spec/aggregation/terms_spec.rb
|
141
145
|
- spec/aggregation/top_hits_spec.rb
|
@@ -168,17 +172,17 @@ require_paths:
|
|
168
172
|
- lib
|
169
173
|
required_ruby_version: !ruby/object:Gem::Requirement
|
170
174
|
requirements:
|
171
|
-
- -
|
175
|
+
- - ! '>='
|
172
176
|
- !ruby/object:Gem::Version
|
173
177
|
version: '0'
|
174
178
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
175
179
|
requirements:
|
176
|
-
- -
|
180
|
+
- - ! '>='
|
177
181
|
- !ruby/object:Gem::Version
|
178
182
|
version: '0'
|
179
183
|
requirements: []
|
180
184
|
rubyforge_project:
|
181
|
-
rubygems_version: 2.4.
|
185
|
+
rubygems_version: 2.4.5
|
182
186
|
signing_key:
|
183
187
|
specification_version: 4
|
184
188
|
summary: Query builder for elasticsearch-rails
|