stretchy 0.4.6 → 0.4.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.editorconfig +12 -0
- data/CONTRIBUTING.md +52 -0
- data/README.md +157 -40
- data/lib/stretchy/builders/filter_builder.rb +12 -7
- data/lib/stretchy/builders/query_builder.rb +1 -1
- data/lib/stretchy/builders/where_builder.rb +7 -3
- data/lib/stretchy/clauses/base.rb +63 -57
- data/lib/stretchy/clauses/boost_clause.rb +47 -49
- data/lib/stretchy/clauses/boost_match_clause.rb +52 -19
- data/lib/stretchy/clauses/boost_where_clause.rb +46 -28
- data/lib/stretchy/clauses/match_clause.rb +52 -42
- data/lib/stretchy/clauses/where_clause.rb +86 -70
- data/lib/stretchy/filters/params_filter.rb +27 -0
- data/lib/stretchy/filters.rb +1 -0
- data/lib/stretchy/queries/params_query.rb +21 -0
- data/lib/stretchy/queries.rb +1 -0
- data/lib/stretchy/version.rb +1 -1
- metadata +6 -2
@@ -2,13 +2,13 @@ require 'stretchy/clauses/boost_clause'
|
|
2
2
|
|
3
3
|
module Stretchy
|
4
4
|
module Clauses
|
5
|
-
#
|
5
|
+
#
|
6
6
|
# Boosts documents that match certain filters. Most filters will
|
7
|
-
# be passed into {#initialize}, but you can also use `.range` and
|
7
|
+
# be passed into {#initialize}, but you can also use `.range` and
|
8
8
|
# `.geo` .
|
9
|
-
#
|
9
|
+
#
|
10
10
|
# @author [atevans]
|
11
|
-
#
|
11
|
+
#
|
12
12
|
class BoostWhereClause < BoostClause
|
13
13
|
|
14
14
|
def boost_where(params = {}, options = {})
|
@@ -20,18 +20,18 @@ module Stretchy
|
|
20
20
|
self
|
21
21
|
end
|
22
22
|
|
23
|
-
#
|
23
|
+
#
|
24
24
|
# Returns to the base context; filters passed here
|
25
25
|
# will be used to filter documents.
|
26
|
-
#
|
26
|
+
#
|
27
27
|
# @example Returning to base context
|
28
28
|
# query.boost.where(number_field: 33).where(other_field: 64)
|
29
|
-
#
|
29
|
+
#
|
30
30
|
# @example Staying in boost context
|
31
31
|
# query.boost.where(number_field: 33).boost.where(other_field: 99)
|
32
|
-
#
|
32
|
+
#
|
33
33
|
# @see {WhereClause#initialize}
|
34
|
-
#
|
34
|
+
#
|
35
35
|
# @return [WhereClause] Query with where clause applied
|
36
36
|
def where(*args)
|
37
37
|
WhereClause.new(base).where(*args)
|
@@ -42,64 +42,82 @@ module Stretchy
|
|
42
42
|
boost_where(params, options)
|
43
43
|
end
|
44
44
|
|
45
|
-
#
|
45
|
+
#
|
46
|
+
# Boosts documents that match a filter composed of arbitrary json
|
47
|
+
# passed into the method.
|
48
|
+
#
|
49
|
+
# @param [Hash] Parameters for the filter. See {WhereClause#filter}
|
50
|
+
# @param [Hash] Options for Stretchy to determine behavior of this boost
|
51
|
+
#
|
52
|
+
# @see {WhereClause#query}
|
53
|
+
#
|
54
|
+
# @return [Base] Query with filter boost applied
|
55
|
+
def filter(params = {}, options = {})
|
56
|
+
weight = params.delete(:weight) || options[:weight]
|
57
|
+
clause = WhereClause.new.filter(params)
|
58
|
+
boost = clause.to_boost
|
59
|
+
base.boost_builder.add_boost(boost) if boost
|
60
|
+
Base.new(base)
|
61
|
+
end
|
62
|
+
|
63
|
+
#
|
46
64
|
# Returns to the base context. Queries passed here
|
47
65
|
# will be used to filter documents.
|
48
|
-
#
|
66
|
+
#
|
49
67
|
# @example Returning to base context
|
50
68
|
# query.boost.where(number_field: 89).match('username')
|
51
|
-
#
|
69
|
+
#
|
52
70
|
# @example Staying in boost context
|
53
71
|
# query.boost.where(number_field: 89).boost.match('love')
|
54
|
-
#
|
72
|
+
#
|
55
73
|
# @see {MatchClause#initialize}
|
56
|
-
#
|
74
|
+
#
|
57
75
|
# @return [MatchClause] Base context with match queries applied
|
58
76
|
def match(*args)
|
59
77
|
MatchClause.new(base).match(*args)
|
60
78
|
end
|
61
79
|
|
62
|
-
#
|
80
|
+
#
|
63
81
|
# Applies a range filter with a min or max
|
64
82
|
# as a boost.
|
65
|
-
#
|
83
|
+
#
|
66
84
|
# @see {WhereClause#range}
|
67
|
-
#
|
85
|
+
#
|
68
86
|
# @see {Filters::RangeFilter}
|
69
|
-
#
|
87
|
+
#
|
70
88
|
# @see http://www.elastic.co/guide/en/elasticsearch/guide/master/_ranges.html Elastic Guides - Ranges
|
71
|
-
#
|
89
|
+
#
|
72
90
|
# @return [Base] Query in base context with range boost applied
|
73
91
|
def range(field, options = {})
|
74
92
|
weight = options[:weight]
|
75
93
|
options[:inverse] = true if inverse?
|
76
|
-
|
94
|
+
|
77
95
|
clause = WhereClause.new.range(field, options)
|
78
96
|
boost = clause.to_boost(weight)
|
79
97
|
base.boost_builder.add_boost(boost) if boost
|
80
|
-
|
98
|
+
|
81
99
|
Base.new(base)
|
82
100
|
end
|
83
101
|
|
84
|
-
#
|
102
|
+
#
|
85
103
|
# Boosts a document if it matches a geo filter.
|
86
104
|
# This is different than {BoostClause#near} -
|
87
105
|
# while `.near` applies a decay function that boosts
|
88
106
|
# based on how close a field is to a geo point,
|
89
107
|
# `.geo` applies a filter that either boosts or doesn't
|
90
108
|
# boost the document.
|
91
|
-
#
|
109
|
+
#
|
92
110
|
# @see {WhereFunction#geo}
|
93
|
-
#
|
111
|
+
#
|
94
112
|
# @see {Filters::GeoFilter}
|
95
|
-
#
|
113
|
+
#
|
96
114
|
# @see http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-geo-distance-filter.html Elastic Docs - Geo Distance Filter
|
97
|
-
#
|
115
|
+
#
|
98
116
|
# @return [Base] Query in base context with geo filter boost applied
|
99
117
|
def geo(field, options = {})
|
100
118
|
weight = options[:weight]
|
101
119
|
options[:inverse] = true if inverse?
|
102
|
-
|
120
|
+
|
103
121
|
clause = WhereClause.new.geo(field, options)
|
104
122
|
boost = clause.to_boost(weight)
|
105
123
|
base.boost_builder.add_boost(boost) if boost
|
@@ -107,4 +125,4 @@ module Stretchy
|
|
107
125
|
end
|
108
126
|
end
|
109
127
|
end
|
110
|
-
end
|
128
|
+
end
|
@@ -2,13 +2,13 @@ require 'stretchy/clauses/base'
|
|
2
2
|
|
3
3
|
module Stretchy
|
4
4
|
module Clauses
|
5
|
-
#
|
5
|
+
#
|
6
6
|
# A Match clause inherits the same state as any clause.
|
7
7
|
# There aren't any more specific methods to chain, as
|
8
8
|
# this clause only handles basic full-text searches.
|
9
|
-
#
|
9
|
+
#
|
10
10
|
# @author [atevans]
|
11
|
-
#
|
11
|
+
#
|
12
12
|
class MatchClause < Base
|
13
13
|
|
14
14
|
FULLTEXT_SLOP = 50
|
@@ -20,14 +20,27 @@ module Stretchy
|
|
20
20
|
self
|
21
21
|
end
|
22
22
|
|
23
|
-
#
|
23
|
+
#
|
24
|
+
# Add arbitrary json as a query in the appropriate context.
|
25
|
+
# This can be used to add query types that are not currently
|
26
|
+
# supported by Stretchy to be used in the final query.
|
27
|
+
#
|
28
|
+
# @param params = {} [Hash] Query to be applied to the new state
|
29
|
+
# @option options [true, false] :inverse (nil) Ignore query state and add to the `not` query
|
30
|
+
# @option options [true, false] :should (nil) Ignore query state and add to the `should` query
|
31
|
+
def query(params = {}, options = {})
|
32
|
+
base.add_query(Queries::ParamsQuery.new(params), merge_state(options))
|
33
|
+
self
|
34
|
+
end
|
35
|
+
|
36
|
+
#
|
24
37
|
# Specifies that values for this field should be
|
25
38
|
# matched with a proximity boost, rather than as
|
26
39
|
# a generic match query.
|
27
|
-
#
|
40
|
+
#
|
28
41
|
# This means searching for "quick brown fox" will
|
29
42
|
# return matches in the following order:
|
30
|
-
#
|
43
|
+
#
|
31
44
|
# * "the quick brown fox jumped over"
|
32
45
|
# * "the brown quick fox jumped over"
|
33
46
|
# * "the fox, brown & quick jumped over"
|
@@ -35,23 +48,23 @@ module Stretchy
|
|
35
48
|
# * "the quick green and purple sparkly fox jumped over"
|
36
49
|
# * "the quick dog jumped over"
|
37
50
|
# * "the adoreable puppy jumped over" **not returned**
|
38
|
-
#
|
51
|
+
#
|
39
52
|
# @overload phrase(params)
|
40
|
-
# @param params = {} [String] A phrase that will
|
53
|
+
# @param params = {} [String] A phrase that will
|
41
54
|
# be matched anywhere in the document
|
42
|
-
#
|
55
|
+
#
|
43
56
|
# @overload phrase(params)
|
44
57
|
# @param params = {} [Hash] A hash of fields and phrases
|
45
58
|
# that should be matched in those fields
|
46
|
-
#
|
59
|
+
#
|
47
60
|
# @example Matching multiple words together
|
48
61
|
# query.match.phrase('hugs and love')
|
49
|
-
#
|
62
|
+
#
|
50
63
|
# @example Not matching a phrase
|
51
64
|
# query.match.not.phrase(comment: 'offensive words to hide')
|
52
|
-
#
|
65
|
+
#
|
53
66
|
# @return [self] Allows continuing the query chain
|
54
|
-
#
|
67
|
+
#
|
55
68
|
# @see https://www.elastic.co/guide/en/elasticsearch/guide/current/proximity-relevance.html Elasticsearch guide: proximity for relevance
|
56
69
|
def fulltext(params = {})
|
57
70
|
add_params(params)
|
@@ -59,8 +72,8 @@ module Stretchy
|
|
59
72
|
self
|
60
73
|
end
|
61
74
|
|
62
|
-
#
|
63
|
-
# Adds a MoreLikeThis query to the chain. Pass in document ids,
|
75
|
+
#
|
76
|
+
# Adds a MoreLikeThis query to the chain. Pass in document ids,
|
64
77
|
# an array of index/name/ids, or a string to get documents that
|
65
78
|
# have similar terms.
|
66
79
|
#
|
@@ -81,9 +94,9 @@ module Stretchy
|
|
81
94
|
# Defaults to '_all'
|
82
95
|
# @option params [Array] :include Whether the source documents should be
|
83
96
|
# included in the result set. Defaults to `false`
|
84
|
-
#
|
97
|
+
#
|
85
98
|
# @return [MatchClause] allows continuing the query chain
|
86
|
-
#
|
99
|
+
#
|
87
100
|
# @example Getting more like a document by id
|
88
101
|
# query.more_like(ids: other_result_id)
|
89
102
|
#
|
@@ -92,32 +105,29 @@ module Stretchy
|
|
92
105
|
#
|
93
106
|
# @example Getting more like a document from a string
|
94
107
|
# query.more_like(like_text: 'puppies and kittens are great')
|
95
|
-
#
|
108
|
+
#
|
96
109
|
# @see https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-mlt-query.html Elasticsearch more-like-this query documentation
|
97
110
|
#
|
98
111
|
def more_like(params = {}, options = {})
|
99
112
|
query = Queries::MoreLikeThisQuery.new(params)
|
100
|
-
options
|
101
|
-
options[:should] = true if should?
|
102
|
-
|
103
|
-
base.add_query(query, options)
|
113
|
+
base.add_query(query, merge_state(options))
|
104
114
|
self
|
105
115
|
end
|
106
116
|
|
107
|
-
#
|
117
|
+
#
|
108
118
|
# Switches to inverted context. Matches applied here work the same way as
|
109
119
|
# {#initialize}, but returned documents must **not** match these filters.
|
110
|
-
#
|
120
|
+
#
|
111
121
|
# @overload not(params)
|
112
122
|
# @param [String] A string that must not be matched anywhere in the document
|
113
123
|
# @overload not(params)
|
114
124
|
# @param [Hash] A hash of fields and strings that must not be matched in those fields
|
115
|
-
#
|
125
|
+
#
|
116
126
|
# @return [MatchClause] inverted query state with match filters applied
|
117
|
-
#
|
127
|
+
#
|
118
128
|
# @example Inverted full-text
|
119
129
|
# query.match.not("hello")
|
120
|
-
#
|
130
|
+
#
|
121
131
|
# @example Inverted full-text matching for specific fields
|
122
132
|
# query.match.not(
|
123
133
|
# my_field: "not_match_1",
|
@@ -129,35 +139,35 @@ module Stretchy
|
|
129
139
|
self
|
130
140
|
end
|
131
141
|
|
132
|
-
#
|
142
|
+
#
|
133
143
|
# Switches to `should` context. Applies full-text matches
|
134
144
|
# that are not required, but boost the relevance score for
|
135
145
|
# matching documents.
|
136
|
-
#
|
146
|
+
#
|
137
147
|
# Can be chained with {#not}
|
138
|
-
#
|
148
|
+
#
|
139
149
|
# @overload should(params)
|
140
150
|
# @param [String] A string that should be matched anywhere in the document
|
141
151
|
# @overload should(params)
|
142
152
|
# @param [Hash] A hash of fields and strings that should be matched in those fields
|
143
|
-
#
|
153
|
+
#
|
144
154
|
# @return [MatchClause] query state with should filters added
|
145
|
-
#
|
155
|
+
#
|
146
156
|
# @example Should match with full-text
|
147
157
|
# query.match.should("anywhere")
|
148
|
-
#
|
158
|
+
#
|
149
159
|
# @example Should match specific fields
|
150
160
|
# query.match.should(
|
151
161
|
# field_one: "one",
|
152
162
|
# field_two: "two"
|
153
163
|
# )
|
154
|
-
#
|
164
|
+
#
|
155
165
|
# @example Should not match
|
156
166
|
# query.match.should.not(
|
157
167
|
# field_one: "one",
|
158
168
|
# field_two: "two"
|
159
169
|
# )
|
160
|
-
#
|
170
|
+
#
|
161
171
|
# @see http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-bool-query.html Elastic Docs - Bool Query
|
162
172
|
def should(params = {}, options = {})
|
163
173
|
@should = true
|
@@ -166,16 +176,16 @@ module Stretchy
|
|
166
176
|
self
|
167
177
|
end
|
168
178
|
|
169
|
-
#
|
179
|
+
#
|
170
180
|
# Converts this match context to a set of boosts
|
171
181
|
# to use in a {Stretchy::Queries::FunctionScoreQuery}
|
172
|
-
#
|
182
|
+
#
|
173
183
|
# @param weight = nil [Numeric] Weight of generated boost
|
174
|
-
#
|
184
|
+
#
|
175
185
|
# @return [Stretchy::Boosts::FilterBoost] boost containing these match parameters
|
176
186
|
def to_boost(weight = nil)
|
177
187
|
weight ||= Stretchy::Boosts::FilterBoost::DEFAULT_WEIGHT
|
178
|
-
|
188
|
+
|
179
189
|
Stretchy::Boosts::FilterBoost.new(
|
180
190
|
filter: Stretchy::Filters::QueryFilter.new(
|
181
191
|
base.match_builder.to_query
|
@@ -184,9 +194,9 @@ module Stretchy
|
|
184
194
|
)
|
185
195
|
end
|
186
196
|
|
187
|
-
#
|
197
|
+
#
|
188
198
|
# Accessor for `@should`
|
189
|
-
#
|
199
|
+
#
|
190
200
|
# @return [true, false] `@should`
|
191
201
|
def should?
|
192
202
|
!!@should
|
@@ -213,4 +223,4 @@ module Stretchy
|
|
213
223
|
|
214
224
|
end
|
215
225
|
end
|
216
|
-
end
|
226
|
+
end
|