ElasticsearchからデータをCSV形式でワンライナーで取り出す


## はじめに
業務で、Elasticsearchに入ってるデータをちょうだい！と言われて、Elasticsearchに入れたときのデータをそのまま渡せばいいのだが、実態がそれと違うかもだし、Elasticsearchからでもデータを抜けるだろうと試してできたコマンド

## 準備
- Elasticsearch 1.7.1
- jq 1.3
	- JSONの操作と言えば、やはりこれ。
- csvkit 0.9
	- csvkitは、JSONから簡単にCSVに変換できるコマンドなどが入ったCSVについて便利な操作ができるツール。詳しくは[公式ドキュメント](http://csvkit.readthedocs.org/en/0.9.1/)
- curl 
	- 入ってるよね？

## 1行コマンド

```
curl -XGET "[IPアドレス or ホスト名]:[ポート番号]/[index名]/[type名]/_search?&size=[抽出したいレコード数]" | jq [.hits.hits[]._source] | in2csv -f json
```

例えば、nginxのアクセスログデータでちょっとやってみた。アドレスとかは適当な値に変換してる。

```
$ curl -XGET "[IPアドレス]:[ポート番号]/nginxaccess-2015.10.16/nginx/_search?&size=2" | jq [.hits.hits[]._source] | in2csv -f json
```
```
% Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  1478  100  1478    0     0  48481      0 --:--:-- --:--:-- --:--:-- 50965
@timestamp,status,query_string,uri,https,request_uri,request_length,request_method,remote_addr,bytes_sent,body_bytes_sent,referer,useragent,forwardedfor,request_time,upstream_response_time,@nginx.access
2015-10-16T10:35:24+09:00,200,-,/~hogehoge.user/img/title.gif,,/~hogehoge.user/img/title.gif,511,GET,192.168.42.1,16445,16204,http://hogehoge.com,User-HogeAgent,::ffff:192.168.43.1,0.000,-,nginx.access
2015-10-16T10:21:17+09:00,404,-,/favicon.ico,,/favicon.ico,563,GET,192.168.42.1,726,571,http://hogehoge.com,User-HogeAgent,"::ffff:192.168.43.1,0.000,-,nginx.acces

```

## 解説

### Elasticsearch

- REST API的な操作が可能なのはすでにご存知だと思います。
- [index名]と[type名]を記入し、_searchで検索
	- デフォルトだと10レコードだけしか表示されないので、欲しいレコード数分だけ、sizeで指定する

#### そもそもindex名がわからない

以下でElasticsearchにあるindex一覧を取得できる。

```
$ curl -XGET [IPアドレス or ホスト名]:[ポート番号]/_aliases?pretty
```

#### そもそもType名がわからない

下記例では、index名が「nginxaccess-*」のnginxのログの例。mappingから「nginx」がType名と分かる。

```
$ curl -XGET [IPアドレス or ホスト名]:[ポート番号]/nginxaccess-*/_mapping?pretty=true

{
  "nginxaccess-2015.10.09" : {
    "mappings" : {
      "nginx" : {
        "properties" : {
          "@nginx.access" : {
            "type" : "string"
          },
          "@timestamp" : {
            "type" : "date",
            "format" : "dateOptionalTime"
          },
<snip>
```

#### そもそもどれくらいレコード入ってるのかわからない

\_countでも分かります。\_searchでも分かる。

```
$ curl -XGET [IPアドレス or ホスト名]:[ポート番号]/nginxaccess-*/nginx/_count?pretty
```

#### そもそもどんな風にレコードが保存されているかわからない

なにもいじってなければ、以下の感じで入ってるかと。hits -> hits -> _source の中が実際のデータ。

```
$ curl -XGET [IPアドレス or ホスト名]:[ポート番号]/nginxaccess-2015.10.16/nginx/_search?&pretty&size=2"
{
  "took" : 15,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "failed" : 0
  },
  "hits" : {
    "total" : 145,
    "max_score" : 1.0,
    "hits" : [ {
      "_index" : "nginxaccess-2015.10.16",
      "_type" : "nginx",
      "_id" : "AVBuSYiyx-w4SUTcVChQ",
      "_score" : 1.0,
      "_source":{"remote_addr":hogehoge ....}
    }, {
      "_index" : "nginxaccess-2015.10.16",
      "_type" : "nginx",
      "_id" : "AVBuPKMsx-w4SUTcVCfh",
      "_score" : 1.0,
      "_source":{"remote_addr":hogehoge ....}
    } ]
  }
}
```

#### クエリも投げたい

"q="で指定する。OR検索は、"|"を入れる。

```
$ curl -XGET [IPアドレス or ホスト名]:[ポート番号]/nginxaccess-2015.10.16/nginx/_search?&q=remote_addr:172.16.1.1|172.16.1.2"
```

### jq

- jq自体のドキュメントは日本語だと、[軽量JSONパーサー『jq』のドキュメント：『jq Manual』をざっくり日本語訳してみました](http://dev.classmethod.jp/tool/jq-manual-japanese-translation-roughly/)が詳しく翻訳してくれている。英語が読めるならもちろん[公式ドキュメント](https://stedolan.github.io/jq/manual/#Basicfilters)が良い。

### in2csv

- csvkitツールのコマンドの1つ。-f オプションで指定したフォーマットを入力として、csv形式に変換してくれる。
- 参考は以前自分が書いた[csvkitの使い方まとめ](http://qiita.com/gingi99/items/d5add3aa062bf4f10cad)

### おわりに

- もともとは、pythonの[Elasticsearch API](https://elasticsearch-py.readthedocs.org/en/master/index.html)を使おうと思ったが、jqとcsvkit強いなと思って、結局Linuxコマンドで。
- rubyでcsvを抽出するやつなどもあるようです。[Elasticsearch の検索結果を csv に書き出すスクリプトを作った](http://blog.cloudpack.jp/2014/11/10/script-of-elasticsearch-csv-output/)。