2014-12-20 13 views
5

Ich habe ein Modell Movie benannt, der wie folgt aussieht:Elasticsearch Schienen/Elasticsearch Modell Suchmodell Verein

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 

Wenn ich Movie.first.as_indexed_json tun, erhalte ich:

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

aber wenn ich tun Movie.search("Christopher Lloyd").records.first i erhalten: => nil.

Welche Änderungen kann ich am Index vornehmen, um mit dem gesuchten Akteur verbundene Filme zu suchen?

+1

ich das gleiche Dilemma haben, Sie haben keine Antwort auf diese? – Finks

Antwort

0

benutzte ich filtering query dieses Problem zu lösen, zuerst habe ich eine ActiveSupport::Concernsearchable.rb genannt, die Sorge sieht wie folgt aus:

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 

ich die oben Sorge im models/concerns Verzeichnis haben. In movies.rb ich habe:

class Movie < ActiveRecord::Base 
    include Searchable 
end 

In movies_controller.rb ich auf der index Aktion die Suche mache und die Aktion wie folgt aussieht:

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

Jetzt, als ich zu http://localhost:3000/movies?q=future&actor=Christopher gehen bekomme ich alle Datensätze, die die haben Wort Zukunft auf ihren Titel und hat einen Schauspieler mit einem Namen Christopher. Sie können mehr als einen Filter verwenden, wie in der Vorlage expert der Beispielanwendungsvorlagen found here gezeigt.

0

Versuchen Sie, diese

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

Sie versuchen Methode Suche zu Ihrem Modell wie folgt hinzufügen:

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 

Hier einige Beispiele für Suchlauf: Sie http://www.sitepoint.com/full-text-search-rails-elasticsearch/

Und jetzt kann in allen indizierten Feldern suchen.

0

Sie müssen die Felder in der die search Methode angeben, wie:

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