Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails - ElasticSearch - Multiple indices in one model

I have a Post model:

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

  # I WANT THIS FUNCTION EXECUTED ON index1
  def self.search1(query)
      __elasticsearch__.search(
        {
        query:
        }
      )
  end

  # I WANT THIS FUNCTION EXECUTED ON index2
  def self.search2(query)
      __elasticsearch__.search(
        {
        query:
        }
      )
  end

  index_name  "index1" 

  # I NEED ANOTHER INDEX ? HOW CAN I DO ?  
  settings index1: { number_of_shards: 1 } do
    mappings dynamic: 'false' do
      indexes :title, analyzer: 'english'
    end
  end
end

Post.__elasticsearch__.client.indices.delete index: "index1" rescue nil
Post.__elasticsearch__.client.indices.create index: "index1", body: { settings: Post.settings.to_hash, mappings: Post.mappings.to_hash }
Post.import

I have 1 model, 2 very different functions which need a completely different index.

How can I build 2 different indices in 1 model and tell the __elasticsearch__.search which index it should use ?

like image 796
Beuun Avatar asked Mar 01 '15 00:03

Beuun


2 Answers

You know you can use 2 models for the same database table right? I'd use a concern for the shared methods and one model per index, that or 3 models, one for regular use and the 2 others specifically for the indexes. It might feel like a hack at first but that might be a cleaner solution in the end. Let me know how it goes :p

like image 76
Alex C Avatar answered Sep 28 '22 13:09

Alex C


Although a bit late, I came across this question when trying to find a solution for the same problem. In my case I needed multilanguage support for a model and elasticsearch.

In config/initializers/elasticsearch.rb we override __type_for_hit to avoid index_name matching

module Elasticsearch
  module Model
    module Adapter
      module Multiple
        module Records

          def __type_for_hit(hit)
            @@__types ||= {}

            @@__types[ "#{hit[:_index]}::#{hit[:_type]}" ] ||= begin
            Registry.all.detect do |model|
              model.document_type == hit[:_type]
            end
          end
        end
      end
   end
end

Then in our Model

def self.mappings
  {
   :post => {
     :dynamic => "false",
     :properties => {
       :name => {
         :type          => "text",
         :analyzer      => "english"
        }
      }
    }
  }
end

class Elastic

   def initialize locale
      @locale = locale
   end

   def index_name
      "posts-" + @locale    
   end

   def document_type
      "post"
   end
end  

mappings allows us to create indexes like:

Post.__elasticsearch__.client.indices.create index: "posts-en", body: { mappings: Post.mappings.to_hash }

Then, in order to import documents:

Post.import index:'posts-en'

Notice that you can define mappings as a function and create as many different indexes as you want. Finally you can search across an index or multiple indexes like:

Elasticsearch::Model.search('my_query', [Post::Elastic.new('en'), Post::Elastic.new('es') ]).records
like image 45
Alejandro Marti Avatar answered Sep 28 '22 14:09

Alejandro Marti