csvを読んでelasticsearchのバルクインサート用のjsonに整形する

  • 20
    いいね
  • 1
    コメント
この記事は最終更新日から1年以上が経過しています。

csvを読んでelasticsearchのバルクインサート用のjsonに整形する

elasticsearchにバルクインサートする時、
データのjson1行につきコマンドのjsonを1行追加しないとならないので。

see also:
http://blog.johtani.info/blog/2014/04/24/usage-stream2es/

stream2es だと一気に登録までしてしまうので、
変換の時点で一度確認したかったので書いてみた。

中身は

1行目にヘッダ。
それ以降がデータ。

エスケープなどはRFC4180 っぽい感じ。

items.txt
"item_id","title","description","price","url","image_url"
"11111","たいとる","でぃすくりぷしょん","1000","http://example.com/item/11111","http://example.com/11111.jpg"
"22222","たいとる2","でぃすくりぷしょん2","2000","http://example.com/item/22222","http://example.com/22222.jpg"

変換

rubyのCSVクラスがちゃんとcsv読んでくれるので、これを使うことにした。

が、パースにけっこう時間がかかるみたいなので、
大量の件数(百万件単位とか)扱う時は速度面で不安がある。

cmd2json.rb
#!/usr/bin/env ruby

require 'csv'
require 'json'
require 'securerandom'

line = STDIN.gets.chomp
csv = CSV.new(line)
header = csv.to_a[0]

INDEX = "test"
TYPE  = "type1"

CSV(STDIN).each_with_index do |row, i|
  index = { "index" =>
    { "_index" => INDEX, "_type" => TYPE, "_id" => SecureRandom.uuid }
  }
  puts JSON.dump(index)

  hash = Hash[header.zip row]
  puts JSON.dump(hash)
end
bash
cat items.txt | ./csv2json.rb > items.es.json

esに登録

で、こう。

bulk.sh
curl -s -XPOST localhost:9200/_bulk --data-binary @items.es.json

プロトタイプ

最初

  1. csv => json
  2. json => elasticsearch登録用のjson

ってやってみたけど、別に一気にやっちゃってもいいじゃん、
ってことで上記の形に落ち着いた。

2. の部分はbashでも書いたので、一応それも。
jq

1行ごとに jq 2回叩くので、
件数が多くなってくるとプロセスの起動と破棄コストがけっこう馬鹿にならなくなってくるため、あまりオススメはしない。
10万件くらい流し込んだだけでもけっこう時間かかった。

cmd2es.sh
#!/bin/bash

set -u

_INDEX=$1
_TYPE=$2

while read -r line; do
    _ID=`uuidgen`
    cat <<EOD | jq -c .
{
    "index" : {
        "_index" : "$_INDEX",
        "_type" : "$_TYPE",
        "_id" : "$_ID"
    }
}
EOD
    echo $line | jq . -c
done
bash
cat items.json | ./cmd2es.sh foo bar > items.es.json