searchkick 4.4.0 → 5.3.1
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/CHANGELOG.md +160 -3
 - data/LICENSE.txt +1 -1
 - data/README.md +567 -421
 - data/lib/searchkick/bulk_reindex_job.rb +12 -8
 - data/lib/searchkick/controller_runtime.rb +40 -0
 - data/lib/searchkick/index.rb +167 -74
 - data/lib/searchkick/index_cache.rb +30 -0
 - data/lib/searchkick/index_options.rb +465 -404
 - data/lib/searchkick/indexer.rb +15 -8
 - data/lib/searchkick/log_subscriber.rb +57 -0
 - data/lib/searchkick/middleware.rb +9 -2
 - data/lib/searchkick/model.rb +50 -51
 - data/lib/searchkick/process_batch_job.rb +9 -25
 - data/lib/searchkick/process_queue_job.rb +4 -3
 - data/lib/searchkick/query.rb +106 -77
 - data/lib/searchkick/record_data.rb +1 -1
 - data/lib/searchkick/record_indexer.rb +136 -51
 - data/lib/searchkick/reindex_queue.rb +51 -9
 - data/lib/searchkick/reindex_v2_job.rb +10 -34
 - data/lib/searchkick/relation.rb +247 -0
 - data/lib/searchkick/relation_indexer.rb +155 -0
 - data/lib/searchkick/results.rb +131 -96
 - data/lib/searchkick/version.rb +1 -1
 - data/lib/searchkick/where.rb +11 -0
 - data/lib/searchkick.rb +202 -96
 - data/lib/tasks/searchkick.rake +14 -10
 - metadata +18 -85
 - data/CONTRIBUTING.md +0 -53
 - data/lib/searchkick/bulk_indexer.rb +0 -173
 - data/lib/searchkick/logging.rb +0 -246
 
    
        data/lib/searchkick/indexer.rb
    CHANGED
    
    | 
         @@ -1,3 +1,5 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # thread-local (technically fiber-local) indexer
         
     | 
| 
      
 2 
     | 
    
         
            +
            # used to aggregate bulk callbacks across models
         
     | 
| 
       1 
3 
     | 
    
         
             
            module Searchkick
         
     | 
| 
       2 
4 
     | 
    
         
             
              class Indexer
         
     | 
| 
       3 
5 
     | 
    
         
             
                attr_reader :queued_items
         
     | 
| 
         @@ -14,15 +16,20 @@ module Searchkick 
     | 
|
| 
       14 
16 
     | 
    
         
             
                def perform
         
     | 
| 
       15 
17 
     | 
    
         
             
                  items = @queued_items
         
     | 
| 
       16 
18 
     | 
    
         
             
                  @queued_items = []
         
     | 
| 
       17 
     | 
    
         
            -
             
     | 
| 
       18 
     | 
    
         
            -
             
     | 
| 
       19 
     | 
    
         
            -
             
     | 
| 
       20 
     | 
    
         
            -
             
     | 
| 
       21 
     | 
    
         
            -
             
     | 
| 
       22 
     | 
    
         
            -
             
     | 
| 
       23 
     | 
    
         
            -
             
     | 
| 
       24 
     | 
    
         
            -
             
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                  return if items.empty?
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                  response = Searchkick.client.bulk(body: items)
         
     | 
| 
      
 23 
     | 
    
         
            +
                  if response["errors"]
         
     | 
| 
      
 24 
     | 
    
         
            +
                    # note: delete does not set error when item not found
         
     | 
| 
      
 25 
     | 
    
         
            +
                    first_with_error = response["items"].map do |item|
         
     | 
| 
      
 26 
     | 
    
         
            +
                      (item["index"] || item["delete"] || item["update"])
         
     | 
| 
      
 27 
     | 
    
         
            +
                    end.find { |item| item["error"] }
         
     | 
| 
      
 28 
     | 
    
         
            +
                    raise ImportError, "#{first_with_error["error"]} on item with id '#{first_with_error["_id"]}'"
         
     | 
| 
       25 
29 
     | 
    
         
             
                  end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                  # maybe return response in future
         
     | 
| 
      
 32 
     | 
    
         
            +
                  nil
         
     | 
| 
       26 
33 
     | 
    
         
             
                end
         
     | 
| 
       27 
34 
     | 
    
         
             
              end
         
     | 
| 
       28 
35 
     | 
    
         
             
            end
         
     | 
| 
         @@ -0,0 +1,57 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # based on https://gist.github.com/mnutt/566725
         
     | 
| 
      
 2 
     | 
    
         
            +
            module Searchkick
         
     | 
| 
      
 3 
     | 
    
         
            +
              class LogSubscriber < ActiveSupport::LogSubscriber
         
     | 
| 
      
 4 
     | 
    
         
            +
                def self.runtime=(value)
         
     | 
| 
      
 5 
     | 
    
         
            +
                  Thread.current[:searchkick_runtime] = value
         
     | 
| 
      
 6 
     | 
    
         
            +
                end
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                def self.runtime
         
     | 
| 
      
 9 
     | 
    
         
            +
                  Thread.current[:searchkick_runtime] ||= 0
         
     | 
| 
      
 10 
     | 
    
         
            +
                end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                def self.reset_runtime
         
     | 
| 
      
 13 
     | 
    
         
            +
                  rt = runtime
         
     | 
| 
      
 14 
     | 
    
         
            +
                  self.runtime = 0
         
     | 
| 
      
 15 
     | 
    
         
            +
                  rt
         
     | 
| 
      
 16 
     | 
    
         
            +
                end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                def search(event)
         
     | 
| 
      
 19 
     | 
    
         
            +
                  self.class.runtime += event.duration
         
     | 
| 
      
 20 
     | 
    
         
            +
                  return unless logger.debug?
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                  payload = event.payload
         
     | 
| 
      
 23 
     | 
    
         
            +
                  name = "#{payload[:name]} (#{event.duration.round(1)}ms)"
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                  index = payload[:query][:index].is_a?(Array) ? payload[:query][:index].join(",") : payload[:query][:index]
         
     | 
| 
      
 26 
     | 
    
         
            +
                  type = payload[:query][:type]
         
     | 
| 
      
 27 
     | 
    
         
            +
                  request_params = payload[:query].except(:index, :type, :body)
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                  params = []
         
     | 
| 
      
 30 
     | 
    
         
            +
                  request_params.each do |k, v|
         
     | 
| 
      
 31 
     | 
    
         
            +
                    params << "#{CGI.escape(k.to_s)}=#{CGI.escape(v.to_s)}"
         
     | 
| 
      
 32 
     | 
    
         
            +
                  end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                  debug "  #{color(name, YELLOW, bold: true)}  #{index}#{type ? "/#{type.join(',')}" : ''}/_search#{params.any? ? '?' + params.join('&') : nil} #{payload[:query][:body].to_json}"
         
     | 
| 
      
 35 
     | 
    
         
            +
                end
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                def request(event)
         
     | 
| 
      
 38 
     | 
    
         
            +
                  self.class.runtime += event.duration
         
     | 
| 
      
 39 
     | 
    
         
            +
                  return unless logger.debug?
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                  payload = event.payload
         
     | 
| 
      
 42 
     | 
    
         
            +
                  name = "#{payload[:name]} (#{event.duration.round(1)}ms)"
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
                  debug "  #{color(name, YELLOW, bold: true)}  #{payload.except(:name).to_json}"
         
     | 
| 
      
 45 
     | 
    
         
            +
                end
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                def multi_search(event)
         
     | 
| 
      
 48 
     | 
    
         
            +
                  self.class.runtime += event.duration
         
     | 
| 
      
 49 
     | 
    
         
            +
                  return unless logger.debug?
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                  payload = event.payload
         
     | 
| 
      
 52 
     | 
    
         
            +
                  name = "#{payload[:name]} (#{event.duration.round(1)}ms)"
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
                  debug "  #{color(name, YELLOW, bold: true)}  _msearch #{payload[:body]}"
         
     | 
| 
      
 55 
     | 
    
         
            +
                end
         
     | 
| 
      
 56 
     | 
    
         
            +
              end
         
     | 
| 
      
 57 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -1,10 +1,17 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            require "faraday 
     | 
| 
      
 1 
     | 
    
         
            +
            require "faraday"
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            module Searchkick
         
     | 
| 
       4 
4 
     | 
    
         
             
              class Middleware < Faraday::Middleware
         
     | 
| 
       5 
5 
     | 
    
         
             
                def call(env)
         
     | 
| 
       6 
     | 
    
         
            -
                   
     | 
| 
      
 6 
     | 
    
         
            +
                  path = env[:url].path.to_s
         
     | 
| 
      
 7 
     | 
    
         
            +
                  if path.end_with?("/_search")
         
     | 
| 
       7 
8 
     | 
    
         
             
                    env[:request][:timeout] = Searchkick.search_timeout
         
     | 
| 
      
 9 
     | 
    
         
            +
                  elsif path.end_with?("/_msearch")
         
     | 
| 
      
 10 
     | 
    
         
            +
                    # assume no concurrent searches for timeout for now
         
     | 
| 
      
 11 
     | 
    
         
            +
                    searches = env[:request_body].count("\n") / 2
         
     | 
| 
      
 12 
     | 
    
         
            +
                    # do not allow timeout to exceed Searchkick.timeout
         
     | 
| 
      
 13 
     | 
    
         
            +
                    timeout = [Searchkick.search_timeout * searches, Searchkick.timeout].min
         
     | 
| 
      
 14 
     | 
    
         
            +
                    env[:request][:timeout] = timeout
         
     | 
| 
       8 
15 
     | 
    
         
             
                  end
         
     | 
| 
       9 
16 
     | 
    
         
             
                  @app.call(env)
         
     | 
| 
       10 
17 
     | 
    
         
             
                end
         
     | 
    
        data/lib/searchkick/model.rb
    CHANGED
    
    | 
         @@ -5,9 +5,9 @@ module Searchkick 
     | 
|
| 
       5 
5 
     | 
    
         | 
| 
       6 
6 
     | 
    
         
             
                  unknown_keywords = options.keys - [:_all, :_type, :batch_size, :callbacks, :case_sensitive, :conversions, :deep_paging, :default_fields,
         
     | 
| 
       7 
7 
     | 
    
         
             
                    :filterable, :geo_shape, :highlight, :ignore_above, :index_name, :index_prefix, :inheritance, :language,
         
     | 
| 
       8 
     | 
    
         
            -
                    :locations, :mappings, :match, :merge_mappings, :routing, :searchable, :search_synonyms, :settings, :similarity,
         
     | 
| 
       9 
     | 
    
         
            -
                    :special_characters, :stem, :stem_conversions, :suggest, :synonyms, :text_end,
         
     | 
| 
       10 
     | 
    
         
            -
                    :text_middle, :text_start, : 
     | 
| 
      
 8 
     | 
    
         
            +
                    :locations, :mappings, :match, :max_result_window, :merge_mappings, :routing, :searchable, :search_synonyms, :settings, :similarity,
         
     | 
| 
      
 9 
     | 
    
         
            +
                    :special_characters, :stem, :stemmer, :stem_conversions, :stem_exclusion, :stemmer_override, :suggest, :synonyms, :text_end,
         
     | 
| 
      
 10 
     | 
    
         
            +
                    :text_middle, :text_start, :unscope, :word, :word_end, :word_middle, :word_start]
         
     | 
| 
       11 
11 
     | 
    
         
             
                  raise ArgumentError, "unknown keywords: #{unknown_keywords.join(", ")}" if unknown_keywords.any?
         
     | 
| 
       12 
12 
     | 
    
         | 
| 
       13 
13 
     | 
    
         
             
                  raise "Only call searchkick once per model" if respond_to?(:searchkick_index)
         
     | 
| 
         @@ -22,52 +22,78 @@ module Searchkick 
     | 
|
| 
       22 
22 
     | 
    
         
             
                    raise ArgumentError, "Invalid value for callbacks"
         
     | 
| 
       23 
23 
     | 
    
         
             
                  end
         
     | 
| 
       24 
24 
     | 
    
         | 
| 
       25 
     | 
    
         
            -
                   
     | 
| 
       26 
     | 
    
         
            -
             
     | 
| 
       27 
     | 
    
         
            -
             
     | 
| 
       28 
     | 
    
         
            -
             
     | 
| 
       29 
     | 
    
         
            -
             
     | 
| 
       30 
     | 
    
         
            -
                     
     | 
| 
       31 
     | 
    
         
            -
                       
     | 
| 
       32 
     | 
    
         
            -
                    end
         
     | 
| 
      
 25 
     | 
    
         
            +
                  base = self
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                  mod = Module.new
         
     | 
| 
      
 28 
     | 
    
         
            +
                  include(mod)
         
     | 
| 
      
 29 
     | 
    
         
            +
                  mod.module_eval do
         
     | 
| 
      
 30 
     | 
    
         
            +
                    def reindex(method_name = nil, mode: nil, refresh: false)
         
     | 
| 
      
 31 
     | 
    
         
            +
                      self.class.searchkick_index.reindex([self], method_name: method_name, mode: mode, refresh: refresh, single: true)
         
     | 
| 
      
 32 
     | 
    
         
            +
                    end unless base.method_defined?(:reindex)
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                    def similar(**options)
         
     | 
| 
      
 35 
     | 
    
         
            +
                      self.class.searchkick_index.similar_record(self, **options)
         
     | 
| 
      
 36 
     | 
    
         
            +
                    end unless base.method_defined?(:similar)
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                    def search_data
         
     | 
| 
      
 39 
     | 
    
         
            +
                      data = respond_to?(:to_hash) ? to_hash : serializable_hash
         
     | 
| 
      
 40 
     | 
    
         
            +
                      data.delete("id")
         
     | 
| 
      
 41 
     | 
    
         
            +
                      data.delete("_id")
         
     | 
| 
      
 42 
     | 
    
         
            +
                      data.delete("_type")
         
     | 
| 
      
 43 
     | 
    
         
            +
                      data
         
     | 
| 
      
 44 
     | 
    
         
            +
                    end unless base.method_defined?(:search_data)
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                    def should_index?
         
     | 
| 
      
 47 
     | 
    
         
            +
                      true
         
     | 
| 
      
 48 
     | 
    
         
            +
                    end unless base.method_defined?(:should_index?)
         
     | 
| 
      
 49 
     | 
    
         
            +
                  end
         
     | 
| 
       33 
50 
     | 
    
         | 
| 
       34 
51 
     | 
    
         
             
                  class_eval do
         
     | 
| 
       35 
     | 
    
         
            -
                    cattr_reader :searchkick_options, :searchkick_klass
         
     | 
| 
      
 52 
     | 
    
         
            +
                    cattr_reader :searchkick_options, :searchkick_klass, instance_reader: false
         
     | 
| 
       36 
53 
     | 
    
         | 
| 
       37 
54 
     | 
    
         
             
                    class_variable_set :@@searchkick_options, options.dup
         
     | 
| 
       38 
55 
     | 
    
         
             
                    class_variable_set :@@searchkick_klass, self
         
     | 
| 
       39 
     | 
    
         
            -
                    class_variable_set :@@ 
     | 
| 
       40 
     | 
    
         
            -
                    class_variable_set :@@searchkick_index_cache, {}
         
     | 
| 
      
 56 
     | 
    
         
            +
                    class_variable_set :@@searchkick_index_cache, Searchkick::IndexCache.new
         
     | 
| 
       41 
57 
     | 
    
         | 
| 
       42 
58 
     | 
    
         
             
                    class << self
         
     | 
| 
       43 
59 
     | 
    
         
             
                      def searchkick_search(term = "*", **options, &block)
         
     | 
| 
       44 
     | 
    
         
            -
                         
     | 
| 
       45 
     | 
    
         
            -
             
     | 
| 
      
 60 
     | 
    
         
            +
                        if Searchkick.relation?(self)
         
     | 
| 
      
 61 
     | 
    
         
            +
                          raise Searchkick::Error, "search must be called on model, not relation"
         
     | 
| 
      
 62 
     | 
    
         
            +
                        end
         
     | 
| 
       46 
63 
     | 
    
         | 
| 
       47 
64 
     | 
    
         
             
                        Searchkick.search(term, model: self, **options, &block)
         
     | 
| 
       48 
65 
     | 
    
         
             
                      end
         
     | 
| 
       49 
66 
     | 
    
         
             
                      alias_method Searchkick.search_method_name, :searchkick_search if Searchkick.search_method_name
         
     | 
| 
       50 
67 
     | 
    
         | 
| 
       51 
68 
     | 
    
         
             
                      def searchkick_index(name: nil)
         
     | 
| 
       52 
     | 
    
         
            -
                         
     | 
| 
       53 
     | 
    
         
            -
                         
     | 
| 
      
 69 
     | 
    
         
            +
                        index_name = name || searchkick_klass.searchkick_index_name
         
     | 
| 
      
 70 
     | 
    
         
            +
                        index_name = index_name.call if index_name.respond_to?(:call)
         
     | 
| 
       54 
71 
     | 
    
         
             
                        index_cache = class_variable_get(:@@searchkick_index_cache)
         
     | 
| 
       55 
     | 
    
         
            -
                        index_cache 
     | 
| 
      
 72 
     | 
    
         
            +
                        index_cache.fetch(index_name) { Searchkick::Index.new(index_name, searchkick_options) }
         
     | 
| 
       56 
73 
     | 
    
         
             
                      end
         
     | 
| 
       57 
74 
     | 
    
         
             
                      alias_method :search_index, :searchkick_index unless method_defined?(:search_index)
         
     | 
| 
       58 
75 
     | 
    
         | 
| 
       59 
76 
     | 
    
         
             
                      def searchkick_reindex(method_name = nil, **options)
         
     | 
| 
       60 
     | 
    
         
            -
                         
     | 
| 
       61 
     | 
    
         
            -
                        relation = (respond_to?(:current_scope) && respond_to?(:default_scoped) && current_scope && current_scope.to_sql != default_scoped.to_sql) ||
         
     | 
| 
       62 
     | 
    
         
            -
                          (respond_to?(:queryable) && queryable != unscoped.with_default_scope)
         
     | 
| 
       63 
     | 
    
         
            -
             
     | 
| 
       64 
     | 
    
         
            -
                        searchkick_index.reindex(searchkick_klass, method_name, scoped: relation, **options)
         
     | 
| 
      
 77 
     | 
    
         
            +
                        searchkick_index.reindex(self, method_name: method_name, **options)
         
     | 
| 
       65 
78 
     | 
    
         
             
                      end
         
     | 
| 
       66 
79 
     | 
    
         
             
                      alias_method :reindex, :searchkick_reindex unless method_defined?(:reindex)
         
     | 
| 
       67 
80 
     | 
    
         | 
| 
       68 
81 
     | 
    
         
             
                      def searchkick_index_options
         
     | 
| 
       69 
82 
     | 
    
         
             
                        searchkick_index.index_options
         
     | 
| 
       70 
83 
     | 
    
         
             
                      end
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
                      def searchkick_index_name
         
     | 
| 
      
 86 
     | 
    
         
            +
                        @searchkick_index_name ||= begin
         
     | 
| 
      
 87 
     | 
    
         
            +
                          options = class_variable_get(:@@searchkick_options)
         
     | 
| 
      
 88 
     | 
    
         
            +
                          if options[:index_name]
         
     | 
| 
      
 89 
     | 
    
         
            +
                            options[:index_name]
         
     | 
| 
      
 90 
     | 
    
         
            +
                          elsif options[:index_prefix].respond_to?(:call)
         
     | 
| 
      
 91 
     | 
    
         
            +
                            -> { [options[:index_prefix].call, model_name.plural, Searchkick.env, Searchkick.index_suffix].compact.join("_") }
         
     | 
| 
      
 92 
     | 
    
         
            +
                          else
         
     | 
| 
      
 93 
     | 
    
         
            +
                            [options.key?(:index_prefix) ? options[:index_prefix] : Searchkick.index_prefix, model_name.plural, Searchkick.env, Searchkick.index_suffix].compact.join("_")
         
     | 
| 
      
 94 
     | 
    
         
            +
                          end
         
     | 
| 
      
 95 
     | 
    
         
            +
                        end
         
     | 
| 
      
 96 
     | 
    
         
            +
                      end
         
     | 
| 
       71 
97 
     | 
    
         
             
                    end
         
     | 
| 
       72 
98 
     | 
    
         | 
| 
       73 
99 
     | 
    
         
             
                    # always add callbacks, even when callbacks is false
         
     | 
| 
         @@ -78,33 +104,6 @@ module Searchkick 
     | 
|
| 
       78 
104 
     | 
    
         
             
                      after_save :reindex, if: -> { Searchkick.callbacks?(default: callbacks) }
         
     | 
| 
       79 
105 
     | 
    
         
             
                      after_destroy :reindex, if: -> { Searchkick.callbacks?(default: callbacks) }
         
     | 
| 
       80 
106 
     | 
    
         
             
                    end
         
     | 
| 
       81 
     | 
    
         
            -
             
     | 
| 
       82 
     | 
    
         
            -
                    def reindex(method_name = nil, **options)
         
     | 
| 
       83 
     | 
    
         
            -
                      RecordIndexer.new(self).reindex(method_name, **options)
         
     | 
| 
       84 
     | 
    
         
            -
                    end unless method_defined?(:reindex)
         
     | 
| 
       85 
     | 
    
         
            -
             
     | 
| 
       86 
     | 
    
         
            -
                    # TODO switch to keyword arguments
         
     | 
| 
       87 
     | 
    
         
            -
                    def similar(options = {})
         
     | 
| 
       88 
     | 
    
         
            -
                      self.class.searchkick_index.similar_record(self, **options)
         
     | 
| 
       89 
     | 
    
         
            -
                    end unless method_defined?(:similar)
         
     | 
| 
       90 
     | 
    
         
            -
             
     | 
| 
       91 
     | 
    
         
            -
                    def search_data
         
     | 
| 
       92 
     | 
    
         
            -
                      data = respond_to?(:to_hash) ? to_hash : serializable_hash
         
     | 
| 
       93 
     | 
    
         
            -
                      data.delete("id")
         
     | 
| 
       94 
     | 
    
         
            -
                      data.delete("_id")
         
     | 
| 
       95 
     | 
    
         
            -
                      data.delete("_type")
         
     | 
| 
       96 
     | 
    
         
            -
                      data
         
     | 
| 
       97 
     | 
    
         
            -
                    end unless method_defined?(:search_data)
         
     | 
| 
       98 
     | 
    
         
            -
             
     | 
| 
       99 
     | 
    
         
            -
                    def should_index?
         
     | 
| 
       100 
     | 
    
         
            -
                      true
         
     | 
| 
       101 
     | 
    
         
            -
                    end unless method_defined?(:should_index?)
         
     | 
| 
       102 
     | 
    
         
            -
             
     | 
| 
       103 
     | 
    
         
            -
                    if defined?(Cequel) && self < Cequel::Record && !method_defined?(:destroyed?)
         
     | 
| 
       104 
     | 
    
         
            -
                      def destroyed?
         
     | 
| 
       105 
     | 
    
         
            -
                        transient?
         
     | 
| 
       106 
     | 
    
         
            -
                      end
         
     | 
| 
       107 
     | 
    
         
            -
                    end
         
     | 
| 
       108 
107 
     | 
    
         
             
                  end
         
     | 
| 
       109 
108 
     | 
    
         
             
                end
         
     | 
| 
       110 
109 
     | 
    
         
             
              end
         
     | 
| 
         @@ -3,34 +3,18 @@ module Searchkick 
     | 
|
| 
       3 
3 
     | 
    
         
             
                queue_as { Searchkick.queue_name }
         
     | 
| 
       4 
4 
     | 
    
         | 
| 
       5 
5 
     | 
    
         
             
                def perform(class_name:, record_ids:, index_name: nil)
         
     | 
| 
       6 
     | 
    
         
            -
                   
     | 
| 
       7 
     | 
    
         
            -
                   
     | 
| 
       8 
     | 
    
         
            -
                  record_ids = routing.keys
         
     | 
| 
      
 6 
     | 
    
         
            +
                  model = Searchkick.load_model(class_name)
         
     | 
| 
      
 7 
     | 
    
         
            +
                  index = model.searchkick_index(name: index_name)
         
     | 
| 
       9 
8 
     | 
    
         | 
| 
       10 
     | 
    
         
            -
                   
     | 
| 
       11 
     | 
    
         
            -
             
     | 
| 
       12 
     | 
    
         
            -
             
     | 
| 
       13 
     | 
    
         
            -
             
     | 
| 
       14 
     | 
    
         
            -
             
     | 
| 
       15 
     | 
    
         
            -
                  # determine which records to delete
         
     | 
| 
       16 
     | 
    
         
            -
                  delete_ids = record_ids - records.map { |r| r.id.to_s }
         
     | 
| 
       17 
     | 
    
         
            -
                  delete_records = delete_ids.map do |id|
         
     | 
| 
       18 
     | 
    
         
            -
                    m = klass.new
         
     | 
| 
       19 
     | 
    
         
            -
                    m.id = id
         
     | 
| 
       20 
     | 
    
         
            -
                    if routing[id]
         
     | 
| 
       21 
     | 
    
         
            -
                      m.define_singleton_method(:search_routing) do
         
     | 
| 
       22 
     | 
    
         
            -
                        routing[id]
         
     | 
| 
       23 
     | 
    
         
            -
                      end
         
     | 
| 
      
 9 
     | 
    
         
            +
                  items =
         
     | 
| 
      
 10 
     | 
    
         
            +
                    record_ids.map do |r|
         
     | 
| 
      
 11 
     | 
    
         
            +
                      parts = r.split(/(?<!\|)\|(?!\|)/, 2)
         
     | 
| 
      
 12 
     | 
    
         
            +
                        .map { |v| v.gsub("||", "|") }
         
     | 
| 
      
 13 
     | 
    
         
            +
                      {id: parts[0], routing: parts[1]}
         
     | 
| 
       24 
14 
     | 
    
         
             
                    end
         
     | 
| 
       25 
     | 
    
         
            -
                    m
         
     | 
| 
       26 
     | 
    
         
            -
                  end
         
     | 
| 
       27 
15 
     | 
    
         | 
| 
       28 
     | 
    
         
            -
                   
     | 
| 
       29 
     | 
    
         
            -
                  index  
     | 
| 
       30 
     | 
    
         
            -
                  Searchkick.callbacks(:bulk) do
         
     | 
| 
       31 
     | 
    
         
            -
                    index.bulk_index(records) if records.any?
         
     | 
| 
       32 
     | 
    
         
            -
                    index.bulk_delete(delete_records) if delete_records.any?
         
     | 
| 
       33 
     | 
    
         
            -
                  end
         
     | 
| 
      
 16 
     | 
    
         
            +
                  relation = Searchkick.scope(model)
         
     | 
| 
      
 17 
     | 
    
         
            +
                  RecordIndexer.new(index).reindex_items(relation, items, method_name: nil)
         
     | 
| 
       34 
18 
     | 
    
         
             
                end
         
     | 
| 
       35 
19 
     | 
    
         
             
              end
         
     | 
| 
       36 
20 
     | 
    
         
             
            end
         
     | 
| 
         @@ -3,15 +3,16 @@ module Searchkick 
     | 
|
| 
       3 
3 
     | 
    
         
             
                queue_as { Searchkick.queue_name }
         
     | 
| 
       4 
4 
     | 
    
         | 
| 
       5 
5 
     | 
    
         
             
                def perform(class_name:, index_name: nil, inline: false)
         
     | 
| 
       6 
     | 
    
         
            -
                  model = class_name 
     | 
| 
      
 6 
     | 
    
         
            +
                  model = Searchkick.load_model(class_name)
         
     | 
| 
      
 7 
     | 
    
         
            +
                  index = model.searchkick_index(name: index_name)
         
     | 
| 
       7 
8 
     | 
    
         
             
                  limit = model.searchkick_options[:batch_size] || 1000
         
     | 
| 
       8 
9 
     | 
    
         | 
| 
       9 
10 
     | 
    
         
             
                  loop do
         
     | 
| 
       10 
     | 
    
         
            -
                    record_ids =  
     | 
| 
      
 11 
     | 
    
         
            +
                    record_ids = index.reindex_queue.reserve(limit: limit)
         
     | 
| 
       11 
12 
     | 
    
         
             
                    if record_ids.any?
         
     | 
| 
       12 
13 
     | 
    
         
             
                      batch_options = {
         
     | 
| 
       13 
14 
     | 
    
         
             
                        class_name: class_name,
         
     | 
| 
       14 
     | 
    
         
            -
                        record_ids: record_ids,
         
     | 
| 
      
 15 
     | 
    
         
            +
                        record_ids: record_ids.uniq,
         
     | 
| 
       15 
16 
     | 
    
         
             
                        index_name: index_name
         
     | 
| 
       16 
17 
     | 
    
         
             
                      }
         
     | 
| 
       17 
18 
     | 
    
         |