Module: Searchkick

Defined in:
lib/searchkick.rb,
lib/searchkick/index.rb,
lib/searchkick/model.rb,
lib/searchkick/query.rb,
lib/searchkick/indexer.rb,
lib/searchkick/logging.rb,
lib/searchkick/results.rb,
lib/searchkick/version.rb,
lib/searchkick/middleware.rb,
lib/searchkick/record_data.rb,
lib/searchkick/bulk_indexer.rb,
lib/searchkick/hash_wrapper.rb,
lib/searchkick/multi_search.rb,
lib/searchkick/index_options.rb,
lib/searchkick/reindex_queue.rb,
lib/searchkick/record_indexer.rb,
lib/searchkick/reindex_v2_job.rb,
lib/searchkick/bulk_reindex_job.rb,
lib/searchkick/process_batch_job.rb,
lib/searchkick/process_queue_job.rb

Defined Under Namespace

Modules: ControllerRuntime, IndexWithInstrumentation, IndexerWithInstrumentation, Model, QueryWithInstrumentation, SearchkickWithInstrumentation Classes: BulkIndexer, BulkReindexJob, DangerousOperation, Error, HashWrapper, ImportError, Index, IndexOptions, Indexer, InvalidQueryError, LogSubscriber, Middleware, MissingIndexError, MultiSearch, ProcessBatchJob, ProcessQueueJob, Query, RecordData, RecordIndexer, ReindexQueue, ReindexV2Job, Results, UnsupportedVersionError

Constant Summary collapse

VERSION =
"4.4.2"

Class Attribute Summary collapse

Class Method Summary collapse

Class Attribute Details

.aws_credentialsObject

Returns the value of attribute aws_credentials.



44
45
46
# File 'lib/searchkick.rb', line 44

def aws_credentials
  @aws_credentials
end

.clientObject



54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/searchkick.rb', line 54

def self.client
  @client ||= begin
    require "typhoeus/adapters/faraday" if defined?(Typhoeus) && Gem::Version.new(Faraday::VERSION) < Gem::Version.new("0.14.0")

    Elasticsearch::Client.new({
      url: ENV["ELASTICSEARCH_URL"],
      transport_options: {request: {timeout: timeout}, headers: {content_type: "application/json"}},
      retry_on_failure: 2
    }.deep_merge(client_options)) do |f|
      f.use Searchkick::Middleware
      f.request signer_middleware_key, signer_middleware_aws_params if aws_credentials
    end
  end
end

.client_optionsObject

Returns the value of attribute client_options.



42
43
44
# File 'lib/searchkick.rb', line 42

def client_options
  @client_options
end

.envObject



69
70
71
# File 'lib/searchkick.rb', line 69

def self.env
  @env ||= ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development"
end

.index_prefixObject

Returns the value of attribute index_prefix.



42
43
44
# File 'lib/searchkick.rb', line 42

def index_prefix
  @index_prefix
end

.index_suffixObject

Returns the value of attribute index_suffix.



42
43
44
# File 'lib/searchkick.rb', line 42

def index_suffix
  @index_suffix
end

.model_optionsObject

Returns the value of attribute model_options.



42
43
44
# File 'lib/searchkick.rb', line 42

def model_options
  @model_options
end

.modelsObject

Returns the value of attribute models.



42
43
44
# File 'lib/searchkick.rb', line 42

def models
  @models
end

.queue_nameObject

Returns the value of attribute queue_name.



42
43
44
# File 'lib/searchkick.rb', line 42

def queue_name
  @queue_name
end

.redisObject

Returns the value of attribute redis.



42
43
44
# File 'lib/searchkick.rb', line 42

def redis
  @redis
end

.search_method_nameObject

Returns the value of attribute search_method_name.



42
43
44
# File 'lib/searchkick.rb', line 42

def search_method_name
  @search_method_name
end

.search_timeoutObject



73
74
75
# File 'lib/searchkick.rb', line 73

def self.search_timeout
  (defined?(@search_timeout) && @search_timeout) || timeout
end

.timeoutObject

Returns the value of attribute timeout.



42
43
44
# File 'lib/searchkick.rb', line 42

def timeout
  @timeout
end

.wordnet_pathObject

Returns the value of attribute wordnet_path.



42
43
44
# File 'lib/searchkick.rb', line 42

def wordnet_path
  @wordnet_path
end

Class Method Details

.callbacks(value = nil) ⇒ Object



149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
# File 'lib/searchkick.rb', line 149

def self.callbacks(value = nil)
  if block_given?
    previous_value = callbacks_value
    begin
      self.callbacks_value = value
      result = yield
      indexer.perform if callbacks_value == :bulk
      result
    ensure
      self.callbacks_value = previous_value
    end
  else
    self.callbacks_value = value
  end
end

.callbacks?(default: true) ⇒ Boolean

Returns:

  • (Boolean)


141
142
143
144
145
146
147
# File 'lib/searchkick.rb', line 141

def self.callbacks?(default: true)
  if callbacks_value.nil?
    default
  else
    callbacks_value != false
  end
end

.callbacks_valueObject

private



230
231
232
# File 'lib/searchkick.rb', line 230

def self.callbacks_value
  Thread.current[:searchkick_callbacks_enabled]
end

.callbacks_value=(value) ⇒ Object

private



235
236
237
# File 'lib/searchkick.rb', line 235

def self.callbacks_value=(value)
  Thread.current[:searchkick_callbacks_enabled] = value
end

.disable_callbacksObject



137
138
139
# File 'lib/searchkick.rb', line 137

def self.disable_callbacks
  self.callbacks_value = false
end

.enable_callbacksObject

callbacks



133
134
135
# File 'lib/searchkick.rb', line 133

def self.enable_callbacks
  self.callbacks_value = nil
end

.indexerObject

private



225
226
227
# File 'lib/searchkick.rb', line 225

def self.indexer
  Thread.current[:searchkick_indexer] ||= Searchkick::Indexer.new
end

.load_records(records, ids) ⇒ Object

private

Raises:



204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
# File 'lib/searchkick.rb', line 204

def self.load_records(records, ids)
  records =
    if records.respond_to?(:primary_key)
      # ActiveRecord
      records.where(records.primary_key => ids) if records.primary_key
    elsif records.respond_to?(:queryable)
      # Mongoid 3+
      records.queryable.for_ids(ids)
    elsif records.respond_to?(:unscoped) && :id.respond_to?(:in)
      # Nobrainer
      records.unscoped.where(:id.in => ids)
    elsif records.respond_to?(:key_column_names)
      records.where(records.key_column_names.first => ids)
    end

  raise Searchkick::Error, "Not sure how to load records" if !records

  records
end

.multi_search(queries) ⇒ Object



127
128
129
# File 'lib/searchkick.rb', line 127

def self.multi_search(queries)
  Searchkick::MultiSearch.new(queries).perform
end

.reindex_status(index_name) ⇒ Object

Raises:



176
177
178
179
180
181
182
183
184
# File 'lib/searchkick.rb', line 176

def self.reindex_status(index_name)
  raise Searchkick::Error, "Redis not configured" unless redis

  batches_left = Searchkick::Index.new(index_name).batches_left
  {
    completed: batches_left == 0,
    batches_left: batches_left
  }
end

.relation?(klass) ⇒ Boolean

private methods are forwarded to base class this check to see if scope exists on that class it’s a bit tricky, but this seems to work

Returns:

  • (Boolean)


261
262
263
264
265
266
267
# File 'lib/searchkick.rb', line 261

def self.relation?(klass)
  if klass.respond_to?(:current_scope)
    !klass.current_scope.nil?
  elsif defined?(Mongoid::Threaded)
    !Mongoid::Threaded.current_scope(klass).nil?
  end
end

.search(term = "*", model: nil, **options, &block) ⇒ Object



93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/searchkick.rb', line 93

def self.search(term = "*", model: nil, **options, &block)
  options = options.dup
  klass = model

  # convert index_name into models if possible
  # this should allow for easier upgrade
  if options[:index_name] && !options[:models] && Array(options[:index_name]).all? { |v| v.respond_to?(:searchkick_index) }
    options[:models] = options.delete(:index_name)
  end

  # make Searchkick.search(models: [Product]) and Product.search equivalent
  unless klass
    models = Array(options[:models])
    if models.size == 1
      klass = models.first
      options.delete(:models)
    end
  end

  if klass
    if (options[:models] && Array(options[:models]) != [klass]) || Array(options[:index_name]).any? { |v| v.respond_to?(:searchkick_index) && v != klass }
      raise ArgumentError, "Use Searchkick.search to search multiple models"
    end
  end

  options = options.merge(block: block) if block
  query = Searchkick::Query.new(klass, term, **options)
  if options[:execute] == false
    query
  else
    query.execute
  end
end

.server_below7?Boolean

memoize for performance

Returns:

  • (Boolean)


86
87
88
89
90
91
# File 'lib/searchkick.rb', line 86

def self.server_below7?
  unless defined?(@server_below7)
    @server_below7 = server_below?("7.0.0")
  end
  @server_below7
end

.server_below?(version) ⇒ Boolean

Returns:

  • (Boolean)


81
82
83
# File 'lib/searchkick.rb', line 81

def self.server_below?(version)
  Gem::Version.new(server_version.split("-")[0]) < Gem::Version.new(version.split("-")[0])
end

.server_versionObject



77
78
79
# File 'lib/searchkick.rb', line 77

def self.server_version
  @server_version ||= client.info["version"]["number"]
end

.signer_middleware_aws_paramsObject

private



245
246
247
248
249
250
251
252
253
254
255
# File 'lib/searchkick.rb', line 245

def self.signer_middleware_aws_params
  if signer_middleware_key == :aws_sigv4
    {service: "es", region: "us-east-1"}.merge(aws_credentials)
  else
    {
      credentials: aws_credentials[:credentials] || Aws::Credentials.new(aws_credentials[:access_key_id], aws_credentials[:secret_access_key]),
      service_name: "es",
      region: aws_credentials[:region] || "us-east-1"
    }
  end
end

.signer_middleware_keyObject

private



240
241
242
# File 'lib/searchkick.rb', line 240

def self.signer_middleware_key
  defined?(FaradayMiddleware::AwsSignersV4) ? :aws_signers_v4 : :aws_sigv4
end

.warn(message) ⇒ Object



199
200
201
# File 'lib/searchkick.rb', line 199

def self.warn(message)
  super("[searchkick] WARNING: #{message}")
end

.with_redisObject

TODO use ConnectionPool::Wrapper when redis is set so this is no longer needed



187
188
189
190
191
192
193
194
195
196
197
# File 'lib/searchkick.rb', line 187

def self.with_redis
  if redis
    if redis.respond_to?(:with)
      redis.with do |r|
        yield r
      end
    else
      yield redis
    end
  end
end