Class: Searchkick::Index

Inherits:
Object
  • Object
show all
Includes:
IndexOptions, IndexWithInstrumentation
Defined in:
lib/searchkick/index.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from IndexOptions

#index_options

Constructor Details

#initialize(name, options = {}) ⇒ Index

Returns a new instance of Index.



9
10
11
12
13
# File 'lib/searchkick/index.rb', line 9

def initialize(name, options = {})
  @name = name
  @options = options
  @klass_document_type = {} # cache
end

Instance Attribute Details

#nameObject (readonly)

Returns the value of attribute name.



7
8
9
# File 'lib/searchkick/index.rb', line 7

def name
  @name
end

#optionsObject (readonly)

Returns the value of attribute options.



7
8
9
# File 'lib/searchkick/index.rb', line 7

def options
  @options
end

Instance Method Details

#alias_exists?Boolean

Returns:

  • (Boolean)


37
38
39
# File 'lib/searchkick/index.rb', line 37

def alias_exists?
  client.indices.exists_alias name: name
end

#all_indices(unaliased: false) ⇒ Object



102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/searchkick/index.rb', line 102

def all_indices(unaliased: false)
  indices =
    begin
      if client.indices.respond_to?(:get_alias)
        client.indices.get_alias
      else
        client.indices.get_aliases
      end
    rescue Elasticsearch::Transport::Transport::Errors::NotFound
      {}
    end
  indices = indices.select { |_k, v| v.empty? || v["aliases"].empty? } if unaliased
  indices.select { |k, _v| k =~ /\A#{Regexp.escape(name)}_\d{14,17}\z/ }.keys
end

#batches_leftObject



215
216
217
# File 'lib/searchkick/index.rb', line 215

def batches_left
  bulk_indexer.batches_left
end

#bulk_delete(records) ⇒ Object



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

def bulk_delete(records)
  bulk_indexer.bulk_delete(records)
end

#bulk_index(records) ⇒ Object Also known as: import



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

def bulk_index(records)
  bulk_indexer.bulk_index(records)
end

#bulk_update(records, method_name) ⇒ Object



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

def bulk_update(records, method_name)
  bulk_indexer.bulk_update(records, method_name)
end

#clean_indicesObject

remove old indices that start w/ index_name



118
119
120
121
122
123
124
# File 'lib/searchkick/index.rb', line 118

def clean_indices
  indices = all_indices(unaliased: true)
  indices.each do |index|
    Searchkick::Index.new(index).delete
  end
  indices
end

#conversions_fieldsObject

should not be public



234
235
236
237
238
239
# File 'lib/searchkick/index.rb', line 234

def conversions_fields
  @conversions_fields ||= begin
    conversions = Array(options[:conversions])
    conversions.map(&:to_s) + conversions.map(&:to_sym)
  end
end

#create(body = {}) ⇒ Object



15
16
17
# File 'lib/searchkick/index.rb', line 15

def create(body = {})
  client.indices.create index: name, body: body
end

#create_index(index_options: nil) ⇒ Object



204
205
206
207
208
209
# File 'lib/searchkick/index.rb', line 204

def create_index(index_options: nil)
  index_options ||= self.index_options
  index = Searchkick::Index.new("#{name}_#{Time.now.strftime('%Y%m%d%H%M%S%L')}", @options)
  index.create(index_options)
  index
end

#deleteObject



19
20
21
22
23
24
25
26
27
# File 'lib/searchkick/index.rb', line 19

def delete
  if alias_exists?
    # can't call delete directly on aliases in ES 6
    indices = client.indices.get_alias(name: name).keys
    client.indices.delete index: indices
  else
    client.indices.delete index: name
  end
end

#document_type(record) ⇒ Object



158
159
160
# File 'lib/searchkick/index.rb', line 158

def document_type(record)
  RecordData.new(self, record).document_type
end

#exists?Boolean

Returns:

  • (Boolean)


29
30
31
# File 'lib/searchkick/index.rb', line 29

def exists?
  client.indices.exists index: name
end

#import_scope(relation, **options) ⇒ Object



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

def import_scope(relation, **options)
  bulk_indexer.import_scope(relation, **options)
end

#klass_document_type(klass, ignore_type = false) ⇒ Object

other



221
222
223
224
225
226
227
228
229
230
231
# File 'lib/searchkick/index.rb', line 221

def klass_document_type(klass, ignore_type = false)
  @klass_document_type[[klass, ignore_type]] ||= begin
    if !ignore_type && klass.searchkick_klass.searchkick_options[:_type]
      type = klass.searchkick_klass.searchkick_options[:_type]
      type = type.call if type.respond_to?(:call)
      type
    else
      klass.model_name.to_s.underscore
    end
  end
end

#locations_fieldsObject



245
246
247
248
249
250
# File 'lib/searchkick/index.rb', line 245

def locations_fields
  @locations_fields ||= begin
    locations = Array(options[:locations])
    locations.map(&:to_s) + locations.map(&:to_sym)
  end
end

#mappingObject



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

def mapping
  client.indices.get_mapping index: name
end

#promote(new_name, update_refresh_interval: false) ⇒ Object Also known as: swap



74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/searchkick/index.rb', line 74

def promote(new_name, update_refresh_interval: false)
  if update_refresh_interval
    new_index = Searchkick::Index.new(new_name, @options)
    settings = options[:settings] || {}
    refresh_interval = (settings[:index] && settings[:index][:refresh_interval]) || "1s"
    new_index.update_settings(index: {refresh_interval: refresh_interval})
  end

  old_indices =
    begin
      client.indices.get_alias(name: name).keys
    rescue Elasticsearch::Transport::Transport::Errors::NotFound
      {}
    end
  actions = old_indices.map { |old_name| {remove: {index: old_name, alias: name}} } + [{add: {index: new_name, alias: name}}]
  client.indices.update_aliases body: {actions: actions}
end

#refreshObject



33
34
35
# File 'lib/searchkick/index.rb', line 33

def refresh
  client.indices.refresh index: name
end

#refresh_intervalObject



49
50
51
# File 'lib/searchkick/index.rb', line 49

def refresh_interval
  settings.values.first["settings"]["index"]["refresh_interval"]
end

#reindex(relation, method_name, scoped:, full: false, scope: nil, **options) ⇒ Object

reindex



185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
# File 'lib/searchkick/index.rb', line 185

def reindex(relation, method_name, scoped:, full: false, scope: nil, **options)
  refresh = options.fetch(:refresh, !scoped)

  if method_name
    # update
    import_scope(relation, method_name: method_name, scope: scope)
    self.refresh if refresh
    true
  elsif scoped && !full
    # reindex association
    import_scope(relation, scope: scope)
    self.refresh if refresh
    true
  else
    # full reindex
    reindex_scope(relation, scope: scope, **options)
  end
end

#reindex_queueObject

queue



179
180
181
# File 'lib/searchkick/index.rb', line 179

def reindex_queue
  Searchkick::ReindexQueue.new(name)
end

#remove(record) ⇒ Object



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

def remove(record)
  bulk_indexer.bulk_delete([record])
end

#retrieve(record) ⇒ Object



93
94
95
96
97
98
99
100
# File 'lib/searchkick/index.rb', line 93

def retrieve(record)
  record_data = RecordData.new(self, record).record_data

  # remove underscore
  get_options = Hash[record_data.map { |k, v| [k.to_s.sub(/\A_/, "").to_sym, v] }]

  client.get(get_options)["_source"]
end

#search_id(record) ⇒ Object



154
155
156
# File 'lib/searchkick/index.rb', line 154

def search_id(record)
  RecordData.new(self, record).search_id
end

#settingsObject



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

def settings
  client.indices.get_settings index: name
end

#similar_record(record, **options) ⇒ Object



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

def similar_record(record, **options)
  like_text = retrieve(record).to_hash
    .keep_if { |k, _| !options[:fields] || options[:fields].map(&:to_s).include?(k) }
    .values.compact.join(" ")

  options[:where] ||= {}
  options[:where][:_id] ||= {}
  options[:where][:_id][:not] = Array(options[:where][:_id][:not]) + [record.id.to_s]
  options[:per_page] ||= 10
  options[:similar] = true

  # TODO use index class instead of record class
  Searchkick.search(like_text, model: record.class, **options)
end

#store(record) ⇒ Object

record based use helpers for notifications



129
130
131
# File 'lib/searchkick/index.rb', line 129

def store(record)
  bulk_indexer.bulk_index([record])
end

#suggest_fieldsObject



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

def suggest_fields
  @suggest_fields ||= Array(options[:suggest]).map(&:to_s)
end

#tokens(text, options = {}) ⇒ Object



57
58
59
# File 'lib/searchkick/index.rb', line 57

def tokens(text, options = {})
  client.indices.analyze(body: {text: text}.merge(options), index: name)["tokens"].map { |t| t["token"] }
end

#total_docsObject



61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/searchkick/index.rb', line 61

def total_docs
  response =
    client.search(
      index: name,
      body: {
        query: {match_all: {}},
        size: 0
      }
    )

  Searchkick::Results.new(nil, response).total_count
end

#update_record(record, method_name) ⇒ Object



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

def update_record(record, method_name)
  bulk_indexer.bulk_update([record], method_name)
end

#update_settings(settings) ⇒ Object



53
54
55
# File 'lib/searchkick/index.rb', line 53

def update_settings(settings)
  client.indices.put_settings index: name, body: settings
end