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

# 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として使用しませんでしたが、下記サイトを参考にしました。

- データベースとしてのElasticsearch
  - https://qiita.com/rjkuro/items/95f71ad522226dc381c8
- Elasticsearch as a NoSQL Database
  - https://www.elastic.co/blog/found-elasticsearch-as-nosql
- Elasticsearch 2.3 as primary data store?
  - https://discuss.elastic.co/t/elasticsearch-2-3-as-primary-data-store/50265

## ネストされたデータの作成
- Elasticsearch Nested Type vs Array Objects
  - https://medium.com/hello-elasticsearch/elasticsearch-nested-type-vs-array-objects-2ea7bac68ed8

```/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
```

# ネストされたデータの検索
- 【基礎編】Elasticsearchの検索クエリを使いこなそう
  - https://developers.eure.jp/tech/elasticsearch_search_query/

```
[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が被っている
- activerecord-importとelasticsearch-railsでメソッドが被る問題
  - https://blog.dakatsuka.jp/2015/11/18/activerecord-import.html

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

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

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

# 参考
- elasticsearch-rails検証
  - https://qiita.com/chase0213/items/ca6acc5d6bfecbd72be5
- elasticsearch-rails運用
  - https://qiita.com/chase0213/items/381b1eeacb849d93ecfd
- Elasticsearchを使ったRailsサンプルアプリケーションの作成
  - http://morizyun.github.io/blog/elasticsearch-rails-tutorial/index.html