Как фильтровать коллекцию поиска, только если у ресурса есть определенный атрибут?

Я использую Elastic Search и Tire для поиска.

Я создал класс Search для поиска по всем моим моделям.

class Link < ActiveRecord::Base
  ...
  tire.mapping do
    indexes :id, :type => 'string', :index => :not_analyzed
    indexes :app_id, :type => 'string', :index => :not_analyzed
    indexes :title, analyzer: 'snowball', boost: 100
  end

  def to_indexed_json
    to_json(
      only: [:id, :app_id, :title]
    )
  end    
end

class Search
  def results
    search = Tire.search [:questions, :answers, :links, :events] do
      query { string "#{term}" }
    end
    search.results
  end
end

Дело в том, чтобы вернуть только элементы из приложений 12 и 13.

Поэтому я попытался отфильтровать все результаты, используя search.filter :and, must: {term: {app_id: [12, 13]}}, но только questions, links и answers имеют атрибут app_id. И я хотел бы также вернуть все events.

Как это сделать?

EDIT: На данный момент у меня работает что-то вроде ниже:

multi_search = Tire.multi_search do
  search :without_app, indices: [:events, :past_events, :reviews] do
    query { match :_all, "#{term}" }
  end
  search :with_app, indices: [:questions, :answers, :links, :service_providers] do
    query do
      filtered do
        query { match :_all, "#{term}" }
        filter :terms, app_id: app_ids
      end
    end
  end
end
multi_search.results[:with_app].to_a + multi_search.results[:without_app].to_a

person tomekfranek    schedule 18.12.2012    source источник
comment
Я открыл задачу github в Tire gem: github.com/karmi/tire/issues/551   -  person tomekfranek    schedule 19.12.2012
comment
Пожалуйста, используйте либо вопросы Github, или вопросы StackOverflow, в противном случае это прекращает обсуждение...   -  person karmi    schedule 19.12.2012


Ответы (1)


Хорошим шаблоном может быть использование метода multi_search, если вы хотите сегментировать результаты:

require 'tire'

Tire.index('questions') do
  delete
  store type: 'question', app_id: 1, title: 'Question test 1'
  store type: 'question', app_id: 2, title: 'Question test 2'
  store type: 'question', app_id: 3, title: 'Question test 3'
  refresh
end

Tire.index('links') do
  delete
  store type: 'link', app_id: 1, title: 'Link test 1'
  store type: 'link', app_id: 2, title: 'Link 2'
  store type: 'link', app_id: 3, title: 'Link test 3'
  refresh
end

Tire.index('events') do
  delete
  store type: 'event', title: 'Event test 1'
  store type: 'event', title: 'Event test 2'
  store type: 'event', title: 'Event 3'
  refresh
end

multi_search = Tire.multi_search do
  search :all, indices: [:questions, :links, :events] do
    query { match :_all, 'test' }
  end
  search :rest, indices: [:questions, :links] do
    query do
      filtered do
        query { all }
        filter :terms, app_id: [1, 2]
      end
    end
  end
end

puts "ALL:  " + multi_search.results[:all].map(&:title).inspect
puts '---'
puts "REST: " + multi_search.results[:rest].map(&:title).inspect
person karmi    schedule 19.12.2012
comment
Я отредактировал вопрос с решением, которое мне помогает. Но, возможно, это более эффективный способ сделать это. - person tomekfranek; 19.12.2012
comment
Вы объединяете два массива, сохраняя дубликаты — если это нормально, то это хорошее решение. - person karmi; 27.12.2012