searchkick 1.5.1 → 2.0.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/.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
|