とーますメモ

Ruby on Rails / Goなどの学習メモ

【Elasticsearch】データをElasticsearchに入れる方法について調べてみた

多くのサイトで以下のデータセットを使っているケースが多い。

github.com

この記事ではこのデータセット使用させて頂き
データをElasticsearchに入れる方法について解説する。

調べてみたところ、データの注入方法としては
以下の方法があるようだ。

  1. River系プラグインRDBからデータを入れる
  2. River系プラグインCSVからデータを入れる
  3. Bulk APIを使用する
  4. Index APIを使用する

1) River系プラグインRDBからデータを入れる

elasticsearch-jdbcというツール(元はプラグイン?)を使って
データを入れるというの主流っぽい。

qiita.com

ただしこの「elasticsearch-jdbc」は、現時点(2017/08/21)で
Elasticsearchの2.3.4までにしか対応していない。

※以下公式内の「Compatiblity matrix」箇所を参照
github.com

ちなみに現在の2.x系の最新版は「2.4.6」。

最新版の2.x系や5.x系を使用する場合、上手く動作しないっぽい。
※自分は2.4.6で試してみたが、動作しなかった。

2) River系プラグインCSVからデータを入れる

以前は、以下のプラグインを使ってCSVからデータを入れていたようだが
riverの廃止により、1.7.x系までしかサポートしていない。
1)の方法と同じように、最新版の2.x系や5.x系を使用する場合、上手く動作しないっぽい。

github.com

以下公式より引用

As from ES version 2 and above, rivers are not supported anymore. This said we've discontinued this repo for active development and let it be only for important fixes.

3)Bulk APIを使用する

JSONファイルを作成し、一気にバルクインサートする。
以下のサイトさんが詳しく解説している。

qiita.com

ameblo.jp

ただこのJSONファイルを作るのも、ちょっと面倒くさい。
専用のDSLに沿ったJSONを書かないといけないので、
JSONファイルを作成するためのコードを別途作成必要がある。

elasticsearch用jsonを作成せずとも、単純なデータだけのjson
データを注入できる「steam2es」というツールもあるらしい。
以下のサイトさんが解説している。

blog.johtani.info

ちなみに公式から
各言語に対応したクライアントも出ている。

Rubyだとこんな感じかと。(未検証)

①インストール

gem install elasticsearch

②コード作成

# デフォルトでlocalhost:9200に接続
client = Elasticsearch::Client.new log: true
# HOSTやURLを指定したい場合は以下。
# client = Elasticsearch::Client.new host: 'search.myserver.com'
# client = Elasticsearch::Client.new host: 'myhost:8080'
# client = Elasticsearch::Client.new url: 'https://username:password@api.server.org:4430/search'

client.bulk body: [
  { index:  { _index: 'myindex', _type: 'mytype', _id: 1, data: { title: 'foo' } } },
  { update: { _index: 'myindex', _type: 'mytype', _id: 2, data: { doc: { title: 'foo' } } } },
  { delete: { _index: 'myindex', _type: 'mytype', _id: 3  } }
]

[参考]
https://github.com/elastic/elasticsearch-ruby/blob/master/elasticsearch-api/lib/elasticsearch/api/actions/bulk.rb
http://inokara.hateblo.jp/entry/2015/12/14/231143


4)Index API

自分の場合は、手軽くデータを入れたかったので
この方法に落ち着いた。

以下のサイトさんのやり方を参考にRubyコードを作成
easyramble.com

①コード(insert_data.rb)の作成

#!/usr/bin/env ruby

require "csv"

CSV.open("restaurants.csv", "r") do |f|
  f.each_with_index do |item, i|
    next if i == 0
    p item
    `curl -XPUT 'http://localhost:9200/ldgourmet/restaurant/#{item[0]}' -d '
      {
        "id": "#{item[0]}",
        "name": "#{item[1]}",
        "property": "#{item[2]}",
        "alphabet": "#{item[3]}",
        "name_kana": "#{item[4]}",
        "pref_id": "#{item[5]}",
        "area_id": "#{item[6]}",
        "station_id1": "#{item[7]}",
        "station_time1": "#{item[8]}",
        "station_distance1": "#{item[9]}",
        "station_id2": "#{item[10]}",
        "station_time2": "#{item[11]}",
        "station_distance2": "#{item[12]}",
        "station_id3": "#{item[13]}",
        "station_time3": "#{item[14]}",
        "station_distance3": "#{item[15]}",
        "category_id1": "#{item[16]}",
        "category_id2": "#{item[17]}",
        "category_id3": "#{item[18]}",
        "category_id4": "#{item[19]}",
        "category_id5": "#{item[20]}",
        "zip": "#{item[21]}",
        "address": "#{item[22]}",
        "north_latitude": "#{item[23]}",
        "east_longitude": "#{item[24]}",
        "description": "#{item[25]}",
        "purpose": "#{item[26]}",
        "open_morning": "#{item[27]}",
        "open_lunch": "#{item[28]}",
        "open_late": "#{item[29]}",
        "photo_count": "#{item[30]}",
        "special_count": "#{item[31]}",
        "menu_count": "#{item[32]}",
        "fan_count": "#{item[33]}",
        "access_count": "#{item[34]}",
        "created_on": "#{item[35]}",
        "modified_on": "#{item[36]}",
        "closed": "#{item[37]}"
      }
    '`
  end
end

パーミッションの設定

$ chmod 755 insert_data.rb

③データ挿入

$ ruby insert_data.rb

ちょっと時間かかるけど、シンプルで楽だった。