Skip to content

Instantly share code, notes, and snippets.

@elvisgiv
Last active November 24, 2016 14:30
Show Gist options
  • Save elvisgiv/190fa83b8ba3c70af56ff65f50503540 to your computer and use it in GitHub Desktop.
Save elvisgiv/190fa83b8ba3c70af56ff65f50503540 to your computer and use it in GitHub Desktop.

Elasticsearch sort by id

По умолчанию elascticsearch (ES) НЕ индексирует (отдельно) и НЕ сортирует записи по полю _id. Значения для _id вытаскиваются из поля _uid

https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-id-field.html

Вместо этого он индексирует поле _uid, которое и содержит в себе информацию об _id и _type в виде {type}#{id}

https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-uid-field.html

Сортировка же по полю _uid является некорректной в виду того, что _id в нем является не integer, а string объектом.

Почитать о поле _type

https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-type-field.html

Дано

  1. модель, объекты которой должны бать отсортированы по id - LogDebug
  2. подключаемый к ней модуль с логикой индексации, поиска и сортировки elasticsearch - LogDebugElasticsearchSearchable

Решение

  1. так как мы хотим добавить в ES custom field sort_id, а кастомные поля не индексируются дефолтным колбэком ES, тогда in model add callbacks after_save and after_destroy
../app/models/log_dedug.rb

class LogDebug < ActiveRecord::Base
  self.table_name = "log_debug"
  ....
  ### search elasticsearch
  include LogDebugElasticsearchSearchable

  # add object, with filds who absent in DB, to elasticsearch
  after_save :es_update
  after_destroy :es_update
  ...
  # for indexing custom fields
  def es_update
    self.__elasticsearch__.index_document
  end
end
  1. in including module hasing default ES callback and add field to ES, which contain id in integer format
../app/models/concerns/log_debug_elasticsearch_searchable.rb

module LogDebugElasticsearchSearchable
  extend ActiveSupport::Concern

  included do
    include Elasticsearch::Model
    #include Elasticsearch::Model::Callbacks <--- хэшировать дефолтный коллбэк обязательно
    ...
    settings index: { number_of_shards: 1 } do
      mappings dynamic: 'true' do
        ...
        # for ES sorting by id
        indexes :sort_id,        :index    => :not_analyzed, :type => 'integer'
      end
    end
    
    def as_indexed_json(options={})
      attrs = {
          ...
          # for ES sorting by id
          :sort_id => self.id,
          }
      attrs.as_json
    end
   
    # block for search
    def self.search(asc_or_desc)
      ...
      #
      __elasticsearch__.search(
          {
            ...some query...
              sort: get_order(asc_or_desc)
          }
      )
    end
    ...
    def self.get_order(asc_or_desc)
      [{"sort_id" => {:order => asc_or_desc}}]
    end
  end
end
  1. для того, чтобы сделать index/reindex полей в ES, может быть выполнен следующий код
  ...
  def import_log_debug_index
    #
    LogDebug.__elasticsearch__.create_index! force: true
    LogDebug.__elasticsearch__.refresh_index!
    LogDebug.import(:force=>true, index: 'some_index')
  end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment