Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
17
Help us understand the problem. What is going on with this article?
@dorarep

ElasticSearch-Railsの導入手順・詰まった点など

More than 3 years have passed since last update.

RailsからElasticSearchを使いたい

初めてElasticSearchを使ったので、その際の手順や詰まった点などまとめてみました。

導入手順

Install

gem install elasticsearch-model
gem install elasticsearch-rails

既存のModelに反映させる

class Line < ActiveRecord::Base
  include Elasticsearch::Model
  ...

設定の作成

/config/initializers/elasticsearch.rb
config = {
    host: "http://localhost:9200/",
}

if File.exists?("config/elasticsearch.yml")
  config.merge!(YAML.load_file("config/elasticsearch.yml")[Rails.env].symbolize_keys)
end
Elasticsearch::Model.client = Elasticsearch::Client.new(config)
/config/elasticsearch.yml
development: &default
  host: 'http://localhost:9200/'
test:
  <<: *default
staging:
  <<: *default
production:
  host: 'http://XXX/'

ref) https://medium.com/@thecolorfulcrayon/configuring-elasticsearch-on-rails-8bcbe973e9e7

Rails Consoleで動作確認

[1] pry(main)> Line.__elasticsearch__.create_index!
=> {"acknowledged"=>true, "shards_acknowledged"=>true}
[2] pry(main)> Line.__elasticsearch__.import
  Line Load (1.0ms)  SELECT  `lines`.* FROM `lines`  ORDER BY `lines`.`id` ASC LIMIT 1000
=> 0
[3] pry(main)> Line.__elasticsearch__.search('秋田新幹線').results.first
=> #<Elasticsearch::Model::Response::Result:0x007fbdeccf3080
 @result=
  {"_index"=>"lines",
   "_type"=>"line",
...

悩んだ点

ElasticSearchをPrimary Data Storeに使用することの是非

結局Primary Data Storeとして使用しませんでしたが、下記サイトを参考にしました。

ネストされたデータの作成

/app/models/concerns/line_searchable.rb
module LineSearchable
  extend ActiveSupport::Concern

  included do
    include Elasticsearch::Model

    index_name    "line_#{Rails.env}"

    settings do
      mappings dynamic: 'false' do
        indexes :name, type: 'text'

        indexes :stations, type: :nested do
          indexes :id
          indexes :name, type: 'text'
        end
      end
    end

    def as_indexed_json(option = {})
      category_attrs = {
          id: self.id,
          name: self.name
      }
      category_attrs[:stations] = self.stations.map do |station|
        {
            id: station.id
            name: station.name
        }
      end

      category_attrs.as_json
    end
  end
end

ネストされたデータの検索

[1] pry(main)> query = {:query=>
  {:bool=>
    {:must=>
      [{"term"=>{"name"=>"JR中央線(快速)"}},
       {"nested"=>{"path"=>"stations", "query"=>{"terms"=>{"stations.id"=>[1, 2, 3]}}}}]}}}
[2] pry(main)> Line.search(query).results.first
...

includesやwhereをしてからImportしたい

コードを読み込んで行ったらoptionsに色々な機能を持たせていたので、それによって対応しました。

/app/models/concerns/line_searchable.rb
def self.elasticsearch_import
  self.__elasticsearch__.import(query: -> { includes(:stations).where('XXX') })
end

ref)
https://github.com/elastic/elasticsearch-rails/blob/b6d485748c71a07d064ea2a46a6da82d64a04cd7/elasticsearch-model/lib/elasticsearch/model/adapters/active_record.rb#L96

同一モデルでもindexやtypeを動的に変えたい

結局やりませんでしたが、使用する際にoptionsで動的にindexやtypeを指定することで対応可能かと思われます。

ref)
https://github.com/elastic/elasticsearch-rails/blob/master/elasticsearch-model/lib/elasticsearch/model/importing.rb#L102

ElasticSearchとactiverecord-importでNamespaceが被っている

[1] pry(main)> Line.import
ArgumentError: Invalid arguments!

activerecord-importが先に導入されていたこともあってactiverecord-import側のメソッド名を変えることはリスキーだったので、ElasticSearchのFunctionを呼ぶ際は__elastic_search__を経由することで対応しました。

[1] pry(main) > Line.__elastic_search__.import

参考

17
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
dorarep
いつも困ったときにお世話になっているので、少しでも皆様のお力になれれば幸いです! PHP/Laravel/Ruby on Rails/TypeScript/Vue.js/React/React Native/DevOps/CircleCI/エンジニア採用

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
17
Help us understand the problem. What is going on with this article?