Elasticsearch rails / Elasticsearch Model Search Model

I have a model called Movie that looks like this:

 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 

When I do Movie.first.as_indexed_json , I get:

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

but when I do Movie.search("Christopher Lloyd").records.first , I get: => nil .

What changes can I make to the index to search for films related to an ordinary actor?

+5
source share
4 answers

I used filtering query to solve this problem, first created ActiveSupport::Concern called searchable.rb , the problem is as follows:

 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 

I have the following problem in the models/concerns directory. In movies.rb , I have:

 class Movie < ActiveRecord::Base include Searchable end 

In movies_controller.rb I search in the index action, and the action looks like this:

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

Now, when I go to http://localhost:3000/movies?q=future&actor=Christopher , I get all the records that have the word future by their name, and there is an actor named Christopher. You can have several filters, as shown in the expert template, examples of application templates found here .

0
source

You can try adding the search method to your model as follows:

 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 

Here are some examples of method searches: http://www.sitepoint.com/full-text-search-rails-elasticsearch/

And now you can search in all of your indexed fields.

+1
source

try it

 indexes :actors do indexes :name, type: "string" end 
0
source

You need to specify the fields in the search method, for example:

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

Source: https://habr.com/ru/post/1209614/


All Articles