Индексировать результаты метода в ElasticSearch (Tire + ActiveRecord)

Я индексирую набор данных для elasticsearch, используя Tire и ActiveRecord. У меня есть модель Artist, в которой has_many :images. Как я могу проиндексировать метод модели Artist, который возвращает определенное изображение? Или, альтернативно, сослаться на метод связанной модели? Мой желаемый результат Artist будет включать пути для основного изображения, связанного с Artist (как оригинал, так и миниатюра).

Я пробовал это сопоставление:

mapping do
  indexes :id,                  :index    => :not_analyzed
  indexes :name                     
  indexes :url
  indexes :primary_image_original       
  indexes :primary_image_thumbnail
end

для ссылки на эти методы Artist:

    def primary_image_original  
        return images.where(:priority => 'primary').first.original
    end

    def primary_image_thumbnail
        return images.where(:priority => 'primary').first.thumbnail_150
    end

Это просто игнорирует индексированные методы. На основе других ответов, таких как Elasticsearch, Tire и вложенные запросы/ассоциации с ActiveRecord, я пробовал это:

mapping do
  indexes :id,                  :index    => :not_analyzed
  indexes :name 
  indexes :url
  indexes :images do
    indexes :original
    indexes :thumbnail_150
    indexes :priority
  end
end

def to_indexed_json
    to_json(include: { images: { only: [:original, :thumbnail_150, :priority] } } )
end

Но это также не возвращает то, что мне нужно. Я потратил несколько часов на гугление и чтение документации elasticsearch и Tire и не нашел рабочего примера этого шаблона. Спасибо за ваши идеи!


person johnny.rodgers    schedule 28.11.2012    source источник
comment
Обратите внимание, что другие проиндексированные поля в модели Artist (имя и URL-адрес) индексируются и доступны для поиска, как и ожидалось, с использованием приведенных выше сопоставлений.   -  person johnny.rodgers    schedule 28.11.2012
comment
Не могли бы вы попробовать использовать параметр :as? К сожалению, сейчас нет времени вникать в это подробнее.   -  person karmi    schedule 29.11.2012
comment
Кроме того, не могли бы вы предоставить файл pastie/hastebin/etc со ссылкой на вывод to_indexed_json?   -  person karmi    schedule 29.11.2012
comment
Спасибо за быстрый ответ, @karmi! (И спасибо за потрясающую жемчужину!) Я смог найти два способа индексации метода модели Artist. Пожалуйста, ознакомьтесь с моей пастой здесь: pastie.org/5456743. Однако проблема, которую я вижу сейчас, заключается в том, что оба этих подхода увеличивают время индексации как минимум в 60 раз. Без этих методов индексирование пакета из 1000 записей занимает меньше секунды. С этими методами индексирование пакета из 1000 записей занимает больше минуты. Как можно ускорить индексацию в этом случае? У меня есть несколько миллионов записей для индексации. Есть ли здесь лучший подход? Еще раз спасибо.   -  person johnny.rodgers    schedule 30.11.2012
comment
Обновлена ​​пасти с соответствующими методами: pastie.org/5456766.   -  person johnny.rodgers    schedule 30.11.2012


Ответы (1)


Итак, чтобы включить ваше решение проблемы индексации здесь.

Ассоциации индексации

Один из способов проиндексировать метод — включить его в вызов to_json:

def to_indexed_json
  to_json( 
    :only   => [ :id, :name, :normalized_name, :url ],
    :methods   => [ :primary_image_original, :primary_image_thumbnail, :account_balance ]
  )
end

Другой, и более предпочтительный, — использовать опцию :as в блоке сопоставления:

mapping do
  indexes :id, :index    => :not_analyzed
  indexes :name             
  # ...

  # Relationships
  indexes :primary_image_original, :as => 'primary_image_original'
  indexes :account_balance,        :as => 'account_balance'
end

Борьба с n+1 запросами при импорте

Проблема с медленным индексированием, скорее всего, связана с n+1 запросами в базе данных: для каждого художника, которого вы индексируете, вы выдаете запрос изображений (оригинала и эскиза). Гораздо более эффективным способом было бы объединение связанных записей в один запрос; см. Ассоциации быстрой загрузки в руководствах по Rails.

Метод Tire Index#import и задача import Rake позволяют передавать параметры, которые затем отправляются в метод paginate по сети.

Итак, давайте сравним наивный подход:

bundle exec rake environment tire:import CLASS=Article FORCE=true
Article Load (7.6ms)  SELECT "articles".* FROM "articles" LIMIT 1000 OFFSET 0
Comment Load (0.2ms)  SELECT "comments".* FROM "comments" WHERE ("comments".article_id = 1)
Comment Load (0.1ms)  SELECT "comments".* FROM "comments" WHERE ("comments".article_id = 2)
...
Comment Load (0.3ms)  SELECT "comments".* FROM "comments" WHERE ("comments".article_id = 100)

И когда мы передаем фрагмент include:

bundle exec rake environment tire:import PARAMS='{:include => ["comments"]}'  CLASS=Article FORCE=true 
Article Load (8.7ms)  SELECT "articles".* FROM "articles" LIMIT 1000 OFFSET 0
Comment Load (31.5ms) SELECT "comments".* FROM "comments" WHERE ("comments".article_id IN (1,2, ... ,100))

Намного лучше :) Пожалуйста, попробуйте и дайте мне знать, если это решит вашу проблему.


Вы также можете попробовать это в консоли Rails: Article.import против Article.import(include: ['comments']). Кстати, именно эта проблема стала причиной поддержки хэша params во всей цепочке инструментов импорта в Tire.

person karmi    schedule 12.12.2012
comment
+1 за ответ. У меня есть ресурсоемкая функция, которую я хочу проиндексировать с помощью Elastic Search. Но эта функция принимает несколько аргументов, и я никак не могу избежать этих аргументов. Мой вопрос в том, есть ли способ проиндексировать функцию с аргументами. Большое спасибо. - person VoodooChild92; 18.09.2014