#Elasticsearchに格納されているデータ取得
10000件以上データが格納されているタイプに対して全件取得をしたかったが、
単純なsearchによるデータ取得ではできなかったので、別の方法を試してみた。
###TL;DR
「Search API」によるデータ取得件数にはいくつか制限がある為、
「Scroll API」を利用して全件取得する方法をメモとして残しておく。
###バージョン
Elasticsearch 5.4
##「Search API」の制限
Search APIによるデータ検索には検索数における制限がある
###「Search API」の検索
- 無条件検索する
curl -sS -XGET 'loclahost:9200/[インデックス名]/[タイプ名]/_search?pretty'
制限①:デフォルトの10件までしか取得できない
- クエリを利用して、fromとsizeを指定すうことで10件以上のデータを取得する
curl -sS -XGET 'localhost:9200/[インデックス名]/[タイプ名]/_search?pretty' -d
'{
"query": {
"match_all": {}
},
"from": 0,
"size": 999
}'
制限②:from + sizeが10000件を超えるとエラーとなってしまう
Result window is too large, from + size must be less than or equal to: [10000] but was [12000]. See the scroll api for a more efficient way to r
equest large data sets. This limit can be set by changing the [index.max_result_window] index level setting.
[index.max_result_window]に設定されている値以上は取得できないよう。
(デフォルトで10000が設定されている)
エラー内容に書かれているようにscroll apiを調べて利用してみる。
##「Scroll API」による検索
Scroll APIを利用すると、実行時点でのスナップショットを保存し、取得しきれなかった分を辿っていくことができる。
レスポンスとして検索結果と「scroll_id」が返却される。
返却された「scroll_id」を元に、リクエストを繰り返し投げることで全データを取得することが可能。
###初回リクエスト
必要な設定値
- スナップショットの保存期限
- size
- query
スナップショットの保存期限を「1m」(1分)とし、match_allで9000件取得するクエリを投げる。
curl -sS -XGET 'localhost:9200/[インデックス名]/[タイプ名]/_search?pretty&scroll=1m' -d
'{
"size": 9000,
"query": {
"match_all": {}
}
}'
※sizeには10000件([index.max_result_window]に設定されている値)以上は設定できない
レスポンス例
{
"_scroll_id": "XXXXXXXXX・・・XXX",
"took": 274,
"timed_out": false,
"terminated_early": true,
"_shards": {
"total": 1,
"successful": 1,
"failed": 0
},
"hits": {
"total": 23514,
"max_score": 1,
"hits": [
{
"_index": "index_name",
"_type": "type_name",
"_id": "〇〇〇",
"_score": 1,
"_source": {
"name": "mug",
"group": "sample"
}
},
{
"_index": "index_name",
"_type": "type_name",
"_id": "△△△",
"_score": 1,
"_source": {
"name": "cup",
"group": "sample"
}
}
...........
...........
......
]
}
}
###2回目以降のリクエスト
初回リクエストで返ってきた「scroll_id」を元に作成
スナップショットを元にリクエストを投げるため、初回に設定したクエリやサイズを元に実行される。
エントリポイントは /_search/scroll
curl -sS -XGET 'localhost:9200/_search/scroll?pretty' -d
'{
"scroll": "1m",
"scroll_id": "XXXXXXXXX・・・XXX"
}'
scroll_idは初回以降変わらないため、データ件数を超えるまで投げ続けることでデータを全件取得できる
データ件数を超えた場合は検索結果がレスポンスに返ってこないため、
プログラムとしてそこを判定してループ処理を実施することも可能。
###スナップショットの廃棄
設定したスナップショットの保存期限を超えると自動で削除される仕様だが、
明示的に作成したスナップショットを削除することが推奨されている。
curl -XDELETE 'localhost:9200/_search/scroll?pretty' -d
'{
"scroll_id": "XXXXXXXXX・・・XXX"
}'
##まとめ
確実に全件取得できることは理解したが、
プログラムで実行する場合、データ件数を超えたかどうかの判定の箇所はもう少し考える必要がある。