stretchy 0.4.6 → 0.4.7
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/.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
@@ -3,7 +3,7 @@ module Stretchy
|
|
3
3
|
# A Clause is the basic unit of Stretchy's chainable query syntax.
|
4
4
|
# Think of it as a state machine, with transitions between states
|
5
5
|
# being handled by methods that return another Clause. When you
|
6
|
-
# call the `where` method, it stores the params passed as an
|
6
|
+
# call the `where` method, it stores the params passed as an
|
7
7
|
# internal representation, to be compiled down to the Elastic query
|
8
8
|
# syntax, and returns a WhereClause. The WhereClause reflects the
|
9
9
|
# current state of the query, and gives you access to methods like
|
@@ -21,18 +21,18 @@ module Stretchy
|
|
21
21
|
delegate [:request, :response, :results, :ids, :hits, :query,
|
22
22
|
:took, :shards, :total, :max_score, :total_pages] => :query_results
|
23
23
|
delegate [:to_search] => :base
|
24
|
-
delegate [:where, :range, :geo, :terms, :not] => :build_where
|
25
|
-
delegate [:match, :fulltext, :more_like] => :build_match
|
24
|
+
delegate [:where, :range, :geo, :terms, :not, :filter] => :build_where
|
25
|
+
delegate [:match, :fulltext, :more_like, :query] => :build_match
|
26
26
|
|
27
27
|
#
|
28
28
|
# Generates a chainable query. The only required option for the
|
29
29
|
# first initialization is `:type` , which specifies what type
|
30
30
|
# to query on your index.
|
31
|
-
#
|
31
|
+
#
|
32
32
|
# @overload initialize(base_or_opts, params)
|
33
33
|
# @param base [Base] another clause to copy attributes from
|
34
34
|
# @param params [Hash] params to set on the new state
|
35
|
-
#
|
35
|
+
#
|
36
36
|
# @overload initialize(base_or_opts)
|
37
37
|
# @option base_or_opts [String] :index The Elastic index to query
|
38
38
|
# @option base_or_opts [String] :type The Lucene type to query on
|
@@ -49,7 +49,7 @@ module Stretchy
|
|
49
49
|
end
|
50
50
|
end
|
51
51
|
|
52
|
-
#
|
52
|
+
#
|
53
53
|
# Exits any state the query is in (boost, inverse, should, etc)
|
54
54
|
# and returns to the root query state. You can use this before
|
55
55
|
# calling `.where` or other overridden methods to ensure they
|
@@ -59,44 +59,44 @@ module Stretchy
|
|
59
59
|
# End-of-chain methods (such as `.boost.where.not()`) should
|
60
60
|
# always return to the root state, and state is not
|
61
61
|
# something you should have to think about.
|
62
|
-
#
|
62
|
+
#
|
63
63
|
# @return [Base] Continue the query chain from the root state
|
64
64
|
#
|
65
65
|
def root
|
66
66
|
Base.new(base)
|
67
67
|
end
|
68
68
|
|
69
|
-
#
|
69
|
+
#
|
70
70
|
# Sets how many results to return, similar to
|
71
71
|
# ActiveRecord's limit method.
|
72
|
-
#
|
72
|
+
#
|
73
73
|
# @see http://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-body.html Elastic Docs - Request Body Search
|
74
|
-
#
|
74
|
+
#
|
75
75
|
# @param num [Integer] How many results to return
|
76
|
-
#
|
76
|
+
#
|
77
77
|
# @return [self]
|
78
78
|
def limit(num)
|
79
79
|
base.limit = num
|
80
80
|
self
|
81
81
|
end
|
82
82
|
|
83
|
-
#
|
83
|
+
#
|
84
84
|
# Accessor for `@limit`
|
85
|
-
#
|
85
|
+
#
|
86
86
|
# @return [Integer] Value of `@limit`
|
87
87
|
def get_limit
|
88
88
|
base.limit
|
89
89
|
end
|
90
90
|
alias :limit_value :get_limit
|
91
91
|
|
92
|
-
#
|
92
|
+
#
|
93
93
|
# Sets the offset to start returning results at.
|
94
94
|
# Corresponds to Elastic's "from" parameter
|
95
|
-
#
|
95
|
+
#
|
96
96
|
# @param num [Integer] Offset for query
|
97
|
-
#
|
97
|
+
#
|
98
98
|
# @see http://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-body.html Elastic Docs - Request Body Search
|
99
|
-
#
|
99
|
+
#
|
100
100
|
# @return [self]
|
101
101
|
def offset(num)
|
102
102
|
base.offset = num
|
@@ -104,19 +104,19 @@ module Stretchy
|
|
104
104
|
end
|
105
105
|
alias :per_page :offset
|
106
106
|
|
107
|
-
#
|
107
|
+
#
|
108
108
|
# Accessor for `@offset`
|
109
|
-
#
|
109
|
+
#
|
110
110
|
# @return [Integer] Offset for query
|
111
111
|
def get_offset
|
112
112
|
base.offset
|
113
113
|
end
|
114
114
|
|
115
|
-
#
|
115
|
+
#
|
116
116
|
# Allows pagination via Kaminari-like accessor
|
117
117
|
# @param num [Integer] Page number. Natural numbers only, **this is not zero-indexed**
|
118
118
|
# @option per_page [Integer] :per_page (DEFAULT_LIMIT) Number of results per page
|
119
|
-
#
|
119
|
+
#
|
120
120
|
# @return [self] Allows continuing the query chain
|
121
121
|
def page(num, params = {})
|
122
122
|
base.limit = params[:limit] || params[:per_page] || get_limit
|
@@ -124,28 +124,28 @@ module Stretchy
|
|
124
124
|
self
|
125
125
|
end
|
126
126
|
|
127
|
-
#
|
127
|
+
#
|
128
128
|
# Accessor for current page
|
129
|
-
#
|
129
|
+
#
|
130
130
|
# @return [Integer] (offset / limit).ceil
|
131
131
|
def get_page
|
132
132
|
base.page
|
133
133
|
end
|
134
134
|
alias :current_page :get_page
|
135
135
|
|
136
|
-
#
|
136
|
+
#
|
137
137
|
# Select fields for Elasticsearch to return
|
138
|
-
#
|
139
|
-
# By default, Stretchy will return the entire _source
|
138
|
+
#
|
139
|
+
# By default, Stretchy will return the entire _source
|
140
140
|
# for each document. If you call `.fields` with no
|
141
141
|
# arguments or an empty array, Stretchy will pass
|
142
142
|
# an empty array and only the "_type" and "_id"
|
143
143
|
# fields will be returned.
|
144
|
-
#
|
144
|
+
#
|
145
145
|
# @see https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-fields.html Elastic Docs - Fields
|
146
|
-
#
|
146
|
+
#
|
147
147
|
# @param new_fields [Array] Fields elasticsearch should return
|
148
|
-
#
|
148
|
+
#
|
149
149
|
# @return [self] Allows continuing the query chain
|
150
150
|
def fields(*args)
|
151
151
|
base.fields ||= []
|
@@ -153,20 +153,20 @@ module Stretchy
|
|
153
153
|
self
|
154
154
|
end
|
155
155
|
|
156
|
-
#
|
156
|
+
#
|
157
157
|
# Accessor for fields Elasticsearch will return
|
158
|
-
#
|
158
|
+
#
|
159
159
|
# @return [Array] List of fields in the current query
|
160
160
|
def get_fields
|
161
161
|
base.fields
|
162
162
|
end
|
163
163
|
|
164
|
-
#
|
164
|
+
#
|
165
165
|
# Tells the search to explain the scoring
|
166
166
|
# mechanism for each document.
|
167
|
-
#
|
167
|
+
#
|
168
168
|
# @see http://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-explain.html Elastic Docs - Request Body Search (explain)
|
169
|
-
#
|
169
|
+
#
|
170
170
|
# @return [self] Allows continuing the query chain
|
171
171
|
def explain
|
172
172
|
base.explain = true
|
@@ -177,19 +177,19 @@ module Stretchy
|
|
177
177
|
!!base.explain
|
178
178
|
end
|
179
179
|
|
180
|
-
#
|
180
|
+
#
|
181
181
|
# Filter for documents that do not match the specified fields and values
|
182
|
-
#
|
182
|
+
#
|
183
183
|
# @overload not(params)
|
184
184
|
# @param [String] A string that must not be matched anywhere in the document
|
185
185
|
# @overload not(params)
|
186
186
|
# @param [Hash] A hash of fields and strings or terms that must not be matched in those fields
|
187
|
-
#
|
187
|
+
#
|
188
188
|
# @return [MatchClause, WhereClause] inverted query state with match filters applied
|
189
189
|
#
|
190
190
|
# @see {MatchClause#not}
|
191
191
|
# @see {WhereClause#not}
|
192
|
-
#
|
192
|
+
#
|
193
193
|
def not(params = {}, options = {})
|
194
194
|
if params.is_a?(String)
|
195
195
|
build_match.not(params, options)
|
@@ -198,42 +198,42 @@ module Stretchy
|
|
198
198
|
end
|
199
199
|
end
|
200
200
|
|
201
|
-
#
|
201
|
+
#
|
202
202
|
# Used for boosting the relevance score of
|
203
203
|
# search results. `match` and `where` clauses
|
204
204
|
# added after `boost` will be applied as
|
205
205
|
# boosting functions instead of filters
|
206
|
-
#
|
206
|
+
#
|
207
207
|
# @example Boost documents that match a filter
|
208
208
|
# query.boost.where('post.user_id' => current_user.id)
|
209
|
-
#
|
209
|
+
#
|
210
210
|
# @example Boost documents that match fulltext search
|
211
211
|
# query.boost.match('user search terms')
|
212
|
-
#
|
212
|
+
#
|
213
213
|
# @return [BoostClause] query in boost context
|
214
|
-
#
|
214
|
+
#
|
215
215
|
# @see http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-function-score-query.html Elastic Docs - Function Score Query
|
216
216
|
def boost
|
217
217
|
BoostClause.new(base)
|
218
218
|
end
|
219
219
|
|
220
|
-
#
|
220
|
+
#
|
221
221
|
# Adds filters in the `should` context. Operates just like
|
222
|
-
# {#where}, but these filters only serve to add to the
|
222
|
+
# {#where}, but these filters only serve to add to the
|
223
223
|
# relevance score of the returned documents, rather than
|
224
224
|
# being required to match.
|
225
|
-
#
|
225
|
+
#
|
226
226
|
# @overload should(params)
|
227
|
-
# @param [String] A string to match via full-text search
|
227
|
+
# @param [String] A string to match via full-text search
|
228
228
|
# anywhere in the document.
|
229
|
-
#
|
229
|
+
#
|
230
230
|
# @overload should(params)
|
231
231
|
# @param [Hash] Options to generate filters.
|
232
|
-
#
|
232
|
+
#
|
233
233
|
# @return [WhereClause] current query state with should clauses applied
|
234
|
-
#
|
234
|
+
#
|
235
235
|
# @see http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-bool-query.html Elastic Docs - Bool Query
|
236
|
-
#
|
236
|
+
#
|
237
237
|
# @see http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-bool-filter.html Elastic Docs - Bool Filter
|
238
238
|
def should(params = {}, options = {})
|
239
239
|
if params.is_a?(Hash)
|
@@ -243,11 +243,11 @@ module Stretchy
|
|
243
243
|
end
|
244
244
|
end
|
245
245
|
|
246
|
-
#
|
246
|
+
#
|
247
247
|
# Allows adding raw aggregation JSON to your
|
248
248
|
# query
|
249
249
|
# @param params = {} [Hash] JSON to aggregate on
|
250
|
-
#
|
250
|
+
#
|
251
251
|
# @return [self] Allows continuing the query chain
|
252
252
|
def aggregations(params = {})
|
253
253
|
base.aggregate_builder = base.aggregate_builder.merge(params)
|
@@ -260,19 +260,19 @@ module Stretchy
|
|
260
260
|
end
|
261
261
|
alias :get_aggs :get_aggregations
|
262
262
|
|
263
|
-
#
|
263
|
+
#
|
264
264
|
# Accessor for `@inverse`
|
265
|
-
#
|
265
|
+
#
|
266
266
|
# @return [true, false] If current context is inverse
|
267
267
|
def inverse?
|
268
268
|
!!@inverse
|
269
269
|
end
|
270
270
|
|
271
|
-
#
|
271
|
+
#
|
272
272
|
# The Results object for this query, which handles
|
273
273
|
# sending the search request and providing convienent
|
274
274
|
# accessors for the response.
|
275
|
-
#
|
275
|
+
#
|
276
276
|
# @return [Results::Base] The results returned from Elastic
|
277
277
|
def query_results
|
278
278
|
@query_results ||= Stretchy::Results::Base.new(base)
|
@@ -292,6 +292,12 @@ module Stretchy
|
|
292
292
|
params.is_a?(String) ? { '_all' => params } : params
|
293
293
|
end
|
294
294
|
|
295
|
+
def merge_state(options = {})
|
296
|
+
options[:should] = true if options[:should].nil? && should?
|
297
|
+
options[:inverse] = true if options[:inverse].nil? && inverse?
|
298
|
+
options
|
299
|
+
end
|
300
|
+
|
295
301
|
end
|
296
302
|
end
|
297
303
|
end
|
@@ -2,35 +2,35 @@ require 'stretchy/clauses/base'
|
|
2
2
|
|
3
3
|
module Stretchy
|
4
4
|
module Clauses
|
5
|
-
#
|
5
|
+
#
|
6
6
|
# A Boost clause encapsulates the boost query state. It
|
7
7
|
# basically says "the next where / range / match filter
|
8
8
|
# will be used to boost a document's score instead of
|
9
9
|
# selecting documents to return."
|
10
|
-
#
|
10
|
+
#
|
11
11
|
# Calling `.boost` by itself doesn't do anything, but
|
12
12
|
# the next method (`.near`, `.match`, etc) will specify
|
13
13
|
# a boost using the same syntax as other clauses. These
|
14
|
-
# methods take a `:weight` parameter specifying the weight
|
14
|
+
# methods take a `:weight` parameter specifying the weight
|
15
15
|
# to assign that boost.
|
16
|
-
#
|
16
|
+
#
|
17
17
|
# @author [atevans]
|
18
|
-
#
|
18
|
+
#
|
19
19
|
class BoostClause < Base
|
20
20
|
|
21
21
|
extend Forwardable
|
22
22
|
|
23
|
-
delegate [:geo, :range] => :where
|
24
|
-
delegate [:fulltext] => :match
|
23
|
+
delegate [:geo, :range, :filter] => :where
|
24
|
+
delegate [:fulltext, :query] => :match
|
25
25
|
|
26
|
-
#
|
26
|
+
#
|
27
27
|
# Changes query state to "match" in the context
|
28
28
|
# of boosting. Options here work the same way as
|
29
29
|
# {MatchClause#initialize}, but the combined query
|
30
30
|
# will be applied as a boost function.
|
31
|
-
#
|
31
|
+
#
|
32
32
|
# @param params = {} [Hash] params for full text matching
|
33
|
-
#
|
33
|
+
#
|
34
34
|
# @return [BoostMatchClause] query with boost match state
|
35
35
|
def match(params = {}, options = {})
|
36
36
|
clause = BoostMatchClause.new(base)
|
@@ -38,23 +38,21 @@ module Stretchy
|
|
38
38
|
clause
|
39
39
|
end
|
40
40
|
|
41
|
-
#
|
41
|
+
#
|
42
42
|
# Changes query state to "where" in the context
|
43
43
|
# of boosting. Works the same way as {WhereClause},
|
44
44
|
# but applies the generated filters as a boost
|
45
|
-
# function.
|
46
|
-
#
|
45
|
+
# function.
|
46
|
+
#
|
47
47
|
# @param params = {} [Hash] Filters to use in this boost.
|
48
|
-
#
|
48
|
+
#
|
49
49
|
# @return [BoostWhereClause] Query state with boost filters applied
|
50
|
-
#
|
50
|
+
#
|
51
51
|
def where(params = {}, options = {})
|
52
52
|
BoostWhereClause.new(base).boost_where(params, options)
|
53
53
|
end
|
54
|
-
alias :filter :where
|
55
54
|
|
56
|
-
|
57
|
-
#
|
55
|
+
#
|
58
56
|
# Adds a boost based on the value in the specified field.
|
59
57
|
# You can pass more than one field as arguments, and
|
60
58
|
# you can also pass the `factor` and `modifier` options
|
@@ -66,16 +64,16 @@ module Stretchy
|
|
66
64
|
#
|
67
65
|
# @example Adding two fields with options
|
68
66
|
# query = query.boost.field(:numeric_field, :other_field, factor: 7, modifier: :log2p)
|
69
|
-
#
|
67
|
+
#
|
70
68
|
# @param *args [Arguments] Fields to add to the document score
|
71
69
|
# @param options = {} [Hash] Options to pass to the field_value_factor boost
|
72
|
-
#
|
70
|
+
#
|
73
71
|
# @return [self] Query state with field boosts applied
|
74
72
|
#
|
75
73
|
# @see https://www.elastic.co/guide/en/elasticsearch/guide/current/boosting-by-popularity.html Elasticsearch guide on boosting by popularity
|
76
74
|
#
|
77
75
|
# @see https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-function-score-query.html#_field_value_factor Elasticsearch field value factor reference
|
78
|
-
#
|
76
|
+
#
|
79
77
|
def field(*args)
|
80
78
|
options = args.last.is_a?(Hash) ? args.pop : {}
|
81
79
|
args.each do |field|
|
@@ -88,18 +86,18 @@ module Stretchy
|
|
88
86
|
raise Errors::InvalidQueryError.new("Cannot call .not directly after boost - use .where.not or .match.not instead")
|
89
87
|
end
|
90
88
|
|
91
|
-
#
|
89
|
+
#
|
92
90
|
# Adds a {Boosts::FieldDecayBoost}, which boosts
|
93
|
-
# a search result based on how close it is to a
|
91
|
+
# a search result based on how close it is to a
|
94
92
|
# specified value. That value can be a date, time,
|
95
93
|
# number, or {Types::GeoPoint}
|
96
|
-
#
|
94
|
+
#
|
97
95
|
# Required:
|
98
|
-
#
|
96
|
+
#
|
99
97
|
# * `:field`
|
100
98
|
# * `:origin` or `:lat` & `:lng` combo
|
101
99
|
# * `:scale`
|
102
|
-
#
|
100
|
+
#
|
103
101
|
# @option params [Numeric] :field What field to check with this boost
|
104
102
|
# @option params [Date, Time, Numeric, Types::GeoPoint] :origin Boost score based on how close the field is to this value. Required unless {Types::GeoPoint} is present (:lat, :lng, etc)
|
105
103
|
# @option params [Numeric] :lat Latitude, for a geo point
|
@@ -109,10 +107,10 @@ module Stretchy
|
|
109
107
|
# @option params [Numeric] :longitude Longitude, for a geo point
|
110
108
|
# @option params [String] :scale When the field is this distance from origin, the boost will be multiplied by `:decay` . Default is 0.5, so when `:origin` is a geo point and `:scale` is '10mi', then this boost will be twice as much for a point at the origin as for one 10 miles away
|
111
109
|
# @option params [String] :offset Anything within this distance of the origin is boosted as if it were at the origin
|
112
|
-
# @option params [Symbol] :type (:gauss) What type of decay to use. One of `:linear`, `:exp`, or `:gauss`
|
110
|
+
# @option params [Symbol] :type (:gauss) What type of decay to use. One of `:linear`, `:exp`, or `:gauss`
|
113
111
|
# @option params [Numeric] :decay_amount (0.5) How much the boost falls off when it is `:scale` distance from `:origin`
|
114
112
|
# @option params [Numeric] :weight (1.2) How strongly to weight this boost compared to others
|
115
|
-
#
|
113
|
+
#
|
116
114
|
# @example Boost near a geo point
|
117
115
|
# query.boost.near(
|
118
116
|
# field: :coords,
|
@@ -121,14 +119,14 @@ module Stretchy
|
|
121
119
|
# lat: 33.3,
|
122
120
|
# lng: 28.2
|
123
121
|
# )
|
124
|
-
#
|
122
|
+
#
|
125
123
|
# @example Boost near a date
|
126
124
|
# query.boost.near(
|
127
125
|
# field: :published_at,
|
128
126
|
# origin: Time.now,
|
129
127
|
# scale: '3d'
|
130
128
|
# )
|
131
|
-
#
|
129
|
+
#
|
132
130
|
# @example Boost near a number (with params)
|
133
131
|
# query.boost.near(
|
134
132
|
# field: :followers,
|
@@ -139,9 +137,9 @@ module Stretchy
|
|
139
137
|
# decay: 0.75,
|
140
138
|
# weight: 10
|
141
139
|
# )
|
142
|
-
#
|
140
|
+
#
|
143
141
|
# @return [Base] Query with field decay filter added
|
144
|
-
#
|
142
|
+
#
|
145
143
|
# @see http://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-function-score-query.html Elastic Docs - Function Score Query
|
146
144
|
def near(params = {}, options = {})
|
147
145
|
if params[:lat] || params[:latitude] ||
|
@@ -154,61 +152,61 @@ module Stretchy
|
|
154
152
|
end
|
155
153
|
alias :geo :near
|
156
154
|
|
157
|
-
#
|
155
|
+
#
|
158
156
|
# Adds a {Boosts::RandomBoost} to the query, for slightly
|
159
157
|
# randomizing search results.
|
160
|
-
#
|
158
|
+
#
|
161
159
|
# @param seed [Numeric] The seed for the random value
|
162
160
|
# @param weight [Numeric] The weight for this random value
|
163
|
-
#
|
161
|
+
#
|
164
162
|
# @return [Base] Query with random boost applied
|
165
|
-
#
|
163
|
+
#
|
166
164
|
# @see http://www.elastic.co/guide/en/elasticsearch/guide/master/random-scoring.html Elastic Docs - Random Scoring
|
167
165
|
def random(*args)
|
168
166
|
base.boost_builder.functions << Stretchy::Boosts::RandomBoost.new(*args)
|
169
167
|
Base.new(base)
|
170
168
|
end
|
171
169
|
|
172
|
-
#
|
170
|
+
#
|
173
171
|
# Defines a global boost for all documents in the query
|
174
|
-
#
|
172
|
+
#
|
175
173
|
# @param num [Numeric] Boost to apply to the whole query
|
176
|
-
#
|
174
|
+
#
|
177
175
|
# @return [self] Boost context with overall boost applied
|
178
176
|
def all(num)
|
179
177
|
base.boost_builder.overall_boost = num
|
180
178
|
self
|
181
179
|
end
|
182
180
|
|
183
|
-
#
|
181
|
+
#
|
184
182
|
# The maximum boost that any document can have
|
185
|
-
#
|
183
|
+
#
|
186
184
|
# @param num [Numeric] Maximum score a document can have
|
187
|
-
#
|
185
|
+
#
|
188
186
|
# @return [self] Boost context with maximum score applied
|
189
187
|
def max(num)
|
190
188
|
base.boost_builder.max_boost = num
|
191
189
|
self
|
192
190
|
end
|
193
191
|
|
194
|
-
#
|
192
|
+
#
|
195
193
|
# Set scoring mode for when a document matches multiple
|
196
194
|
# boost functions.
|
197
|
-
#
|
195
|
+
#
|
198
196
|
# @param mode [Symbol] Score mode. Can be one of `multiply sum avg first max min`
|
199
|
-
#
|
197
|
+
#
|
200
198
|
# @return [self] Boost context with score mode applied
|
201
199
|
def score_mode(mode)
|
202
200
|
base.boost_builder.score_mode = mode
|
203
201
|
self
|
204
202
|
end
|
205
203
|
|
206
|
-
#
|
204
|
+
#
|
207
205
|
# Set boost mode for when a document matches multiple
|
208
206
|
# boost functions.
|
209
|
-
#
|
207
|
+
#
|
210
208
|
# @param mode [Symbol] Boost mode. Can be one of `multiply replace sum avg max min`
|
211
|
-
#
|
209
|
+
#
|
212
210
|
# @return [self] Boost context with boost mode applied
|
213
211
|
def boost_mode(mode)
|
214
212
|
base.boost_builder.boost_mode = mode
|
@@ -217,4 +215,4 @@ module Stretchy
|
|
217
215
|
|
218
216
|
end
|
219
217
|
end
|
220
|
-
end
|
218
|
+
end
|
@@ -2,40 +2,57 @@ require 'stretchy/clauses/boost_clause'
|
|
2
2
|
|
3
3
|
module Stretchy
|
4
4
|
module Clauses
|
5
|
-
#
|
5
|
+
#
|
6
6
|
# Boost documents that match a free-text query. Most
|
7
|
-
# options will be passed into {#initialize}, but you
|
7
|
+
# options will be passed into {#initialize}, but you
|
8
8
|
# can also chain `.not` onto it. Calling `.where` or
|
9
9
|
# `.match` from here will apply filters (*not boosts*)
|
10
10
|
# and return to the base state
|
11
|
-
#
|
11
|
+
#
|
12
12
|
# @author [atevans]
|
13
|
-
#
|
13
|
+
#
|
14
14
|
class BoostMatchClause < BoostClause
|
15
15
|
|
16
16
|
delegate [:range, :geo] => :where
|
17
17
|
|
18
|
-
#
|
18
|
+
#
|
19
19
|
# Switches to inverse context, and applies filters as inverse
|
20
20
|
# options (ie, documents that *do not* match the query will
|
21
21
|
# be boosted)
|
22
|
-
#
|
22
|
+
#
|
23
23
|
# @overload not(params)
|
24
24
|
# @param [String] String that must not match anywhere in the document
|
25
|
-
#
|
25
|
+
#
|
26
26
|
# @overload not(params)
|
27
27
|
# @param params [Hash] Fields and values that should not match in the document
|
28
|
-
#
|
28
|
+
#
|
29
29
|
# @return [BoostMatchClause] Query with inverse matching boost function applied
|
30
30
|
def not(params = {})
|
31
31
|
@inverse = true
|
32
32
|
match_function(hashify_params(params))
|
33
33
|
end
|
34
34
|
|
35
|
+
#
|
36
|
+
# Boosts documents that are returned by a Match query.
|
37
|
+
#
|
38
|
+
# @param [Hash] Parameters for the match query. See {MatchClause#match}
|
39
|
+
# @param [Hash] Options for Stretchy to determine behavior of this boost
|
40
|
+
#
|
41
|
+
# @return [BoostMatchClause] Query with boost match applied
|
35
42
|
def boost_match(params = {}, options = {})
|
36
43
|
match_function(hashify_params(params), options)
|
37
44
|
end
|
38
45
|
|
46
|
+
#
|
47
|
+
# Boosts documents according to how closely they match a given phrase.
|
48
|
+
# This acts similarly to {MatchClause#fulltext}, but only adds a boost,
|
49
|
+
# so it will not interfere with the query. For example, it will not
|
50
|
+
# filter out documents that don't match at least one term.
|
51
|
+
#
|
52
|
+
# @param [Hash] Parameters for the match query. See {MatchClause#match}
|
53
|
+
# @param [Hash] Options for Stretchy to determine behavior of this boost
|
54
|
+
#
|
55
|
+
# @return [Base] Query with boost match applied
|
39
56
|
def fulltext(params = {}, options = {})
|
40
57
|
_params = hashify_params(params)
|
41
58
|
weight = _params.delete(:weight) || options[:weight]
|
@@ -48,35 +65,51 @@ module Stretchy
|
|
48
65
|
Base.new(base)
|
49
66
|
end
|
50
67
|
|
51
|
-
#
|
68
|
+
#
|
69
|
+
# Boosts documents using a query with arbitrary json passed to the
|
70
|
+
# method. See {MatchClause#query}.
|
71
|
+
#
|
72
|
+
# @param [Hash] Arbitrary json to use as a query
|
73
|
+
# @param [Hash] Options for Stretchy to determine behavior of this boost
|
74
|
+
#
|
75
|
+
# @return [Base] Query with arbitrary json query boost added
|
76
|
+
def query(params = {}, options = {})
|
77
|
+
weight = params.delete(:weight) || options[:weight]
|
78
|
+
clause = MatchClause.new.query(params, options)
|
79
|
+
boost = clause.to_boost(weight)
|
80
|
+
base.boost_builder.add_boost(boost) if boost
|
81
|
+
Base.new(base)
|
82
|
+
end
|
83
|
+
|
84
|
+
#
|
52
85
|
# Returns to the base context; filters passed here
|
53
86
|
# will be used to filter documents.
|
54
|
-
#
|
87
|
+
#
|
55
88
|
# @example Returning to base context
|
56
89
|
# query.boost.match('string').where(other_field: 64)
|
57
|
-
#
|
90
|
+
#
|
58
91
|
# @example Staying in boost context
|
59
92
|
# query.boost.match('string').boost.where(other_field: 99)
|
60
|
-
#
|
93
|
+
#
|
61
94
|
# @see {WhereClause#initialize}
|
62
|
-
#
|
95
|
+
#
|
63
96
|
# @return [WhereClause] Query with where clause applied
|
64
97
|
def where(*args)
|
65
98
|
WhereClause.new(base).where(*args)
|
66
99
|
end
|
67
100
|
|
68
|
-
#
|
101
|
+
#
|
69
102
|
# Returns to the base context. Queries passed here
|
70
103
|
# will be used to filter documents.
|
71
|
-
#
|
104
|
+
#
|
72
105
|
# @example Returning to base context
|
73
106
|
# query.boost.match(message: 'curse word').match('username')
|
74
|
-
#
|
107
|
+
#
|
75
108
|
# @example Staying in boost context
|
76
109
|
# query.boost.match(message: 'happy word').boost.match('love')
|
77
|
-
#
|
110
|
+
#
|
78
111
|
# @see {MatchClause#initialize}
|
79
|
-
#
|
112
|
+
#
|
80
113
|
# @return [MatchClause] Base context with match queries applied
|
81
114
|
def match(*args)
|
82
115
|
MatchClause.new(base).match(*args)
|
@@ -94,4 +127,4 @@ module Stretchy
|
|
94
127
|
|
95
128
|
end
|
96
129
|
end
|
97
|
-
end
|
130
|
+
end
|