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.5.0"

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



162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
# File 'lib/searchkick.rb', line 162

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)


154
155
156
157
158
159
160
# File 'lib/searchkick.rb', line 154

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

.callbacks_valueObject

private



243
244
245
# File 'lib/searchkick.rb', line 243

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

.callbacks_value=(value) ⇒ Object

private



248
249
250
# File 'lib/searchkick.rb', line 248

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

.disable_callbacksObject



150
151
152
# File 'lib/searchkick.rb', line 150

def self.disable_callbacks
  self.callbacks_value = false
end

.enable_callbacksObject

callbacks



146
147
148
# File 'lib/searchkick.rb', line 146

def self.enable_callbacks
  self.callbacks_value = nil
end

.indexerObject

private



238
239
240
# File 'lib/searchkick.rb', line 238

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

.load_records(records, ids) ⇒ Object

private

Raises:



217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
# File 'lib/searchkick.rb', line 217

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



140
141
142
# File 'lib/searchkick.rb', line 140

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

.opensearch?Boolean

Returns:

  • (Boolean)


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

def self.opensearch?
  unless defined?(@opensearch)
    @opensearch = server_info["version"]["distribution"] == "opensearch"
  end
  @opensearch
end

.reindex_status(index_name) ⇒ Object

Raises:



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

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)


274
275
276
277
278
279
280
# File 'lib/searchkick.rb', line 274

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



106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/searchkick.rb', line 106

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)


99
100
101
102
103
104
# File 'lib/searchkick.rb', line 99

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)


93
94
95
96
# File 'lib/searchkick.rb', line 93

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

.server_infoObject

private



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

def self.server_info
  @server_info ||= client.info
end

.server_versionObject



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

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

.signer_middleware_aws_paramsObject

private



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

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



253
254
255
# File 'lib/searchkick.rb', line 253

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

.warn(message) ⇒ Object



212
213
214
# File 'lib/searchkick.rb', line 212

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



200
201
202
203
204
205
206
207
208
209
210
# File 'lib/searchkick.rb', line 200

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