Поиск по нескольким терминам с помощью ElasticSearch + Tire

Используя Tire с Mongoid, я не могу понять, как структурировать запрос для поиска событий с помощью ElasticSearch. В частности, я пытаюсь найти события, которые смотрят пользователи, в дополнение к событиям с исполнителями, на которые подписан пользователь:

# app/models/event.rb
class Event
  include Mongoid::Document
  include Tire::Model::Search
  include Tire::Model::Callbacks

  field :name, type: String

  has_and_belongs_to_many :performers
  has_many :watchers, class_name: 'User'

  mapping do
    indexes :name
    indexes :watcher_ids, type: 'string', index: :not_analyzed
    indexes :performer_ids, type: 'string', index: :not_analyzed
  end
end

Следующий запрос работает только для наблюдателей или исполнителей.

Tire.search 'events' do
  query do
    string params[:query]
    # Only one of these will work at a time:
    terms :performer_ids, current_user.followed_performers.collect(&:id).map(&:to_s)
    terms :watcher_ids, [current_user.id.to_s]
  end
end
  • небольшое редактирование, потому что я неправильно набрал свой пример.

Вот решение, которое кажется "работающим"... но кажется неправильным

Tire.search('events') do
  query do
    boolean do
      should { string params[:query] }
      should { string "performer_ids:#{current_user.followed_performers.collect(&:id).map(&:to_s).join(',')}" }
      should { string "watcher_ids:#{current_user.id.to_s}" }
    end
  end
end

person jeremywoertink    schedule 21.12.2012    source источник


Ответы (2)


Вы на правильном пути, но, как советовал Расс Смит, вам нужно использовать filter DSL.

Теперь, если вы просто повторно вызовете filter, вы выполните объединение: AND. Если вы хотите вернуть любые события, которые пользователь смотрит, или по исполнителям, за которыми следит пользователь, вы должны использовать фильтр or.

Кроме того, для лучшей производительности используйте запрос filtered, а не фильтр верхнего уровня — в первом случае фильтры запускаются первыми, разрезая корпус и выполняя запросы только к этому подмножеству.

Код должен выглядеть так:

Tire.search 'events' do
  query do
    filtered do
      query do
        string params[:query]
      end
      filter :or, terms: { organization_ids: current_user.followed_performers.collect(&:id).map(&:to_s) },
                  terms: { watcher_ids:      [current_user.id.to_s] }
    end
  end
end

Дополнительные примеры см. в интеграционных тестах:

person karmi    schedule 22.12.2012
comment
Спасибо, ребята, я пробовал оба примера, и мои тесты не удались. @karmi при попытке вашего примера возвращает watcher_ids, но не другие термины... filter:{and:[{or:{terms:{watcher_ids:[.... - person jeremywoertink; 22.12.2012
comment
хорошо, я потратил некоторое время, чтобы решить это, но я все еще не получаю результатов, которые я ищу. Я не использую фильтры, так как логическое значение не работает так, как мне нужно. Вот что у меня есть. - person jeremywoertink; 27.12.2012
comment
1. Я не понимаю, что он возвращает watcher_ids, но не другие термины. 2. Я не понимаю, что логическое значение не работает, как мне это нужно. 3. Код, опубликованный Рассом и /me, определенно должен работать для описанного случая - может быть, попытаться изолировать поведение в простом Ruby? 4. Мне трудно прочитать назначение кода в связанном тексте: зачем использовать multi_search для одиночного поиска, зачем оборачивать все в метод relevant_events? - person karmi; 27.12.2012
comment
Извините, общение через комментарии усложняет ситуацию. Причина multi_search в том, что около 70% кода, который я использую, было вырвано, поэтому был показан только код, относящийся к моей проблеме. Моя проблема в том, что у меня есть массив идентификаторов объектов, которые я хочу найти. Используя фильтр с или, я не получаю результатов. Используя логическое значение, я получаю результаты. Проблема с логическим значением заключается в том, что каждый должен обязателен. Итак, если Performer_ids пуст, запрос завершается ошибкой. Я уверен, что это легко исправить, но я застрял на этом некоторое время. Есть ли лучшее место для размещения вопросов для Tire? - person jeremywoertink; 28.12.2012
comment
Да, проблемы с Github работают достаточно хорошо... С фильтрами or вы должны добиться того же, что и с логическими запросами string... - person karmi; 28.12.2012

Я думаю, что вы ищете фильтр. Это не полностью протестированный код, но он может привести вас в правильном направлении.

class Event
  include Mongoid::Document
  include Tire::Model::Search
  include Tire::Model::Callbacks

  field :name, type: String

  has_and_belongs_to_many :performers
  has_many :watchers, class_name: 'User'

  mapping do
    indexes :name
    indexes :watcher_ids, type: 'integer', index: :not_analyzed
    indexes :performer_ids, type: 'integer', index: :not_analyzed
  end
end

Tire.search('events') do
  query do
    string 'my event'
  end

  filter :in, :organization_ids, [1,2,3]
  filter :in, :watcher_ids, [1]
end
person Russ Smith    schedule 22.12.2012
comment
нет :( это не работает. Если я брошу все в логическое значение с кучей должен {строка ''} тогда это работает.. - person jeremywoertink; 22.12.2012
comment
сотрите это. На самом деле это не работает, потому что для возврата результатов требуются все параметры. Вернемся к попыткам использовать фильтры... - person jeremywoertink; 26.12.2012