Переписать SQL-запрос с шиной

Я пытаюсь переписать запрос с помощью шины.

Вот такая модель у меня:

class User < ActiveRecord::Base
  has_many :bookmarks, :dependent => :destroy
  has_many :followed_venues, :through => :bookmarks, :source => :bookmarkable, :source_type => 'Venue'
end

Пользователь может следить за местами. И мне нужно искать места, на которые подписаны определенные пользователи.

До сих пор я делал это с ActiveRecord:

@user.followed_venues.where(["venues.title LIKE ?", "%"+params[:q]+"%"])

Это явно не идеально, поэтому я добавил в свое приложение с шиной elasticsearch.

Как мне искать места с шиной, фильтруя по пользователю, который за ними следит?


person egze    schedule 26.01.2012    source источник


Ответы (2)


Я собираюсь опубликовать ответ на свой вопрос.

Так что довольно легко просто искать места. Стандарт Venue.tire.search {...} Проблема заключается в том, как отфильтровать пользователей, которые следят за местами. Вместо использования модели Venue для поиска я решил индексировать закладки.

Это моя модель закладки

class Bookmark < ActiveRecord::Base
  belongs_to :bookmarkable, :polymorphic => true

  def to_indexed_json
    {
      :title => bookmarkable.display_name,
      :user_id => user_id
    }.to_json
  end
end

После этого у меня есть user_id и название места в индексе. Теперь поиск становится таким простым:

Bookmark.tire.search :load => {:include => 'bookmarkable'}, :page => page, :per_page => per_page do
  query do
    fuzzy :title => { :value => query.downcase, :min_similarity => 0.6, :prefix_length => 2}
  end
  filter :terms, {:bookmarkable_type => ["Venue"], :user_id => [user.id]}
end

Теперь это не полное решение. И я надеюсь, что даже правильно использую filter :terms. Результат, который я получаю сейчас, на самом деле представляет собой массив закладок. Но для них легко загрузить фактические места и, возможно, обернуть их в коллекцию WillPaginate для лучшего разбиения на страницы во внешнем интерфейсе.

Есть ли проблемы с этим решением? Как это будет сравниваться с тем, что предложил phoet, добавив идентификаторы пользователей в индекс мест проведения?

person egze    schedule 26.01.2012
comment
Проблема с вашим решением заключается в том, что с load в вашем запросе вы попадаете в базу данных. Это, конечно, не так быстро, как использование только индекса elasticsearch. - person tommasop; 08.02.2012
comment
Да, я понимаю это. Но мне нужны объекты AR, так что без этого никуда. - person egze; 08.02.2012
comment
@tommasop Верно, но запрос будет очень быстрым, так как он делает SELECT ... IN [ids] - person karmi; 25.07.2012
comment
@egze Я думаю, что ваше решение в порядке, использование filter здесь правильно (быстро, кэшируется и т. д.) - person karmi; 25.07.2012

я бы создал документ для каждого места, а затем добавил поле с массивом всех идентификаторов пользователей, которые следуют.

Вы действительно уверены, что это подходящая задача для elasticsearch?

я думаю, было бы намного проще просто искать в индексе название места, а затем искать нужные данные в вашей реляционной базе данных.

person phoet    schedule 26.01.2012
comment
Я думаю, что это задача для elasticsearch, потому что я также хочу иметь нечеткое соответствие для названия места. Я пробую другой подход, как это сделать. Вместо того, чтобы индексировать места, я буду индексировать закладки, у которых есть user_id, и добавлю название места в индекс. Я собираюсь опубликовать решение через секунду. - person egze; 26.01.2012
comment
@phoet Да, я думаю, что предпочтительнее использовать filter в самом запросе elasticsearch, поскольку тогда запрос к базе данных будет очень простым/быстрым. Очевидно, что одним недостатком является то, что вам необходимо синхронизировать базу данных и индекс, чтобы записи не смешивались между пользователями. - person karmi; 25.07.2012