Module: ElasticSearchable::ActiveRecordExtensions::LocalMethods::ClassMethods

Defined in:
lib/elastic_searchable/active_record_extensions.rb

Constant Summary collapse

PER_PAGE_DEFAULT =
20

Instance Method Summary collapse

Instance Method Details

#after_index(*args, &block) ⇒ Object

Available callback method after indexing is complete called after the object is indexed in elasticsearch (optional) :on => :create/:update can be used to only fire callback when object is created or updated override default after_index callback definition to support :on option see ActiveRecord::Transactions::ClassMethods#after_commit for example



57
58
59
60
61
62
63
64
# File 'lib/elastic_searchable/active_record_extensions.rb', line 57

def after_index(*args, &block)
  options = args.last
  if options.is_a?(Hash) && options[:on]
    options[:if] = Array.wrap(options[:if])
    options[:if] << "self.index_lifecycle == :#{options[:on]}"
  end
  set_callback(:index, :after, *args, &block)
end

#create_mappingObject



168
169
170
171
# File 'lib/elastic_searchable/active_record_extensions.rb', line 168

def create_mapping
  return unless self.elastic_options[:mapping]
  ElasticSearchable.request :put, index_mapping_path('_mapping'), :json_body => {index_type => self.elastic_options[:mapping]}
end

#delete_id_from_index(id) ⇒ Object



175
176
177
178
179
# File 'lib/elastic_searchable/active_record_extensions.rb', line 175

def delete_id_from_index(id)
  ElasticSearchable.request :delete, index_mapping_path(id)
rescue ElasticSearchable::ElasticError => e
  ElasticSearchable.logger.warn e
end

#delete_mappingObject



162
163
164
# File 'lib/elastic_searchable/active_record_extensions.rb', line 162

def delete_mapping
  ElasticSearchable.request :delete, index_mapping_path
end

#index_mapping_path(action = nil) ⇒ Object

helper method to generate elasticsearch url for this object type



156
157
158
# File 'lib/elastic_searchable/active_record_extensions.rb', line 156

def index_mapping_path(action = nil)
  ElasticSearchable.request_path [index_type, action].compact.join('/')
end

#index_typeObject



151
152
153
# File 'lib/elastic_searchable/active_record_extensions.rb', line 151

def index_type
  self.elastic_options[:type] || self.table_name
end

#per_pageObject

default number of search results for this model can be overridden by implementing classes



68
69
70
# File 'lib/elastic_searchable/active_record_extensions.rb', line 68

def per_page
  PER_PAGE_DEFAULT
end

#reindex(options = {}) ⇒ Object

reindex all records using bulk api see www.elasticsearch.org/guide/reference/api/bulk.html options:

:scope - scope to use for looking up records to reindex. defaults to self (all)
:page - page/batch to begin indexing at. defaults to 1
:per_page - number of records to index per batch. defaults to 1000

TODO: move this to AREL relation to remove the options scope param



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/elastic_searchable/active_record_extensions.rb', line 80

def reindex(options = {})
  self.create_mapping
  options.reverse_merge! :page => 1, :per_page => 1000
  scope = options.delete(:scope) || self
  page = options[:page]
  per_page = options[:per_page]
  records = scope.limit(per_page).offset(per_page * (page -1)).all
  while records.any? do
    ElasticSearchable.logger.debug "reindexing batch ##{page}..."
    actions = []
    records.each do |record|
      next unless record.should_index?
      begin
        doc = ElasticSearchable.encode_json(record.as_json_for_index)
        actions << ElasticSearchable.encode_json({:index => {'_index' => ElasticSearchable.index_name, '_type' => index_type, '_id' => record.id}})
        actions << doc
      rescue => e
        ElasticSearchable.logger.warn "Unable to bulk index record: #{record.inspect} [#{e.message}]"
      end
    end
    begin
      ElasticSearchable.request(:put, '/_bulk', :body => "\n#{actions.join("\n")}\n") if actions.any?
    rescue ElasticError => e
      ElasticSearchable.logger.warn "Error indexing batch ##{page}: #{e.message}"
      ElasticSearchable.logger.warn e
    end

    page += 1
    records = scope.limit(per_page).offset(per_page* (page-1)).all
  end
end

#search(query, options = {}) ⇒ Object

search returns a will_paginate collection of ActiveRecord objects for the search results supported options: :page - page of results to search for :per_page - number of results per page

www.elasticsearch.com/docs/elasticsearch/rest_api/search/



118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/elastic_searchable/active_record_extensions.rb', line 118

def search(query, options = {})
  page = (options.delete(:page) || 1).to_i
  options[:fields] ||= '_id'
  options[:size] ||= per_page_for_search(options)
  options[:from] ||= options[:size] * (page - 1)
  options[:query] ||= if query.is_a?(Hash)
    query
  else
    {}.tap do |q|
      q[:query_string] = { :query => query }
      q[:query_string][:default_operator] = options.delete(:default_operator) if options.has_key?(:default_operator)
    end
  end
  query = {}
  case sort = options.delete(:sort)
  when Array,Hash
    options[:sort] = sort
  when String
    query[:sort] = sort
  end

  response = ElasticSearchable.request :get, index_mapping_path('_search'), :query => query, :json_body => options
  hits = response['hits']
  ids = hits['hits'].collect {|h| h['_id'].to_i }
  results = self.find(ids).sort_by {|result| ids.index(result.id) }

  results.each do |result|
    result.instance_variable_set '@hit', hits['hits'][ids.index(result.id)]
  end

  ElasticSearchable::Paginator.handler.new(results, page, options[:size], hits['total'])
end