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



101
102
103
104
105
106
107
108
109
110
# File 'lib/searchkick/index.rb', line 101

def all_indices(unaliased: false)
  indices =
    begin
      client.indices.get_aliases
    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



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

def batches_left
  bulk_indexer.batches_left
end

#bulk_delete(records) ⇒ Object



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

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

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



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

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

#bulk_update(records, method_name) ⇒ Object



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

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

#clean_indicesObject

remove old indices that start w/ index_name



113
114
115
116
117
118
119
# File 'lib/searchkick/index.rb', line 113

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



230
231
232
233
234
235
# File 'lib/searchkick/index.rb', line 230

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



200
201
202
203
204
205
# File 'lib/searchkick/index.rb', line 200

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 !Searchkick.server_below?("6.0.0") && 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



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

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



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

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

#klass_document_type(klass, ignore_type = false) ⇒ Object

other



217
218
219
220
221
222
223
224
225
226
227
# File 'lib/searchkick/index.rb', line 217

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



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

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



181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
# File 'lib/searchkick/index.rb', line 181

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



175
176
177
# File 'lib/searchkick/index.rb', line 175

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

#remove(record) ⇒ Object



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

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

#retrieve(record) ⇒ Object



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

def retrieve(record)
  client.get(
    index: name,
    type: document_type(record),
    id: search_id(record)
  )["_source"]
end

#search_id(record) ⇒ Object



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

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



157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# File 'lib/searchkick/index.rb', line 157

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(" ")

  # TODO deep merge method
  options[:where] ||= {}
  options[:where][:_id] ||= {}
  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



124
125
126
# File 'lib/searchkick/index.rb', line 124

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

#suggest_fieldsObject



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

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
      }
    )

  response["hits"]["total"]
end

#update_record(record, method_name) ⇒ Object



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

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