stretchy 0.1.2 → 0.2.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/stretchy/boosts/base.rb +2 -0
- data/lib/stretchy/boosts/filter_boost.rb +4 -4
- data/lib/stretchy/boosts/random_boost.rb +2 -2
- data/lib/stretchy/builders/boost_builder.rb +36 -0
- data/lib/stretchy/builders/match_builder.rb +44 -0
- data/lib/stretchy/builders/where_builder.rb +126 -0
- data/lib/stretchy/clauses/base.rb +95 -0
- data/lib/stretchy/clauses/boost_clause.rb +50 -0
- data/lib/stretchy/clauses/boost_match_clause.rb +31 -0
- data/lib/stretchy/clauses/boost_where_clause.rb +44 -0
- data/lib/stretchy/clauses/match_clause.rb +57 -0
- data/lib/stretchy/clauses/where_clause.rb +113 -0
- data/lib/stretchy/filters/and_filter.rb +6 -2
- data/lib/stretchy/filters/bool_filter.rb +8 -7
- data/lib/stretchy/filters/exists_filter.rb +3 -0
- data/lib/stretchy/filters/geo_filter.rb +9 -9
- data/lib/stretchy/filters/range_filter.rb +8 -6
- data/lib/stretchy/filters/terms_filter.rb +17 -9
- data/lib/stretchy/queries/bool_query.rb +21 -0
- data/lib/stretchy/queries/filtered_query.rb +4 -3
- data/lib/stretchy/queries/function_score_query.rb +1 -1
- data/lib/stretchy/queries/match_query.rb +12 -5
- data/lib/stretchy/results/base.rb +45 -0
- data/lib/stretchy/results/null_results.rb +22 -0
- data/lib/stretchy/utils/contract.rb +16 -1
- data/lib/stretchy/version.rb +1 -1
- data/lib/stretchy.rb +12 -3
- data/stretchy.gemspec +6 -4
- metadata +42 -5
- data/lib/stretchy/null_query.rb +0 -30
- data/lib/stretchy/query.rb +0 -241
- data/lib/stretchy/request_body.rb +0 -67
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 02cee68659326cb0fcbb36e25b584efd846149cc
|
4
|
+
data.tar.gz: 4af82a79df5998f4bf7beface88f4467425fd86a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 432060e10838aa8438d545ff402214d9b4048d5848f1dbefde4d0a4fff4be366b51dfe52642d02628b61462679c0a7ee513035acd9dd2cd6c5604cb2ac1b64ec
|
7
|
+
data.tar.gz: 98a4e9114c0b8a99687773994ab45bbc32a07621cb48a7cb41f6e132e0d3dc975211ed091a99a686739efee9010742219ede298b3d0402da75a92e353f718e90
|
data/lib/stretchy/boosts/base.rb
CHANGED
@@ -2,14 +2,14 @@ module Stretchy
|
|
2
2
|
module Boosts
|
3
3
|
class FilterBoost < Base
|
4
4
|
|
5
|
-
|
5
|
+
attr_reader :filter, :weight
|
6
6
|
|
7
7
|
contract filter: {type: Stretchy::Filters::Base},
|
8
8
|
weight: {type: Numeric}
|
9
9
|
|
10
|
-
def initialize(
|
11
|
-
@filter = filter
|
12
|
-
@weight = weight
|
10
|
+
def initialize(options = {})
|
11
|
+
@filter = options[:filter]
|
12
|
+
@weight = options[:weight] || DEFAULT_WEIGHT
|
13
13
|
validate!
|
14
14
|
end
|
15
15
|
|
@@ -10,9 +10,9 @@ module Stretchy
|
|
10
10
|
# randomizes order (somewhat) consistently per-user
|
11
11
|
# http://www.elastic.co/guide/en/elasticsearch/guide/current/random-scoring.html
|
12
12
|
|
13
|
-
def initialize(seed, weight =
|
13
|
+
def initialize(seed, weight = nil)
|
14
14
|
@seed = seed
|
15
|
-
@weight = weight
|
15
|
+
@weight = weight || DEFAULT_WEIGHT
|
16
16
|
validate!
|
17
17
|
end
|
18
18
|
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Stretchy
|
2
|
+
module Builders
|
3
|
+
class BoostBuilder
|
4
|
+
|
5
|
+
attr_accessor :functions, :overall_boost, :max_boost, :score_mode, :boost_mode
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@functions = []
|
9
|
+
@overall_boost = nil
|
10
|
+
@max_boost = nil
|
11
|
+
@score_mode = 'sum'
|
12
|
+
@boost_mode = 'sum'
|
13
|
+
end
|
14
|
+
|
15
|
+
def any?
|
16
|
+
@functions.any?
|
17
|
+
end
|
18
|
+
|
19
|
+
def build(query_or_filter)
|
20
|
+
options = {
|
21
|
+
functions: @functions,
|
22
|
+
score_mode: @score_mode,
|
23
|
+
boost_mode: @boost_mode
|
24
|
+
}
|
25
|
+
|
26
|
+
options[:overall_boost] = @overall_boost if @overall_boost
|
27
|
+
options[:max_boost] = @max_boost if @max_boost
|
28
|
+
options[:query] = query_or_filter if query_or_filter.is_a?(Stretchy::Queries::Base)
|
29
|
+
options[:filter] = query_or_filter if query_or_filter.is_a?(Stretchy::Filters::Base)
|
30
|
+
|
31
|
+
Stretchy::Queries::FunctionScoreQuery.new(options)
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Stretchy
|
2
|
+
module Builders
|
3
|
+
class MatchBuilder
|
4
|
+
|
5
|
+
attr_accessor :matches, :antimatches
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@matches = Hash.new { [] }
|
9
|
+
@antimatches = Hash.new { [] }
|
10
|
+
end
|
11
|
+
|
12
|
+
def any?
|
13
|
+
@matches.any? || @antimatches.any?
|
14
|
+
end
|
15
|
+
|
16
|
+
def build
|
17
|
+
return Stretchy::Queries::MatchAllQuery.new unless any?
|
18
|
+
|
19
|
+
if @matches.count > 1 || @antimatches.any?
|
20
|
+
bool_query
|
21
|
+
else
|
22
|
+
field, strings = @matches.first
|
23
|
+
Stretchy::Queries::MatchQuery.new(field: field, string: strings.join(' '))
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def bool_query
|
28
|
+
Stretchy::Queries::BoolQuery.new(
|
29
|
+
must: to_queries(@matches),
|
30
|
+
must_not: to_queries(@antimatches)
|
31
|
+
)
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def to_queries(matches)
|
37
|
+
matches.map do |field, strings|
|
38
|
+
Stretchy::Queries::MatchQuery.new(field: field, string: strings.join(' '))
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
module Stretchy
|
2
|
+
module Builders
|
3
|
+
class WhereBuilder
|
4
|
+
|
5
|
+
attr_accessor :terms, :antiterms, :exists, :empties,
|
6
|
+
:ranges, :antiranges, :geos, :antigeos
|
7
|
+
|
8
|
+
def initialize(options = {})
|
9
|
+
@terms = Hash.new { [] }
|
10
|
+
@antiterms = Hash.new { [] }
|
11
|
+
@ranges = {}
|
12
|
+
@antiranges = {}
|
13
|
+
@geos = {}
|
14
|
+
@antigeos = {}
|
15
|
+
|
16
|
+
@exists = []
|
17
|
+
@empties = []
|
18
|
+
end
|
19
|
+
|
20
|
+
def build
|
21
|
+
if use_bool?
|
22
|
+
bool_filter
|
23
|
+
elsif musts?
|
24
|
+
and_filter
|
25
|
+
elsif must_nots?
|
26
|
+
not_filter
|
27
|
+
else
|
28
|
+
nil
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def musts?
|
33
|
+
@terms.any? || @exists.any? || @ranges.any? || @geos.any?
|
34
|
+
end
|
35
|
+
|
36
|
+
def must_nots?
|
37
|
+
@antiterms.any? || @empties.any? ||
|
38
|
+
@antiranges.any? || @antigeos.any?
|
39
|
+
end
|
40
|
+
|
41
|
+
def use_bool?
|
42
|
+
musts? && must_nots?
|
43
|
+
end
|
44
|
+
|
45
|
+
def any?
|
46
|
+
musts? || must_nots?
|
47
|
+
end
|
48
|
+
|
49
|
+
def bool_filter
|
50
|
+
Stretchy::Filters::BoolFilter.new(
|
51
|
+
must: build_filters(
|
52
|
+
terms: @terms,
|
53
|
+
exists: @exists,
|
54
|
+
ranges: @ranges,
|
55
|
+
geos: @geos
|
56
|
+
),
|
57
|
+
must_not: build_filters(
|
58
|
+
terms: @antiterms,
|
59
|
+
exists: @empties,
|
60
|
+
ranges: @antiranges,
|
61
|
+
geos: @antigeos
|
62
|
+
)
|
63
|
+
)
|
64
|
+
end
|
65
|
+
|
66
|
+
def and_filter
|
67
|
+
filter = nil
|
68
|
+
filters = build_filters(
|
69
|
+
terms: @terms,
|
70
|
+
exists: @exists,
|
71
|
+
ranges: @ranges,
|
72
|
+
geos: @geos
|
73
|
+
)
|
74
|
+
if filters.count > 1
|
75
|
+
filter = Stretchy::Filters::AndFilter.new(filters)
|
76
|
+
else
|
77
|
+
filter = filters.first
|
78
|
+
end
|
79
|
+
filter
|
80
|
+
end
|
81
|
+
|
82
|
+
def not_filter
|
83
|
+
filter = build_filters(
|
84
|
+
terms: @antiterms,
|
85
|
+
exists: @empties,
|
86
|
+
ranges: @antiranges,
|
87
|
+
geos: @antigeos
|
88
|
+
)
|
89
|
+
filter = Stretchy::Filters::AndFilter.new(filter) if filter.count > 1
|
90
|
+
Stretchy::Filters::NotFilter.new(filter)
|
91
|
+
end
|
92
|
+
|
93
|
+
def build_filters(options = {})
|
94
|
+
filters = []
|
95
|
+
terms = Hash(options[:terms])
|
96
|
+
ranges = Hash(options[:ranges])
|
97
|
+
geos = Hash(options[:geos])
|
98
|
+
exists = Array(options[:exists])
|
99
|
+
|
100
|
+
filters << Stretchy::Filters::TermsFilter.new(terms) if terms.any?
|
101
|
+
|
102
|
+
filters += exists.map do |field|
|
103
|
+
Stretchy::Filters::ExistsFilter.new(field)
|
104
|
+
end
|
105
|
+
|
106
|
+
filters += ranges.map do |field, values|
|
107
|
+
Stretchy::Filters::RangeFilter.new(
|
108
|
+
field: field,
|
109
|
+
min: values[:min],
|
110
|
+
max: values[:max]
|
111
|
+
)
|
112
|
+
end
|
113
|
+
|
114
|
+
filters += geos.map do |field, values|
|
115
|
+
Stretchy::Filters::GeoFilter.new(
|
116
|
+
field: field,
|
117
|
+
distance: values[:distance],
|
118
|
+
lat: values[:lat],
|
119
|
+
lng: values[:lng]
|
120
|
+
)
|
121
|
+
end
|
122
|
+
filters
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
module Stretchy
|
2
|
+
module Clauses
|
3
|
+
class Base
|
4
|
+
|
5
|
+
extend Forwardable
|
6
|
+
|
7
|
+
DEFAULT_LIMIT = 30
|
8
|
+
DEFAULT_OFFSET = 0
|
9
|
+
|
10
|
+
attr_accessor :match_builder, :where_builder, :boost_builder,
|
11
|
+
:aggregate_builder, :inverse, :type, :index_name
|
12
|
+
|
13
|
+
alias :inverse? :inverse
|
14
|
+
|
15
|
+
delegate [:response, :results, :ids, :hits, :took, :shards, :total, :max_score] => :query_results
|
16
|
+
|
17
|
+
def initialize(base_or_opts = nil, options = {})
|
18
|
+
if base_or_opts && !base_or_opts.is_a?(Hash)
|
19
|
+
base = base_or_opts
|
20
|
+
@index_name = base.index_name
|
21
|
+
@type = base.type
|
22
|
+
@match_builder = base.match_builder
|
23
|
+
@where_builder = base.where_builder
|
24
|
+
@boost_builder = base.boost_builder
|
25
|
+
@aggregate_builder = base.aggregate_builder
|
26
|
+
@inverse = options[:inverse] || base.inverse
|
27
|
+
@limit = base.get_limit
|
28
|
+
@offset = base.get_offset
|
29
|
+
else
|
30
|
+
options = Hash(base_or_opts).merge(options)
|
31
|
+
@index_name = options[:index] || Stretchy.index_name
|
32
|
+
@type = options[:type]
|
33
|
+
@match_builder = Stretchy::Builders::MatchBuilder.new
|
34
|
+
@where_builder = Stretchy::Builders::WhereBuilder.new
|
35
|
+
@boost_builder = Stretchy::Builders::BoostBuilder.new
|
36
|
+
@aggregate_builder = nil
|
37
|
+
@inverse = options[:inverse]
|
38
|
+
@limit = DEFAULT_LIMIT
|
39
|
+
@offset = DEFAULT_OFFSET
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def limit(num)
|
44
|
+
@limit = num
|
45
|
+
self
|
46
|
+
end
|
47
|
+
|
48
|
+
def get_limit
|
49
|
+
@limit
|
50
|
+
end
|
51
|
+
|
52
|
+
def offset(num)
|
53
|
+
@offset = num
|
54
|
+
self
|
55
|
+
end
|
56
|
+
|
57
|
+
def get_offset
|
58
|
+
@offset
|
59
|
+
end
|
60
|
+
|
61
|
+
def match(options = {})
|
62
|
+
MatchClause.new(self, options)
|
63
|
+
end
|
64
|
+
|
65
|
+
def where(options = {})
|
66
|
+
WhereClause.new(self, options)
|
67
|
+
end
|
68
|
+
|
69
|
+
def boost(options = {})
|
70
|
+
BoostClause.new(self, options)
|
71
|
+
end
|
72
|
+
|
73
|
+
def to_search
|
74
|
+
return @to_search if @to_search
|
75
|
+
|
76
|
+
@to_search = if @where_builder.any?
|
77
|
+
Stretchy::Queries::FilteredQuery.new(
|
78
|
+
query: @match_builder.build,
|
79
|
+
filter: @where_builder.build
|
80
|
+
)
|
81
|
+
else
|
82
|
+
@match_builder.build
|
83
|
+
end
|
84
|
+
|
85
|
+
@to_search = @boost_builder.build(@to_search) if @boost_builder.any?
|
86
|
+
@to_search = @to_search.to_search
|
87
|
+
end
|
88
|
+
|
89
|
+
def query_results
|
90
|
+
@query_results ||= Stretchy::Results::Base.new(to_search.merge(from: @limit, size: @offset), type: @type)
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Stretchy
|
2
|
+
module Clauses
|
3
|
+
class BoostClause < Base
|
4
|
+
|
5
|
+
def initialize(base, options = {})
|
6
|
+
super(base)
|
7
|
+
@inverse = options.delete(:inverse)
|
8
|
+
end
|
9
|
+
|
10
|
+
def match(options = {})
|
11
|
+
BoostMatchClause.new(self, options)
|
12
|
+
end
|
13
|
+
|
14
|
+
def where(options = {})
|
15
|
+
BoostWhereClause.new(self, options)
|
16
|
+
end
|
17
|
+
|
18
|
+
def random(*args)
|
19
|
+
@boost_builder.functions << Stretchy::Boosts::RandomBoost.new(*args)
|
20
|
+
self
|
21
|
+
end
|
22
|
+
|
23
|
+
def all(num)
|
24
|
+
@boost_builder.overall_boost = num
|
25
|
+
self
|
26
|
+
end
|
27
|
+
|
28
|
+
def max(num)
|
29
|
+
@boost_builder.max_boost = num
|
30
|
+
self
|
31
|
+
end
|
32
|
+
|
33
|
+
def score_mode(mode)
|
34
|
+
@boost_builder.score_mode = mode
|
35
|
+
self
|
36
|
+
end
|
37
|
+
|
38
|
+
def boost_mode(mode)
|
39
|
+
@boost_builder.boost_mode = mode
|
40
|
+
self
|
41
|
+
end
|
42
|
+
|
43
|
+
def not(options = {})
|
44
|
+
inst = self.class.new(self, options.merge(inverse: !inverse?))
|
45
|
+
inst
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Stretchy
|
2
|
+
module Clauses
|
3
|
+
class BoostMatchClause < BoostClause
|
4
|
+
|
5
|
+
def initialize(base, opts_or_string = {}, options = {})
|
6
|
+
super(base)
|
7
|
+
if opts_or_string.is_a?(Hash)
|
8
|
+
@inverse = opts_or_string.delete(:inverse) || options.delete(:inverse)
|
9
|
+
match_function(opts_or_string.merge(options))
|
10
|
+
else
|
11
|
+
@inverse = options.delete(:inverse)
|
12
|
+
match_function(options.merge('_all' => opts_or_string))
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def not(opts_or_string = {}, options = {})
|
17
|
+
self.class.new(self, opts_or_string, options.merge(inverse: !inverse?))
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def match_function(options = {})
|
23
|
+
weight = options.delete(:weight)
|
24
|
+
clause = MatchClause.tmp(options)
|
25
|
+
boost = clause.to_boost(weight)
|
26
|
+
@boost_builder.functions << boost if boost
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Stretchy
|
2
|
+
module Clauses
|
3
|
+
class BoostWhereClause < BoostClause
|
4
|
+
|
5
|
+
def initialize(base, options = {})
|
6
|
+
super(base, options)
|
7
|
+
where_function(:init, options)
|
8
|
+
self
|
9
|
+
end
|
10
|
+
|
11
|
+
def range(*args)
|
12
|
+
where_function(:range, *args)
|
13
|
+
self
|
14
|
+
end
|
15
|
+
|
16
|
+
def geo(*args)
|
17
|
+
where_function(:geo, *args)
|
18
|
+
self
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def add_params(params = {})
|
24
|
+
where_function(:init, params)
|
25
|
+
end
|
26
|
+
|
27
|
+
def where_function(method, *args)
|
28
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
29
|
+
weight = options.delete(:weight)
|
30
|
+
|
31
|
+
clause = nil
|
32
|
+
if method == :init
|
33
|
+
clause = WhereClause.tmp(options.merge(inverse: inverse?))
|
34
|
+
else
|
35
|
+
args.push(options)
|
36
|
+
clause = WhereClause.tmp(inverse: inverse?).send(method, *args)
|
37
|
+
end
|
38
|
+
boost = clause.to_boost(weight)
|
39
|
+
|
40
|
+
@boost_builder.functions << boost if boost
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Stretchy
|
2
|
+
module Clauses
|
3
|
+
class MatchClause < Base
|
4
|
+
|
5
|
+
def self.tmp(options = {})
|
6
|
+
self.new(Base.new, options)
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize(base, opts_or_str = {}, options = {})
|
10
|
+
super(base)
|
11
|
+
if opts_or_str.is_a?(Hash)
|
12
|
+
@inverse = opts_or_str.delete(:inverse) || options.delete(:inverse)
|
13
|
+
add_params(options.merge(opts_or_str))
|
14
|
+
else
|
15
|
+
@inverse = options.delete(:inverse)
|
16
|
+
add_params(options.merge('_all' => opts_or_str))
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def not(opts_or_str = {}, options = {})
|
21
|
+
self.class.new(self, opts_or_str, options.merge(inverse: !@inverse))
|
22
|
+
end
|
23
|
+
|
24
|
+
def to_boost(weight = nil)
|
25
|
+
weight ||= Stretchy::Boosts::FilterBoost::DEFAULT_WEIGHT
|
26
|
+
Stretchy::Boosts::FilterBoost.new(
|
27
|
+
filter: Stretchy::Filters::QueryFilter.new(
|
28
|
+
@match_builder.build
|
29
|
+
),
|
30
|
+
weight: weight
|
31
|
+
)
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def add_params(params = {})
|
37
|
+
case params
|
38
|
+
when Hash
|
39
|
+
params.each do |field, params|
|
40
|
+
add_param(field, params)
|
41
|
+
end
|
42
|
+
else
|
43
|
+
add_param('_all', params)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def add_param(field, param)
|
48
|
+
if inverse?
|
49
|
+
@match_builder.antimatches[field] += Array(param)
|
50
|
+
else
|
51
|
+
@match_builder.matches[field] += Array(param)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
module Stretchy
|
2
|
+
module Clauses
|
3
|
+
class WhereClause < Base
|
4
|
+
|
5
|
+
def self.tmp(options = {})
|
6
|
+
self.new(Base.new, options)
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize(base, options = {})
|
10
|
+
super(base)
|
11
|
+
@inverse = options.delete(:inverse)
|
12
|
+
add_params(options)
|
13
|
+
end
|
14
|
+
|
15
|
+
def range(field, options = {})
|
16
|
+
min = max = nil
|
17
|
+
|
18
|
+
case options
|
19
|
+
when Hash
|
20
|
+
min = options[:min]
|
21
|
+
max = options[:max]
|
22
|
+
store = inverse? ? @where_builder.antiranges : @where_builder.ranges
|
23
|
+
store[field] = { min: min, max: max }
|
24
|
+
when Range
|
25
|
+
add_param(field, options)
|
26
|
+
end
|
27
|
+
|
28
|
+
self
|
29
|
+
end
|
30
|
+
|
31
|
+
def geo(field, options = {})
|
32
|
+
add_geo(field, options)
|
33
|
+
self
|
34
|
+
end
|
35
|
+
|
36
|
+
def not(options = {})
|
37
|
+
self.class.new(self, options.merge(inverse: !@inverse))
|
38
|
+
end
|
39
|
+
|
40
|
+
def to_boost(weight = nil)
|
41
|
+
weight ||= Stretchy::Boosts::FilterBoost::DEFAULT_WEIGHT
|
42
|
+
|
43
|
+
if @match_builder.any? && @where_builder.any?
|
44
|
+
Stretchy::Boosts::FilterBoost.new(
|
45
|
+
filter: Stretchy::Filters::QueryFilter.new(
|
46
|
+
Stretchy::Queries::FilteredQuery.new(
|
47
|
+
query: @match_builder.build,
|
48
|
+
filter: @where_builder.build
|
49
|
+
)
|
50
|
+
),
|
51
|
+
weight: weight
|
52
|
+
)
|
53
|
+
|
54
|
+
elsif @match_builder.any?
|
55
|
+
Stretchy::Boosts::FilterBoost.new(
|
56
|
+
filter: Stretchy::Filters::QueryFilter.new(
|
57
|
+
@match_builder.build
|
58
|
+
),
|
59
|
+
weight: weight
|
60
|
+
)
|
61
|
+
|
62
|
+
elsif @where_builder.any?
|
63
|
+
Stretchy::Boosts::FilterBoost.new(
|
64
|
+
filter: @where_builder.build,
|
65
|
+
weight: weight
|
66
|
+
)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
def add_params(options = {})
|
73
|
+
options.each do |field, param|
|
74
|
+
# if it is an array, process each param
|
75
|
+
# separately - ensures string & symbols
|
76
|
+
# always go into .match_builder
|
77
|
+
|
78
|
+
if param.is_a?(Array)
|
79
|
+
param.each{|p| add_param(field, p) }
|
80
|
+
else
|
81
|
+
add_param(field, param)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def add_geo(field, options = {})
|
87
|
+
store = inverse? ? @where_builder.antigeos : @where_builder.geos
|
88
|
+
store[field] = options
|
89
|
+
end
|
90
|
+
|
91
|
+
def add_param(field, param)
|
92
|
+
case param
|
93
|
+
when nil
|
94
|
+
store = inverse? ? @where_builder.exists : @where_builder.empties
|
95
|
+
store << field
|
96
|
+
when String, Symbol
|
97
|
+
if inverse?
|
98
|
+
@match_builder.antimatches[field] += Array(param)
|
99
|
+
else
|
100
|
+
@match_builder.matches[field] += Array(param)
|
101
|
+
end
|
102
|
+
when Range
|
103
|
+
store = inverse? ? @where_builder.antiranges : @where_builder.ranges
|
104
|
+
store[field] = { min: param.min, max: param.max }
|
105
|
+
else
|
106
|
+
store = inverse? ? @where_builder.antiterms : @where_builder.terms
|
107
|
+
store[field] += Array(param)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -4,8 +4,12 @@ module Stretchy
|
|
4
4
|
|
5
5
|
contract filters: {type: Stretchy::Filters::Base, array: true}
|
6
6
|
|
7
|
-
def initialize(
|
8
|
-
|
7
|
+
def initialize(*args)
|
8
|
+
if args.count == 1 && args.first.is_a?(Array)
|
9
|
+
@filters = args.first
|
10
|
+
else
|
11
|
+
@filters = args
|
12
|
+
end
|
9
13
|
validate!
|
10
14
|
end
|
11
15
|
|
@@ -6,18 +6,19 @@ module Stretchy
|
|
6
6
|
must_not: {type: Base, array: true},
|
7
7
|
should: {type: Base, array: true}
|
8
8
|
|
9
|
-
def initialize(
|
10
|
-
@must = Array(must)
|
11
|
-
@must_not = Array(must_not)
|
12
|
-
@should = Array(should)
|
9
|
+
def initialize(options = {})
|
10
|
+
@must = Array(options[:must])
|
11
|
+
@must_not = Array(options[:must_not])
|
12
|
+
@should = Array(options[:should])
|
13
13
|
validate!
|
14
|
+
require_one(must: @must, must_not: @must_not, should: @should)
|
14
15
|
end
|
15
16
|
|
16
17
|
def to_search
|
17
18
|
json = {}
|
18
|
-
json[:must] = @must.map(&:to_search) if @must
|
19
|
-
json[:must_not] = @must_not.map(&:to_search) if @must_not
|
20
|
-
json[:should] = @should.map(&:to_search) if @should
|
19
|
+
json[:must] = @must.map(&:to_search) if @must.any?
|
20
|
+
json[:must_not] = @must_not.map(&:to_search) if @must_not.any?
|
21
|
+
json[:should] = @should.map(&:to_search) if @should.any?
|
21
22
|
{ bool: json }
|
22
23
|
end
|
23
24
|
end
|