はてだBlog(仮称)

私的なブログど真ん中のつもりでしたが、気づけばWebサイト系のアプリケーション開発周りで感じたこと寄りの自分メモなどをつれづれ述べています。2020年6月現在、Elasticsearch、pandas、CMSなどに関する話題が多めです。...ですが、だんだんとより私的なプログラムのスニペット置き場になりつつあります。ブログで述べている内容は所属組織で販売している製品などに関するものではなく、また所属する組織の見解を代表するものではありません。

Elasticsearchのネストしたaggsの検索結果をflat形式で戻してくれるComposite aggregationのさわり

拙ブログに、「Elasticsearch aggs/aggregations flat」で検索して迷いこむ方がいらっしゃるようです。

flat」というところから、もしかして?、と思いまして、あらためて Elasticsearch のAggregationのひとつのCompositeに入門してみましたので、せっかくお越しいただいた方の参考になるかもということで、ご紹介します。

www.elastic.co

確認した、Elasticsearchのバージョンは6.8です。

なお、このブログでComposite以外のAggregationを試した他の記事はこちらです。

itdepends.hateblo.jp

itdepends.hateblo.jp

itdepends.hateblo.jp

Composite aggregationと他のaggsの違い(compositeの嬉しいこと:検索結果がflatな配列で戻る)

Composite aggregation以外の例を先にご紹介してから、対比でComposite aggregationのメリットをお伝えすることにします。

他の記事にも例示しましたが、ElasticsearchのAggregationは、バケットの組み合わせ・掛け合わせができます。

例えば、Compositeではない(おそらくもっとメジャーな普通の)Aggregationの例では、次のクエリで(もちろんインデックスの作り次第ですが)、 都道府県ごとの、該当カテゴリごとの飲食店数が得られます。

POST /飲食店インデックス/_search
{
  "aggs": {
    "bk1": {
      "terms": {
        "field": "都道府県",
        "size": 50
      },
      "aggs": {
        "bk2": {
          "terms": {
            "field": "飲食カテゴリ",
            "size": 100
          }
        }
      }
    }
  }
}

このクエリでは、検索結果の表現方法が、都道府県が親で飲食カテゴリが子のJSONとなります。

例えば、次のようなイメージです。

{
    bk1:{
        buckets:[
            {
              key:東京都,
              bk2:{
                buckets:[
                   {
                    key:ラーメン,
                    doc_count: 1000
                   },
                   {
                    key:フレンチ,
                    doc_count: 500
                   }
                ]
              }
            },
        ]
    }
}

ここで、好みの範囲なのですが、上記の例であれば、次のような戻し方をしてくれると嬉しいな〜と思いませんか。 このような戻り値の形式、ある種のflat/フラットな表現で結果が得られると嬉しいなというのが、「Composite Aggregations」です。

{
    buckets:[
       {
        key1:東京都,
        key2:ラーメン,
        doc_count: 1000
       },
       {
        key1:東京都,
        key2:フレンチ,
        doc_count: 500
       }
       ...
    ]
}

Composite aggregationクエリの例

ということで、「Composite aggregation」の例です。

「compostite」プロパティで制御します。また、ポイントは「sources」の中です。 ちなみに、terms以外も、ヒストグラムなどいくつかの、集計の方法が指定できます。

GET /インデックス名/_search
{
  "aggs": {
    "my_buckets": {
      "composite": {
        "sources": [
          { "prefecture": { "terms": { "field": "集計対象のフィールド_都道府県"} } },
          { "category": { "terms": { "field": "集計対象のフィールド_レストランカテゴリ" } } }
          /* ここに他にも条件を加えたければ追加可能 */
        ],
        "size": 10000
      }
    }
  }
}

結果の例

先のクエリの戻りは次のようになります。

トップレベルのbucketsの中で、都道府県と飲食カテゴリの組み合わせの配列が得られますね。

{
  "aggregations" : {
    "my_buckets" : {
      "buckets" : [
        {
          "key" : {
            "prefecture" : "東京都",
            "category" : "焼き鳥"
          },
          "doc_count" : 2181
        },
        {
          "key" : {
            "prefecture" : "東京都",
            "category" : "焼きとん",
           },
          "doc_count" : 18
        },
        {
          "key" : {
            "prefecture" : "東京都",
            "category" : "焼きそば・焼きうどん",
          },
          "doc_count" : 120
        },
        ...

}

注意事項など

Compositeに限らず、Aggregationは重い処理なので、性能などや、sizeの指定件数等はよろしくお気をつけください。

それ以外では、他のAggregationにぶら下げる無印の「terms」と次のようなところが異なるところです。

1) 取得件数は、compositeプロパティの直下のsizeで指定できます。

2) 他のaggsでは可能な、doc_count順のソートができません。

3) termsは、keyの昇順・降順の並び指定が、orderパラメータで指定できます。 繰り返しますが、doc_count順のソートはできません。

aggregationsの無印のtermsとは少し違いますね。

参考:無印のterms Terms aggregation | Elasticsearch Reference [7.11] | Elastic

4) 上記の戻り値イメージでは割愛したのですが、戻り値のトップフィールドに「buckets」と同じ並びに、「after_key」というものがあります。 「after_key」には、buckets配列の最後のエントリと同じものが入っています。一見不思議な項目なのですが、検索結果が多い場合のページネーションの目印となります。 具体的には、この値を同じ条件のaggs-compositeクエリの「after」フィールドに指定してやることで、それ以降のエントリを取得することができます。

戻り値をフラットな形式にしてくれるとともに、1)、2)、3)のような挙動から察するに、他のAggregationに比べて、全パターンを取得したい/取得せざるを得ない要件において、ページネーションしながら使って良いよ、という方針かなと思いました。