class Searchkick::Index
Attributes
name[R]
options[R]
Public Class Methods
new(name, options = {})
click to toggle source
# File lib/searchkick/index.rb, line 9 def initialize(name, options = {}) @name = name @options = options @klass_document_type = {} # cache end
Public Instance Methods
alias_exists?()
click to toggle source
# File lib/searchkick/index.rb, line 37 def alias_exists? client.indices.exists_alias name: name end
all_indices(unaliased: false)
click to toggle source
# 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_left()
click to toggle source
# File lib/searchkick/index.rb, line 211 def batches_left bulk_indexer.batches_left end
bulk_delete(records)
click to toggle source
# File lib/searchkick/index.rb, line 136 def bulk_delete(records) bulk_indexer.bulk_delete(records) end
bulk_index(records)
click to toggle source
# File lib/searchkick/index.rb, line 140 def bulk_index(records) bulk_indexer.bulk_index(records) end
Also aliased as: import
bulk_update(records, method_name)
click to toggle source
# File lib/searchkick/index.rb, line 145 def bulk_update(records, method_name) bulk_indexer.bulk_update(records, method_name) end
clean_indices()
click to toggle source
remove old indices that start w/ index_name
# 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_fields()
click to toggle source
should not be public
# 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 = {})
click to toggle source
# File lib/searchkick/index.rb, line 15 def create(body = {}) client.indices.create index: name, body: body end
create_index(index_options: nil)
click to toggle source
# 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
delete()
click to toggle source
# 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)
click to toggle source
# File lib/searchkick/index.rb, line 153 def document_type(record) RecordData.new(self, record).document_type end
exists?()
click to toggle source
# File lib/searchkick/index.rb, line 29 def exists? client.indices.exists index: name end
import_scope(relation, **options)
click to toggle source
# 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)
click to toggle source
other
# 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_fields()
click to toggle source
# 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
mapping()
click to toggle source
# File lib/searchkick/index.rb, line 41 def mapping client.indices.get_mapping index: name end
promote(new_name, update_refresh_interval: false)
click to toggle source
# 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
Also aliased as: swap
refresh()
click to toggle source
# File lib/searchkick/index.rb, line 33 def refresh client.indices.refresh index: name end
refresh_interval()
click to toggle source
# 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)
click to toggle source
reindex
# 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_queue()
click to toggle source
queue
# File lib/searchkick/index.rb, line 175 def reindex_queue Searchkick::ReindexQueue.new(name) end
remove(record)
click to toggle source
# File lib/searchkick/index.rb, line 128 def remove(record) bulk_indexer.bulk_delete([record]) end
retrieve(record)
click to toggle source
# 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)
click to toggle source
# File lib/searchkick/index.rb, line 149 def search_id(record) RecordData.new(self, record).search_id end
settings()
click to toggle source
# File lib/searchkick/index.rb, line 45 def settings client.indices.get_settings index: name end
similar_record(record, **options)
click to toggle source
# 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)
click to toggle source
record based use helpers for notifications
# File lib/searchkick/index.rb, line 124 def store(record) bulk_indexer.bulk_index([record]) end
suggest_fields()
click to toggle source
# File lib/searchkick/index.rb, line 237 def suggest_fields @suggest_fields ||= Array(options[:suggest]).map(&:to_s) end
tokens(text, options = {})
click to toggle source
# 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_docs()
click to toggle source
# 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)
click to toggle source
# File lib/searchkick/index.rb, line 132 def update_record(record, method_name) bulk_indexer.bulk_update([record], method_name) end
update_settings(settings)
click to toggle source
# File lib/searchkick/index.rb, line 53 def update_settings(settings) client.indices.put_settings index: name, body: settings end
Protected Instance Methods
bulk_indexer()
click to toggle source
# File lib/searchkick/index.rb, line 254 def bulk_indexer @bulk_indexer ||= BulkIndexer.new(self) end
client()
click to toggle source
# File lib/searchkick/index.rb, line 250 def client Searchkick.client end
reindex_scope(relation, import: true, resume: false, retain: false, async: false, refresh_interval: nil, scope: nil)
click to toggle source
gist.github.com/jarosan/3124884 www.elasticsearch.org/blog/changing-mapping-with-zero-downtime/
# File lib/searchkick/index.rb, line 260 def reindex_scope(relation, import: true, resume: false, retain: false, async: false, refresh_interval: nil, scope: nil) if resume index_name = all_indices.sort.last raise Searchkick::Error, "No index to resume" unless index_name index = Searchkick::Index.new(index_name, @options) else clean_indices unless retain index_options = relation.searchkick_index_options index_options.deep_merge!(settings: {index: {refresh_interval: refresh_interval}}) if refresh_interval index = create_index(index_options: index_options) end import_options = { resume: resume, async: async, full: true, scope: scope } # check if alias exists alias_exists = alias_exists? if alias_exists # import before promotion index.import_scope(relation, **import_options) if import # get existing indices to remove unless async promote(index.name, update_refresh_interval: !refresh_interval.nil?) clean_indices unless retain end else delete if exists? promote(index.name, update_refresh_interval: !refresh_interval.nil?) # import after promotion index.import_scope(relation, **import_options) if import end if async if async.is_a?(Hash) && async[:wait] puts "Created index: #{index.name}" puts "Jobs queued. Waiting..." loop do sleep 3 status = Searchkick.reindex_status(index.name) break if status[:completed] puts "Batches left: #{status[:batches_left]}" end # already promoted if alias didn't exist if alias_exists puts "Jobs complete. Promoting..." promote(index.name, update_refresh_interval: !refresh_interval.nil?) end clean_indices unless retain puts "SUCCESS!" end {index_name: index.name} else index.refresh true end rescue Elasticsearch::Transport::Transport::Errors::BadRequest => e if e.message.include?("No handler for type [text]") raise UnsupportedVersionError, "This version of Searchkick requires Elasticsearch 5 or greater" end raise e end