2014-12-20 19 views
5

Mam modelu nazwie Movie, który wygląda tak:Elasticsearch szyny/Elasticsearch Modelarski wyszukiwania stowarzyszenie

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 

Kiedy zrobić Movie.first.as_indexed_json, otrzymuję:

{"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"}]} 

ale kiedy zrobić Movie.search("Christopher Lloyd").records.first ja uzyskać: => nil.

Jakie zmiany można wprowadzić w indeksie, aby wyszukać filmy powiązane z wyszukiwanym aktorem?

+1

Mam ten sam dylemat, czy masz żadnej odpowiedzi na to? – Finks

Odpowiedz

0

użyłem filtering query aby rozwiązać ten problem, najpierw stworzył ActiveSupport::Concern nazwie searchable.rb koncern wygląda następująco:

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 

mam powyższy problem w katalogu models/concerns. W movies.rb mam:

class Movie < ActiveRecord::Base 
    include Searchable 
end 

W movies_controller.rb robie szukają na działanie index i działania wygląda następująco:

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

Teraz, kiedy idę do http://localhost:3000/movies?q=future&actor=Christopher uzyskać wszystkie rekordy, które mają słowo przyszłość na ich tytuł i ma aktora o imieniu Christopher. Możesz mieć więcej niż jeden filtr, jak pokazano w szablonie expert przykładowych szablonów aplikacji found here.

0

Spróbuj

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

Można spróbować dodać metodę przeszukiwanie do modelu jak ten:

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 

Oto kilka przykładów wyszukiwania Metoda: http://www.sitepoint.com/full-text-search-rails-elasticsearch/

a teraz może wyszukiwać we wszystkich twoich indeksowanych polach.

0

musisz określić pola w The search metody, jak:

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