Commit 6088da6d735511fc411902899a18dfba159ed14d

Authored by Andrew Kane
1 parent 7b7a445f

Added retry_misspellings flag for backwards compatibility

lib/searchkick.rb
... ... @@ -102,10 +102,8 @@ module Searchkick
102 102 end
103 103 end
104 104  
105   - def self.multi_search(queries)
106   - search = Searchkick::MultiSearch.new(queries)
107   - search.perform
108   - search.queries
  105 + def self.multi_search(queries, retry_misspellings: false)
  106 + Searchkick::MultiSearch.new(queries, retry_misspellings: retry_misspellings).perform
109 107 end
110 108  
111 109 # callbacks
... ...
lib/searchkick/logging.rb
... ... @@ -129,7 +129,7 @@ module Searchkick
129 129 end
130 130  
131 131 module SearchkickWithInstrumentation
132   - def multi_search(searches)
  132 + def multi_search(searches, **options)
133 133 event = {
134 134 name: "Multi Search",
135 135 body: searches.flat_map { |q| [q.params.except(:body).to_json, q.body.to_json] }.map { |v| "#{v}\n" }.join
... ...
lib/searchkick/multi_search.rb
... ... @@ -2,34 +2,37 @@ module Searchkick
2 2 class MultiSearch
3 3 attr_reader :queries
4 4  
5   - def initialize(queries)
  5 + def initialize(queries, retry_misspellings: false)
6 6 @queries = queries
  7 + @retry_misspellings = retry_misspellings
7 8 end
8 9  
9 10 def perform
10 11 if queries.any?
11   - perform_search(queries)
  12 + perform_search(queries, retry_misspellings: @retry_misspellings)
12 13 end
13 14 end
14 15  
15 16 private
16 17  
17   - def perform_search(queries, retry_below_misspellings_threshold: true)
  18 + def perform_search(queries, retry_misspellings: true)
18 19 responses = client.msearch(body: queries.flat_map { |q| [q.params.except(:body), q.body] })["responses"]
19 20  
20   - queries_below_misspellings_threshold = []
  21 + retry_queries = []
21 22 queries.each_with_index do |query, i|
22   - if query.below_misspellings_threshold?(responses[i])
23   - query.prepare
24   - queries_below_misspellings_threshold << query
  23 + if retry_misspellings && query.retry_misspellings?(responses[i])
  24 + query.send(:prepare) # okay, since we don't want to expose this method outside Searchkick
  25 + retry_queries << query
25 26 else
26 27 query.handle_response(responses[i])
27 28 end
28 29 end
29 30  
30   - if retry_below_misspellings_threshold && queries_below_misspellings_threshold.any?
31   - perform_search(queries_below_misspellings_threshold, retry_below_misspellings_threshold: false)
  31 + if retry_misspellings && retry_queries.any?
  32 + perform_search(retry_queries, retry_misspellings: false)
32 33 end
  34 +
  35 + queries
33 36 end
34 37  
35 38 def client
... ...
lib/searchkick/query.rb
... ... @@ -4,7 +4,7 @@ module Searchkick
4 4  
5 5 @@metric_aggs = [:avg, :cardinality, :max, :min, :sum]
6 6  
7   - attr_reader :klass, :term, :options, :misspellings_below
  7 + attr_reader :klass, :term, :options
8 8 attr_accessor :body
9 9  
10 10 def_delegators :execute, :map, :each, :any?, :empty?, :size, :length, :slice, :[], :to_ary,
... ... @@ -79,7 +79,7 @@ module Searchkick
79 79 @execute ||= begin
80 80 begin
81 81 response = execute_search
82   - if below_misspellings_threshold?(response)
  82 + if retry_misspellings?(response)
83 83 prepare
84 84 response = execute_search
85 85 end
... ... @@ -159,10 +159,49 @@ module Searchkick
159 159 @execute = Searchkick::Results.new(searchkick_klass, response, opts)
160 160 end
161 161  
162   - def below_misspellings_threshold?(response)
  162 + def retry_misspellings?(response)
163 163 @misspellings_below && response["hits"]["total"] < @misspellings_below
164 164 end
165   -
  165 +
  166 + private
  167 +
  168 + def handle_error(e)
  169 + status_code = e.message[1..3].to_i
  170 + if status_code == 404
  171 + raise MissingIndexError, "Index missing - run #{reindex_command}"
  172 + elsif status_code == 500 && (
  173 + e.message.include?("IllegalArgumentException[minimumSimilarity >= 1]") ||
  174 + e.message.include?("No query registered for [multi_match]") ||
  175 + e.message.include?("[match] query does not support [cutoff_frequency]") ||
  176 + e.message.include?("No query registered for [function_score]")
  177 + )
  178 +
  179 + raise UnsupportedVersionError, "This version of Searchkick requires Elasticsearch 2 or greater"
  180 + elsif status_code == 400
  181 + if (
  182 + e.message.include?("bool query does not support [filter]") ||
  183 + e.message.include?("[bool] filter does not support [filter]")
  184 + )
  185 +
  186 + raise UnsupportedVersionError, "This version of Searchkick requires Elasticsearch 2 or greater"
  187 + elsif e.message.include?("[multi_match] analyzer [searchkick_search] not found")
  188 + raise InvalidQueryError, "Bad mapping - run #{reindex_command}"
  189 + else
  190 + raise InvalidQueryError, e.message
  191 + end
  192 + else
  193 + raise e
  194 + end
  195 + end
  196 +
  197 + def reindex_command
  198 + searchkick_klass ? "#{searchkick_klass.name}.reindex" : "reindex"
  199 + end
  200 +
  201 + def execute_search
  202 + Searchkick.client.search(params)
  203 + end
  204 +
166 205 def prepare
167 206 boost_fields, fields = set_fields
168 207  
... ... @@ -452,45 +491,6 @@ module Searchkick
452 491 @load = load
453 492 end
454 493  
455   - private
456   -
457   - def handle_error(e)
458   - status_code = e.message[1..3].to_i
459   - if status_code == 404
460   - raise MissingIndexError, "Index missing - run #{reindex_command}"
461   - elsif status_code == 500 && (
462   - e.message.include?("IllegalArgumentException[minimumSimilarity >= 1]") ||
463   - e.message.include?("No query registered for [multi_match]") ||
464   - e.message.include?("[match] query does not support [cutoff_frequency]") ||
465   - e.message.include?("No query registered for [function_score]")
466   - )
467   -
468   - raise UnsupportedVersionError, "This version of Searchkick requires Elasticsearch 2 or greater"
469   - elsif status_code == 400
470   - if (
471   - e.message.include?("bool query does not support [filter]") ||
472   - e.message.include?("[bool] filter does not support [filter]")
473   - )
474   -
475   - raise UnsupportedVersionError, "This version of Searchkick requires Elasticsearch 2 or greater"
476   - elsif e.message.include?("[multi_match] analyzer [searchkick_search] not found")
477   - raise InvalidQueryError, "Bad mapping - run #{reindex_command}"
478   - else
479   - raise InvalidQueryError, e.message
480   - end
481   - else
482   - raise e
483   - end
484   - end
485   -
486   - def reindex_command
487   - searchkick_klass ? "#{searchkick_klass.name}.reindex" : "reindex"
488   - end
489   -
490   - def execute_search
491   - Searchkick.client.search(params)
492   - end
493   -
494 494 def set_fields
495 495 boost_fields = {}
496 496 fields = options[:fields] || searchkick_options[:default_fields] || searchkick_options[:searchable]
... ...
test/multi_search_test.rb
... ... @@ -21,10 +21,16 @@ class MultiSearchTest &lt; Minitest::Test
21 21 end
22 22  
23 23 def test_misspellings_below_unmet
24   - store_names ["Product A"]
25   - store_names ["Store A"], Store
26   - stores = Store.search("Stre A", misspellings: { below: 2 }, execute: false)
27   - Searchkick.multi_search([stores])
28   - assert_equal ["Store A"], stores.map(&:name)
  24 + store_names ["abc", "abd", "aee"]
  25 + products = Product.search("abc", misspellings: {below: 2}, execute: false)
  26 + Searchkick.multi_search([products])
  27 + assert_equal ["abc"], products.map(&:name)
  28 + end
  29 +
  30 + def test_misspellings_below_unmet_retry
  31 + store_names ["abc", "abd", "aee"]
  32 + products = Product.search("abc", misspellings: {below: 2}, execute: false)
  33 + Searchkick.multi_search([products], retry_misspellings: true)
  34 + assert_equal ["abc", "abd"], products.map(&:name)
29 35 end
30 36 end
... ...