こんにちは、株式会社CINC開発本部です。
前回・前々回に引き続き、Amazon OpenSearch Service ( ElasticSearch ) 関連のTipsです。
↓前々回の記事↓ cincdevteam.hatenablog.com
↓前回の記事↓ cincdevteam.hatenablog.com
はじめに
Amazon OpenSearch Service の Terms Aggregation は、SQLのGroup By句のような集計を実現できます。
ですが、パフォーマンス上の制約から、 1 回のリクエストで取得できる件数の最大値は 10,000 件までという制限があります。
参考:Terms aggregation | Elasticsearch Guide [8.16] | Elastic
そのため、大量のデータを集計して取得する用途には利用できない、と考えていました。
実は、パーティショニングを用いることで、 10,000 件を超えるデータを複数のリクエストに分割しつつ取得することが可能なことを発見しました。
以下で、その具体的な実装方法について説明します。
パーティショニングの指定方法
Amazon OpenSearch Service でのパーティショニングは以下の3つの要素を指定することで、利用ができます。
要素名 | 説明 | ① | partition | 分割したパーティションを特定するための番号 | ② | num_partitions | 分割したパーティションの総数 | ③ | size | 1つのパーティションに含める terms の件数 |
---|
実装例
例として
200,000 未満 ユーザー分のデータがある、ユーザログのドキュメントから、ユーザーごとの最終アクセス日付を取得するクエリを考えてみます。
※「未満」と書いた理由は後述します
GET /_search { "size": 0, "aggs": { "expired_sessions": { "terms": { "field": "account_id", "include": { "partition": 0, <= ① "num_partitions": 20 <= ② }, "size": 10000, <= ③ "order": { "last_access": "asc" } }, "aggs": { "last_access": { "max": { "field": "access_date" } } } } } }
account_id
を Term とし、 Aggregation にて Term ごとに最大の access_date
を取得します(これを last_access
とする)
その際に、10,000 件ごと(③)のパーティションを 20 作成(②)し、そのパーティションの 0 番目(①)を取得する、というクエリです。
このクエリを使って、パーティションごとに 20 回リクエストすることで、合計 200,000 件の Term を取得できます。
※ 実際は partition
の指定を 0〜19 と変えてリクエストします
取得したいTerm数と、設定値の関係
取得したいTerm数と、設定値の関係は以下のとおりです。
注意事項
この手法を使うにあたり、以下の注意事項があります。
partition
は、順に指定する必要はありません。- 取得したい term数 = num_partitions × size としている場合、データが欠落する可能性があります。(これが 未満 とした理由です)
- 1つのパーティションで取得できるterm数は
size
の値より小さくなる場合があるため、より厳密に取得したい場合は、取得したいterm数より大きい数にする必要があります。
- 1つのパーティションで取得できるterm数は
- ソート指定は不可です。
- Termのソートを行うことはできないため、ソートした大量データの一部のみ分割して取得するといったことはできません。
まとめ
今回は、 Aggregate 結果が大量データになった時に、パーティショニングを用いて全データを取得する方法について発見しました。 この方法を使うことで、10,000 件を超えるデータを取得する際にも、効率的にデータを取得することができます。
以上、Amazon OpenSearch Service のパーティショニングについてのTipsでした。
参考
- Terms aggregation | Elasticsearch Guide [8.16] | Elastic
- OpenSearchの公式ドキュメントにパーティショニングに関する記載がなかったためElasticSearchを参照しています。