Amazon OpenSearch Service ( ElasticSearch ) で Terms Aggregation のパーティショニング - 株式会社CINC 開発本部 エンジニアブログ

株式会社CINC 開発本部 エンジニアブログ

ビッグデータ取得・自然言語処理・人工知能(AI)開発を軸に、マーケティングソリューションの開発や、DX推進を行っている、株式会社CINCの開発本部です。

Amazon OpenSearch Service ( ElasticSearch ) で Terms Aggregation のパーティショニング

こんにちは、株式会社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分割したパーティションの総数
size1つのパーティションに含める 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数と、設定値の関係は以下のとおりです。

 \text{取得したいTerm数} \lt \text{size} \times \text{num_partitions}

注意事項

この手法を使うにあたり、以下の注意事項があります。

  • partition は、順に指定する必要はありません。
    • 初めに partition = 3 のリクエストを発行した後、 partition = 1 のリクエストを発行しても問題ないです。
    • 並行処理で取得することも可能です。
  • 取得したい term数 = num_partitions × size としている場合、データが欠落する可能性があります。(これが 未満 とした理由です)
    • 1つのパーティションで取得できるterm数は size の値より小さくなる場合があるため、より厳密に取得したい場合は、取得したいterm数より大きい数にする必要があります。
  • ソート指定は不可です。
    • Termのソートを行うことはできないため、ソートした大量データの一部のみ分割して取得するといったことはできません。

まとめ

今回は、 Aggregate 結果が大量データになった時に、パーティショニングを用いて全データを取得する方法について発見しました。 この方法を使うことで、10,000 件を超えるデータを取得する際にも、効率的にデータを取得することができます。

以上、Amazon OpenSearch Service のパーティショニングについてのTipsでした。

参考