2014-12-20 2 views
5

У меня есть модель под названием Movie который выглядит следующим образом:Elasticsearch рельсы/Elasticsearch модель поиска модели ассоциации

class Movie < ActiveRecord::Base 
    include Elasticsearch::Model 
    include Elasticsearch::Model::Callbacks 

    has_many :actors, after_add: [ lambda {|a,c| a.__elasticsearch__.index_document}], 
        after_remove: [ lambda {|a,c| a.__elasticsearch__.index_document}] 

    settings index: {number_of_shards: 1} do 
    mappings dynamic: 'false' do 
     indexes :title, analyzer: 'snowball', boost: 100 
     indexes :actors 
    end 
    end 

    def as_indexed_json(options={}) 
    self.as_json(
     include: { 
      actors: { only: :name} 
     } 
    ) 
    end 
end 

Когда я сделать Movie.first.as_indexed_json, я получаю:

{"id"=>6, "title"=>"Back to the Future ", 
"created_at"=>Wed, 03 Dec 2014 22:21:24 UTC +00:00, 
"updated_at"=>Fri, 12 Dec 2014 23:40:03 UTC +00:00, 
"actors"=>[{"name"=>"Michael J Fox"}, {"name"=>"Christopher Lloyd"}, 
{"name"=>"Lea Thompson"}]} 

, но когда я делаю Movie.search("Christopher Lloyd").records.first я получить: => nil.

Какие изменения я могу внести в индекс для поиска фильмов, связанных с обычным игроком?

+1

У меня такая же дилемма, у вас есть какой-либо ответ на это? – Finks

ответ

0

Я использовал filtering query, чтобы решить эту проблему, сначала я создал ActiveSupport::Concern под названием searchable.rb, концерн выглядит следующим образом:

module Searchable 
    extend ActiveSupport::Concern 
    included do 
    include Elasticsearch::Model 
    include Elasticsearch::Model::Callbacks 

    index_name [Rails.application.engine_name, Rails.env].join('_') 

    settings index: { number_of_shards: 3, number_of_replicas: 0} do 
    mapping do 
     indexes :title, type: 'multi_field' do 
     indexes :title, analyzer: 'snowball' 
     indexes :tokenized, analyzer: 'simple' 
     end 
     indexes :actors, analyzer: 'keyword' 
    end 
    def as_indexed_json(options={}) 
     hash = self.as_json() 
     hash['actors'] = self.actors.map(&:name) 
     hash 
    end 

    def self.search(query, options={}) 
     __set_filters = lambda do |key, f| 
     @search_definition[:post_filter][:and] ||= [] 
     @search_definition[:post_filter][:and] |= [f] 
     end 

     @search_definition = { 
     query: {}, 

     highlight: { 
      pre_tags: ['<em class="label label-highlight">'], 
      post_tags: ['</em>'], 
      fields: { 
      title: {number_of_fragments: 0} 
      } 
     }, 
     post_filter: {}, 

     aggregations: { 
      actors: { 
      filter: {bool: {must: [match_all: {}]}}, 
      aggregations: {actors: {terms: {field: 'actors'}}} 
      } 
     } 
     } 

     unless query.blank? 
     @search_definition[:query] = { 
      bool: { 
      should: [ 
       { 
       multi_match: { 
        query: query, 
        fields: ['title^10'], 
        operator: 'and' 
       } 
       } 
      ] 
      } 
     } 
     else 
     @search_definition[:query] = { match_all: {} } 
     @search_definition[:sort] = {created_at: 'desc'} 
     end 

     if options[:actor] 
     f = {term: { actors: options[:taxon]}} 
     end 

     if options[:sort] 
     @search_definition[:sort] = { options[:sort] => 'desc'} 
     @search_definition[:track_scores] = true 
     end 
     __elasticsearch__.search(@search_definition) 
    end 
    end 
end 

У меня выше беспокойство в каталоге models/concerns. В movies.rb у меня есть:

class Movie < ActiveRecord::Base 
    include Searchable 
end 

В movies_controller.rb я делаю поиск на index действие и действие выглядит следующим образом:

def index 
    options = { 
    actor: params[:taxon], 
    sort: params[:sort] 
    } 
    @movies = Movie.search(params[q], options).records 
end 

Теперь, когда я иду в http://localhost:3000/movies?q=future&actor=Christopher я получаю все записи, которые имеют слово будущего на их название и имеет актера с именем Кристофер. У вас может быть более одного фильтра, как показано шаблоном expert примерных шаблонов приложений found here.

0

Попробуйте

indexes :actors do 
indexes :name, type: "string" 
end 
1

Вы можете попробовать добавить методы поиска к вашей модели, как это:

class Movie < ActiveRecord::Base 
    include Elasticsearch::Model 
    include Elasticsearch::Model::Callbacks 

    # ... 

    def self.search(query, options = {}) 
    es_options = 
     { 
     query: { 
      query_string: { 
      query:   query, 
      default_operator: 'AND', 
     } 
     }, 
     sort: '_score', 
    }.merge!(options) 
    __elasticsearch__.search(es_options) 
    end 

    # ... 
end 

Вот некоторые примеры поиска метода: http://www.sitepoint.com/full-text-search-rails-elasticsearch/

И теперь вы может выполнять поиск во всех ваших проиндексированных полях.

0

Вы должны указать поля в Передней search метод, как:

def self.search query 
    __elasticsearch__.search(
    query: { 
     multi_match: { 
     query: query, 
     fields: %w[title actor.name] 
     } 
    } 
) 
end 

 Смежные вопросы

  • Нет связанных вопросов^_^