searchkick 1.5.1 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +0 -13
- data/CHANGELOG.md +15 -0
- data/README.md +21 -54
- data/lib/searchkick.rb +2 -3
- data/lib/searchkick/index.rb +12 -18
- data/lib/searchkick/index_options.rb +5 -25
- data/lib/searchkick/model.rb +25 -44
- data/lib/searchkick/query.rb +135 -297
- data/lib/searchkick/results.rb +0 -4
- data/lib/searchkick/version.rb +1 -1
- data/searchkick.gemspec +4 -4
- data/test/aggs_test.rb +2 -6
- data/test/autocomplete_test.rb +3 -3
- data/test/boost_test.rb +0 -22
- data/test/index_test.rb +6 -12
- data/test/inheritance_test.rb +2 -2
- data/test/match_test.rb +0 -3
- data/test/query_test.rb +1 -2
- data/test/reindex_test.rb +25 -0
- data/test/sql_test.rb +16 -64
- data/test/test_helper.rb +3 -38
- metadata +9 -14
- data/lib/searchkick/reindex_job.rb +0 -26
- data/test/dangerous_reindex_test.rb +0 -27
- data/test/facets_test.rb +0 -90
- data/test/reindex_job_test.rb +0 -31
data/lib/searchkick/query.rb
CHANGED
@@ -6,19 +6,21 @@ module Searchkick
|
|
6
6
|
attr_accessor :body
|
7
7
|
|
8
8
|
def_delegators :execute, :map, :each, :any?, :empty?, :size, :length, :slice, :[], :to_ary,
|
9
|
-
:records, :results, :suggestions, :each_with_hit, :with_details, :
|
9
|
+
:records, :results, :suggestions, :each_with_hit, :with_details, :aggregations, :aggs,
|
10
10
|
:took, :error, :model_name, :entry_name, :total_count, :total_entries,
|
11
11
|
:current_page, :per_page, :limit_value, :padding, :total_pages, :num_pages,
|
12
12
|
:offset_value, :offset, :previous_page, :prev_page, :next_page, :first_page?, :last_page?,
|
13
13
|
:out_of_range?, :hits, :response, :to_a, :first
|
14
14
|
|
15
|
-
def initialize(klass, term, options
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
15
|
+
def initialize(klass, term = "*", **options)
|
16
|
+
unknown_keywords = options.keys - [:aggs, :body, :body_options, :boost,
|
17
|
+
:boost_by, :boost_by_distance, :boost_where, :conversions, :debug, :emoji, :execute, :explain,
|
18
|
+
:fields, :highlight, :includes, :index_name, :indices_boost, :limit, :load,
|
19
|
+
:match, :misspellings, :offset, :operator, :order, :padding, :page, :per_page, :profile,
|
20
|
+
:request_params, :routing, :select, :similar, :smart_aggs, :suggest, :track, :type, :where]
|
21
|
+
raise ArgumentError, "unknown keywords: #{unknown_keywords.join(", ")}" if unknown_keywords.any?
|
22
|
+
|
23
|
+
term = term.to_s
|
22
24
|
|
23
25
|
if options[:emoji]
|
24
26
|
term = EmojiParser.parse_unicode(term) { |e| " #{e.name} " }.strip
|
@@ -97,21 +99,12 @@ module Searchkick
|
|
97
99
|
end
|
98
100
|
|
99
101
|
def handle_response(response)
|
100
|
-
# apply facet limit in client due to
|
101
|
-
# https://github.com/elasticsearch/elasticsearch/issues/1305
|
102
|
-
@facet_limits.each do |field, limit|
|
103
|
-
field = field.to_s
|
104
|
-
facet = response["facets"][field]
|
105
|
-
response["facets"][field]["terms"] = facet["terms"].first(limit)
|
106
|
-
response["facets"][field]["other"] = facet["total"] - facet["terms"].sum { |term| term["count"] }
|
107
|
-
end
|
108
|
-
|
109
102
|
opts = {
|
110
103
|
page: @page,
|
111
104
|
per_page: @per_page,
|
112
105
|
padding: @padding,
|
113
106
|
load: @load,
|
114
|
-
includes: options[:
|
107
|
+
includes: options[:includes],
|
115
108
|
json: !@json.nil?,
|
116
109
|
match_suffix: @match_suffix,
|
117
110
|
highlighted_fields: @highlighted_fields || []
|
@@ -171,13 +164,19 @@ module Searchkick
|
|
171
164
|
elsif status_code == 500 && (
|
172
165
|
e.message.include?("IllegalArgumentException[minimumSimilarity >= 1]") ||
|
173
166
|
e.message.include?("No query registered for [multi_match]") ||
|
174
|
-
e.message.include?("[match] query does not support [cutoff_frequency]
|
175
|
-
e.message.include?("No query registered for [function_score]
|
167
|
+
e.message.include?("[match] query does not support [cutoff_frequency]") ||
|
168
|
+
e.message.include?("No query registered for [function_score]")
|
176
169
|
)
|
177
170
|
|
178
|
-
raise UnsupportedVersionError, "This version of Searchkick requires Elasticsearch
|
171
|
+
raise UnsupportedVersionError, "This version of Searchkick requires Elasticsearch 2 or greater"
|
179
172
|
elsif status_code == 400
|
180
|
-
if
|
173
|
+
if (
|
174
|
+
e.message.include?("bool query does not support [filter]") ||
|
175
|
+
e.message.include?("[bool] filter does not support [filter]")
|
176
|
+
)
|
177
|
+
|
178
|
+
raise UnsupportedVersionError, "This version of Searchkick requires Elasticsearch 2 or greater"
|
179
|
+
elsif e.message.include?("[multi_match] analyzer [searchkick_search] not found")
|
181
180
|
raise InvalidQueryError, "Bad mapping - run #{reindex_command}"
|
182
181
|
else
|
183
182
|
raise InvalidQueryError, e.message
|
@@ -198,7 +197,7 @@ module Searchkick
|
|
198
197
|
def prepare
|
199
198
|
boost_fields, fields = set_fields
|
200
199
|
|
201
|
-
operator = options[:operator] ||
|
200
|
+
operator = options[:operator] || "and"
|
202
201
|
|
203
202
|
# pagination
|
204
203
|
page = [options[:page].to_i, 1].max
|
@@ -210,17 +209,14 @@ module Searchkick
|
|
210
209
|
load = options[:load].nil? ? true : options[:load]
|
211
210
|
|
212
211
|
conversions_fields = Array(options[:conversions] || searchkick_options[:conversions]).map(&:to_s)
|
213
|
-
personalize_field = searchkick_options[:personalize]
|
214
212
|
|
215
213
|
all = term == "*"
|
216
214
|
|
217
|
-
@json = options[:
|
215
|
+
@json = options[:body]
|
218
216
|
if @json
|
219
217
|
payload = @json
|
220
218
|
else
|
221
|
-
if options[:
|
222
|
-
payload = options[:query]
|
223
|
-
elsif options[:similar]
|
219
|
+
if options[:similar]
|
224
220
|
payload = {
|
225
221
|
more_like_this: {
|
226
222
|
fields: fields,
|
@@ -235,117 +231,98 @@ module Searchkick
|
|
235
231
|
match_all: {}
|
236
232
|
}
|
237
233
|
else
|
238
|
-
|
239
|
-
payload = {
|
240
|
-
multi_match: {
|
241
|
-
fields: fields,
|
242
|
-
query: term,
|
243
|
-
analyzer: "searchkick_autocomplete_search"
|
244
|
-
}
|
245
|
-
}
|
246
|
-
else
|
247
|
-
queries = []
|
234
|
+
queries = []
|
248
235
|
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
else
|
255
|
-
true
|
256
|
-
end
|
257
|
-
|
258
|
-
if misspellings.is_a?(Hash) && misspellings[:below] && !@misspellings_below
|
259
|
-
@misspellings_below = misspellings[:below].to_i
|
260
|
-
misspellings = false
|
236
|
+
misspellings =
|
237
|
+
if options.key?(:misspellings)
|
238
|
+
options[:misspellings]
|
239
|
+
else
|
240
|
+
true
|
261
241
|
end
|
262
242
|
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
{fuzzy_transpositions: misspellings[:transpositions]}
|
268
|
-
elsif below14?
|
269
|
-
{}
|
270
|
-
else
|
271
|
-
{fuzzy_transpositions: true}
|
272
|
-
end
|
273
|
-
prefix_length = (misspellings.is_a?(Hash) && misspellings[:prefix_length]) || 0
|
274
|
-
default_max_expansions = @misspellings_below ? 20 : 3
|
275
|
-
max_expansions = (misspellings.is_a?(Hash) && misspellings[:max_expansions]) || default_max_expansions
|
276
|
-
end
|
243
|
+
if misspellings.is_a?(Hash) && misspellings[:below] && !@misspellings_below
|
244
|
+
@misspellings_below = misspellings[:below].to_i
|
245
|
+
misspellings = false
|
246
|
+
end
|
277
247
|
|
278
|
-
|
279
|
-
|
248
|
+
if misspellings != false
|
249
|
+
edit_distance = (misspellings.is_a?(Hash) && (misspellings[:edit_distance] || misspellings[:distance])) || 1
|
250
|
+
transpositions =
|
251
|
+
if misspellings.is_a?(Hash) && misspellings.key?(:transpositions)
|
252
|
+
{fuzzy_transpositions: misspellings[:transpositions]}
|
253
|
+
else
|
254
|
+
{fuzzy_transpositions: true}
|
255
|
+
end
|
256
|
+
prefix_length = (misspellings.is_a?(Hash) && misspellings[:prefix_length]) || 0
|
257
|
+
default_max_expansions = @misspellings_below ? 20 : 3
|
258
|
+
max_expansions = (misspellings.is_a?(Hash) && misspellings[:max_expansions]) || default_max_expansions
|
259
|
+
end
|
280
260
|
|
281
|
-
|
282
|
-
|
283
|
-
query: term,
|
284
|
-
boost: 10 * factor
|
285
|
-
}
|
261
|
+
fields.each do |field|
|
262
|
+
qs = []
|
286
263
|
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
:match
|
293
|
-
end
|
264
|
+
factor = boost_fields[field] || 1
|
265
|
+
shared_options = {
|
266
|
+
query: term,
|
267
|
+
boost: 10 * factor
|
268
|
+
}
|
294
269
|
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
qs.concat [
|
300
|
-
shared_options.merge(analyzer: "searchkick_search"),
|
301
|
-
shared_options.merge(analyzer: "searchkick_search2")
|
302
|
-
]
|
303
|
-
elsif field.end_with?(".exact")
|
304
|
-
f = field.split(".")[0..-2].join(".")
|
305
|
-
queries << {match: {f => shared_options.merge(analyzer: "keyword")}}
|
270
|
+
match_type =
|
271
|
+
if field.end_with?(".phrase")
|
272
|
+
field = field.sub(/\.phrase\z/, ".analyzed")
|
273
|
+
:match_phrase
|
306
274
|
else
|
307
|
-
|
308
|
-
qs << shared_options.merge(analyzer: analyzer)
|
275
|
+
:match
|
309
276
|
end
|
310
277
|
|
311
|
-
|
312
|
-
|
313
|
-
|
278
|
+
shared_options[:operator] = operator if match_type == :match
|
279
|
+
|
280
|
+
if field == "_all" || field.end_with?(".analyzed")
|
281
|
+
shared_options[:cutoff_frequency] = 0.001 unless operator == "and" || misspellings == false
|
282
|
+
qs.concat [
|
283
|
+
shared_options.merge(analyzer: "searchkick_search"),
|
284
|
+
shared_options.merge(analyzer: "searchkick_search2")
|
285
|
+
]
|
286
|
+
elsif field.end_with?(".exact")
|
287
|
+
f = field.split(".")[0..-2].join(".")
|
288
|
+
queries << {match: {f => shared_options.merge(analyzer: "keyword")}}
|
289
|
+
else
|
290
|
+
analyzer = field =~ /\.word_(start|middle|end)\z/ ? "searchkick_word_search" : "searchkick_autocomplete_search"
|
291
|
+
qs << shared_options.merge(analyzer: analyzer)
|
292
|
+
end
|
314
293
|
|
315
|
-
|
316
|
-
|
317
|
-
queries << {
|
318
|
-
bool: {
|
319
|
-
must: {
|
320
|
-
bool: {
|
321
|
-
should: qs.map { |q| {match_type => {field => q}} }
|
322
|
-
}
|
323
|
-
},
|
324
|
-
should: {match_type => {field.sub(/\.word_(start|middle|end)\z/, ".analyzed") => qs.first}}
|
325
|
-
}
|
326
|
-
}
|
327
|
-
else
|
328
|
-
queries.concat(qs.map { |q| {match_type => {field => q}} })
|
329
|
-
end
|
294
|
+
if misspellings != false && match_type == :match
|
295
|
+
qs.concat qs.map { |q| q.except(:cutoff_frequency).merge(fuzziness: edit_distance, prefix_length: prefix_length, max_expansions: max_expansions, boost: factor).merge(transpositions) }
|
330
296
|
end
|
331
297
|
|
332
|
-
|
333
|
-
|
334
|
-
|
298
|
+
# boost exact matches more
|
299
|
+
if field =~ /\.word_(start|middle|end)\z/ && searchkick_options[:word] != false
|
300
|
+
queries << {
|
301
|
+
bool: {
|
302
|
+
must: {
|
303
|
+
bool: {
|
304
|
+
should: qs.map { |q| {match_type => {field => q}} }
|
305
|
+
}
|
306
|
+
},
|
307
|
+
should: {match_type => {field.sub(/\.word_(start|middle|end)\z/, ".analyzed") => qs.first}}
|
308
|
+
}
|
335
309
|
}
|
336
|
-
|
310
|
+
else
|
311
|
+
queries.concat(qs.map { |q| {match_type => {field => q}} })
|
312
|
+
end
|
337
313
|
end
|
338
314
|
|
315
|
+
payload = {
|
316
|
+
dis_max: {
|
317
|
+
queries: queries
|
318
|
+
}
|
319
|
+
}
|
320
|
+
|
339
321
|
if conversions_fields.present? && options[:conversions] != false
|
340
322
|
shoulds = []
|
341
323
|
conversions_fields.each do |conversions_field|
|
342
324
|
# wrap payload in a bool query
|
343
|
-
script_score =
|
344
|
-
if below12?
|
345
|
-
{script_score: {script: "doc['count'].value"}}
|
346
|
-
else
|
347
|
-
{field_value_factor: {field: "#{conversions_field}.count"}}
|
348
|
-
end
|
325
|
+
script_score = {field_value_factor: {field: "#{conversions_field}.count"}}
|
349
326
|
|
350
327
|
shoulds << {
|
351
328
|
nested: {
|
@@ -377,7 +354,7 @@ module Searchkick
|
|
377
354
|
multiply_filters = []
|
378
355
|
|
379
356
|
set_boost_by(multiply_filters, custom_filters)
|
380
|
-
set_boost_where(custom_filters
|
357
|
+
set_boost_where(custom_filters)
|
381
358
|
set_boost_by_distance(custom_filters) if options[:boost_by_distance]
|
382
359
|
|
383
360
|
if custom_filters.any?
|
@@ -418,9 +395,6 @@ module Searchkick
|
|
418
395
|
filters = where_filters(options[:where])
|
419
396
|
set_filters(payload, filters) if filters.any?
|
420
397
|
|
421
|
-
# facets
|
422
|
-
set_facets(payload) if options[:facets]
|
423
|
-
|
424
398
|
# aggregations
|
425
399
|
set_aggregations(payload) if options[:aggs]
|
426
400
|
|
@@ -437,25 +411,14 @@ module Searchkick
|
|
437
411
|
# doc for :select - http://www.elasticsearch.org/guide/reference/api/search/fields/
|
438
412
|
# doc for :select_v2 - https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-source-filtering.html
|
439
413
|
if options[:select]
|
440
|
-
|
441
|
-
elsif options[:select_v2]
|
442
|
-
if options[:select_v2] == []
|
414
|
+
if options[:select] == []
|
443
415
|
# intuitively [] makes sense to return no fields, but ES by default returns all fields
|
444
|
-
|
445
|
-
payload[:fields] = []
|
446
|
-
else
|
447
|
-
payload[:_source] = false
|
448
|
-
end
|
416
|
+
payload[:_source] = false
|
449
417
|
else
|
450
|
-
payload[:_source] = options[:
|
418
|
+
payload[:_source] = options[:select]
|
451
419
|
end
|
452
420
|
elsif load
|
453
|
-
|
454
|
-
if below50?
|
455
|
-
payload[:fields] = []
|
456
|
-
else
|
457
|
-
payload[:_source] = false
|
458
|
-
end
|
421
|
+
payload[:_source] = false
|
459
422
|
end
|
460
423
|
|
461
424
|
if options[:type] || (klass != searchkick_klass && searchkick_index)
|
@@ -470,7 +433,6 @@ module Searchkick
|
|
470
433
|
payload = payload.deep_merge(options[:body_options]) if options[:body_options]
|
471
434
|
|
472
435
|
@body = payload
|
473
|
-
@facet_limits ||= {}
|
474
436
|
@page = page
|
475
437
|
@per_page = per_page
|
476
438
|
@padding = padding
|
@@ -482,23 +444,15 @@ module Searchkick
|
|
482
444
|
fields = options[:fields] || searchkick_options[:searchable]
|
483
445
|
fields =
|
484
446
|
if fields
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
field = "#{k2}.#{v == :word ? 'analyzed' : v}"
|
492
|
-
boost_fields[field] = boost.to_f if boost
|
493
|
-
field
|
494
|
-
end
|
447
|
+
fields.map do |value|
|
448
|
+
k, v = value.is_a?(Hash) ? value.to_a.first : [value, options[:match] || searchkick_options[:match] || :word]
|
449
|
+
k2, boost = k.to_s.split("^", 2)
|
450
|
+
field = "#{k2}.#{v == :word ? 'analyzed' : v}"
|
451
|
+
boost_fields[field] = boost.to_f if boost
|
452
|
+
field
|
495
453
|
end
|
496
454
|
else
|
497
|
-
|
498
|
-
(searchkick_options[:autocomplete] || []).map { |f| "#{f}.autocomplete" }
|
499
|
-
else
|
500
|
-
["_all"]
|
501
|
-
end
|
455
|
+
["_all"]
|
502
456
|
end
|
503
457
|
[boost_fields, fields]
|
504
458
|
end
|
@@ -531,14 +485,8 @@ module Searchkick
|
|
531
485
|
multiply_filters.concat boost_filters(multiply_by || {})
|
532
486
|
end
|
533
487
|
|
534
|
-
def set_boost_where(custom_filters
|
488
|
+
def set_boost_where(custom_filters)
|
535
489
|
boost_where = options[:boost_where] || {}
|
536
|
-
if options[:user_id] && personalize_field
|
537
|
-
boost_where[personalize_field] = options[:user_id]
|
538
|
-
end
|
539
|
-
if options[:personalize]
|
540
|
-
boost_where = boost_where.merge(options[:personalize])
|
541
|
-
end
|
542
490
|
boost_where.each do |field, value|
|
543
491
|
if value.is_a?(Array) && value.first.is_a?(Hash)
|
544
492
|
value.each do |value_factor|
|
@@ -676,91 +624,21 @@ module Searchkick
|
|
676
624
|
end
|
677
625
|
end
|
678
626
|
|
679
|
-
def set_facets(payload)
|
680
|
-
facets = options[:facets] || {}
|
681
|
-
facets = Hash[facets.map { |f| [f, {}] }] if facets.is_a?(Array) # convert to more advanced syntax
|
682
|
-
facet_limits = {}
|
683
|
-
payload[:facets] = {}
|
684
|
-
|
685
|
-
facets.each do |field, facet_options|
|
686
|
-
# ask for extra facets due to
|
687
|
-
# https://github.com/elasticsearch/elasticsearch/issues/1305
|
688
|
-
size = facet_options[:limit] ? facet_options[:limit] + 150 : 1_000
|
689
|
-
|
690
|
-
if facet_options[:ranges]
|
691
|
-
payload[:facets][field] = {
|
692
|
-
range: {
|
693
|
-
field.to_sym => facet_options[:ranges]
|
694
|
-
}
|
695
|
-
}
|
696
|
-
elsif facet_options[:stats]
|
697
|
-
payload[:facets][field] = {
|
698
|
-
terms_stats: {
|
699
|
-
key_field: field,
|
700
|
-
value_script: below14? ? "doc.score" : "_score",
|
701
|
-
size: size
|
702
|
-
}
|
703
|
-
}
|
704
|
-
else
|
705
|
-
payload[:facets][field] = {
|
706
|
-
terms: {
|
707
|
-
field: facet_options[:field] || field,
|
708
|
-
size: size
|
709
|
-
}
|
710
|
-
}
|
711
|
-
end
|
712
|
-
|
713
|
-
facet_limits[field] = facet_options[:limit] if facet_options[:limit]
|
714
|
-
|
715
|
-
# offset is not possible
|
716
|
-
# http://elasticsearch-users.115913.n3.nabble.com/Is-pagination-possible-in-termsStatsFacet-td3422943.html
|
717
|
-
|
718
|
-
facet_options.deep_merge!(where: options.fetch(:where, {}).reject { |k| k == field }) if options[:smart_facets] == true
|
719
|
-
facet_filters = where_filters(facet_options[:where])
|
720
|
-
if facet_filters.any?
|
721
|
-
payload[:facets][field][:facet_filter] = {
|
722
|
-
and: {
|
723
|
-
filters: facet_filters
|
724
|
-
}
|
725
|
-
}
|
726
|
-
end
|
727
|
-
end
|
728
|
-
|
729
|
-
@facet_limits = facet_limits
|
730
|
-
end
|
731
|
-
|
732
627
|
def set_filters(payload, filters)
|
733
|
-
if options[:
|
734
|
-
|
735
|
-
|
736
|
-
|
628
|
+
if options[:aggs]
|
629
|
+
payload[:post_filter] = {
|
630
|
+
bool: {
|
631
|
+
filter: filters
|
737
632
|
}
|
738
|
-
|
739
|
-
payload[:post_filter] = {
|
740
|
-
bool: {
|
741
|
-
filter: filters
|
742
|
-
}
|
743
|
-
}
|
744
|
-
end
|
633
|
+
}
|
745
634
|
else
|
746
|
-
# more efficient query if no
|
747
|
-
|
748
|
-
|
749
|
-
|
750
|
-
|
751
|
-
filter: {
|
752
|
-
and: filters
|
753
|
-
}
|
754
|
-
}
|
635
|
+
# more efficient query if no aggs
|
636
|
+
payload[:query] = {
|
637
|
+
bool: {
|
638
|
+
must: payload[:query],
|
639
|
+
filter: filters
|
755
640
|
}
|
756
|
-
|
757
|
-
payload[:query] = {
|
758
|
-
bool: {
|
759
|
-
must: payload[:query],
|
760
|
-
filter: filters
|
761
|
-
}
|
762
|
-
}
|
763
|
-
end
|
641
|
+
}
|
764
642
|
end
|
765
643
|
end
|
766
644
|
|
@@ -778,30 +656,14 @@ module Searchkick
|
|
778
656
|
|
779
657
|
if field == :or
|
780
658
|
value.each do |or_clause|
|
781
|
-
|
782
|
-
filters << {or: or_clause.map { |or_statement| {and: where_filters(or_statement)} }}
|
783
|
-
else
|
784
|
-
filters << {bool: {should: or_clause.map { |or_statement| {bool: {filter: where_filters(or_statement)}} }}}
|
785
|
-
end
|
659
|
+
filters << {bool: {should: or_clause.map { |or_statement| {bool: {filter: where_filters(or_statement)}} }}}
|
786
660
|
end
|
787
661
|
elsif field == :_or
|
788
|
-
|
789
|
-
filters << {or: value.map { |or_statement| {and: where_filters(or_statement)} }}
|
790
|
-
else
|
791
|
-
filters << {bool: {should: value.map { |or_statement| {bool: {filter: where_filters(or_statement)}} }}}
|
792
|
-
end
|
662
|
+
filters << {bool: {should: value.map { |or_statement| {bool: {filter: where_filters(or_statement)}} }}}
|
793
663
|
elsif field == :_not
|
794
|
-
|
795
|
-
filters << {not: {and: where_filters(value)}}
|
796
|
-
else
|
797
|
-
filters << {bool: {must_not: where_filters(value)}}
|
798
|
-
end
|
664
|
+
filters << {bool: {must_not: where_filters(value)}}
|
799
665
|
elsif field == :_and
|
800
|
-
|
801
|
-
filters << {and: value.map { |or_statement| {and: where_filters(or_statement)} }}
|
802
|
-
else
|
803
|
-
filters << {bool: {must: value.map { |or_statement| {bool: {filter: where_filters(or_statement)}} }}}
|
804
|
-
end
|
666
|
+
filters << {bool: {must: value.map { |or_statement| {bool: {filter: where_filters(or_statement)}} }}}
|
805
667
|
else
|
806
668
|
# expand ranges
|
807
669
|
if value.is_a?(Range)
|
@@ -851,11 +713,7 @@ module Searchkick
|
|
851
713
|
when :regexp # support for regexp queries without using a regexp ruby object
|
852
714
|
filters << {regexp: {field => {value: op_value}}}
|
853
715
|
when :not # not equal
|
854
|
-
|
855
|
-
filters << {not: {filter: term_filters(field, op_value)}}
|
856
|
-
else
|
857
|
-
filters << {bool: {must_not: term_filters(field, op_value)}}
|
858
|
-
end
|
716
|
+
filters << {bool: {must_not: term_filters(field, op_value)}}
|
859
717
|
when :all
|
860
718
|
op_value.each do |val|
|
861
719
|
filters << term_filters(field, val)
|
@@ -895,20 +753,12 @@ module Searchkick
|
|
895
753
|
def term_filters(field, value)
|
896
754
|
if value.is_a?(Array) # in query
|
897
755
|
if value.any?(&:nil?)
|
898
|
-
|
899
|
-
{or: [term_filters(field, nil), term_filters(field, value.compact)]}
|
900
|
-
else
|
901
|
-
{bool: {should: [term_filters(field, nil), term_filters(field, value.compact)]}}
|
902
|
-
end
|
756
|
+
{bool: {should: [term_filters(field, nil), term_filters(field, value.compact)]}}
|
903
757
|
else
|
904
758
|
{in: {field => value}}
|
905
759
|
end
|
906
760
|
elsif value.nil?
|
907
|
-
|
908
|
-
{missing: {field: field, existence: true, null_value: true}}
|
909
|
-
else
|
910
|
-
{bool: {must_not: {exists: {field: field}}}}
|
911
|
-
end
|
761
|
+
{bool: {must_not: {exists: {field: field}}}}
|
912
762
|
elsif value.is_a?(Regexp)
|
913
763
|
{regexp: {field => {value: value.source}}}
|
914
764
|
else
|
@@ -936,13 +786,13 @@ module Searchkick
|
|
936
786
|
boost_by.map do |field, value|
|
937
787
|
log = value.key?(:log) ? value[:log] : options[:log]
|
938
788
|
value[:factor] ||= 1
|
939
|
-
script_score =
|
940
|
-
|
941
|
-
|
942
|
-
|
943
|
-
|
944
|
-
|
945
|
-
|
789
|
+
script_score = {
|
790
|
+
field_value_factor: {
|
791
|
+
field: field,
|
792
|
+
factor: value[:factor].to_f,
|
793
|
+
modifier: log ? "ln2p" : nil
|
794
|
+
}
|
795
|
+
}
|
946
796
|
|
947
797
|
{
|
948
798
|
filter: {
|
@@ -961,7 +811,7 @@ module Searchkick
|
|
961
811
|
if value.is_a?(Hash)
|
962
812
|
[value[:lon], value[:lat]]
|
963
813
|
elsif value.is_a?(Array) and !value[0].is_a?(Numeric)
|
964
|
-
value.map {|a| coordinate_array(a) }
|
814
|
+
value.map { |a| coordinate_array(a) }
|
965
815
|
else
|
966
816
|
value
|
967
817
|
end
|
@@ -975,18 +825,6 @@ module Searchkick
|
|
975
825
|
end
|
976
826
|
end
|
977
827
|
|
978
|
-
def below12?
|
979
|
-
Searchkick.server_below?("1.2.0")
|
980
|
-
end
|
981
|
-
|
982
|
-
def below14?
|
983
|
-
Searchkick.server_below?("1.4.0")
|
984
|
-
end
|
985
|
-
|
986
|
-
def below20?
|
987
|
-
Searchkick.server_below?("2.0.0")
|
988
|
-
end
|
989
|
-
|
990
828
|
def below50?
|
991
829
|
Searchkick.server_below?("5.0.0-alpha1")
|
992
830
|
end
|