web-dev-qa-db-ja.com

複数のフィールドを持つElasticsearch集計を取得する方法

現在表示されているタグに関連するタグを見つけようとしています。インデックス内のすべてのドキュメントにはタグが付けられています。各タグは、IDとテキスト名の2つの部分で構成されています。

{
    ...
    meta: {
        ...
        tags: [
            {
                id: 123,
                name: 'Biscuits'
            },
            {
                id: 456,
                name: 'Cakes'
            },
            {
                id: 789,
                name: 'Breads'
            }
        ]
    }
}

関連するタグを取得するには、単にドキュメントをクエリし、それらのタグの集計を取得するだけです。

{
    "query": {
        "bool": {
            "must": [
                {
                    "match": {
                        "item.meta.tags.id": "123"
                    }
                },
                {
                    ...
                }
            ]
        }
    },
    "aggs": {
        "baked_goods": {
            "terms": {
                "field": "item.meta.tags.id",
                "min_doc_count": 2
            }
        }
    }
}

これは完全に機能し、希望する結果が得られます。ただし、便利なことを行うには、タグID and nameの両方が必要です。私はこれを達成する方法を探求しましたが、解決策は次のようです:

  1. インデックス作成時にフィールドを結合します
  2. フィールドを一緒にむちゃくちゃにするスクリプト
  3. ネストされた集約

オプション1と2は利用できないため、3を使用していましたが、期待どおりに応答しません。次のクエリがある場合(「Biscuits」でタグ付けされたドキュメントも検索中):

{
    ...
    "aggs": {
        "baked_goods": {
            "terms": {
                "field": "item.meta.tags.id",
                "min_doc_count": 2
            },
            "aggs": {
                "name": {
                    "terms": {
                        "field": "item.meta.tags.name"
                    }
                }
            }
        }
    }
}

私はこの結果を取得します:

{
    ...
    "aggregations": {
        "baked_goods": {
            "buckets": [
                {
                    "key": "456",
                    "doc_count": 11,
                    "name": {
                        "buckets": [
                            {
                                "key": "Biscuits",
                                "doc_count": 11
                            },
                            {
                                "key": "Cakes",
                                "doc_count": 11
                            }
                        ]
                    }
                }
            ]
        }
    }
}

ネストされた集約には、検索語andの後に続くタグ(アルファベット順に返される)の両方が含まれます。

ネストされた集約にexcludeを追加することでこれを軽減しようとしましたが、これによりクエリの速度が大幅に低下しました(500000ドキュメントで約100倍)。これまでのところ、最速の解決策は結果を手動で重複排除することです。

応答にタグIDとタグ名の両方を持つタグの集約を取得する最良の方法は何ですか?

ここまで作ってくれてありがとう!

37
i_like_robots

見た目では、あなたのtagsnestedではありません。この集計が機能するためには、 _nestedidの間に関連があるように、name が必要です。 nestedがなければ、idsのリストは単なる配列であり、namesのリストは別の配列です。

    "item": {
      "properties": {
        "meta": {
          "properties": {
            "tags": {
              "type": "nested",           <-- nested field
              "include_in_parent": true,  <-- to, also, keep the flat array-like structure
              "properties": {
                "id": {
                  "type": "integer"
                },
                "name": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    }

また、この行"include_in_parent": trueのマッピングに追加したことに注意してください。これはnestedタグも「フラットな」配列のような構造のように動作することを意味します。

そのため、これまでクエリで使用していたすべてが、クエリに変更を加えなくても機能します。

ただし、この特定のクエリでは、集計を次のように変更する必要があります。

{
  "aggs": {
    "baked_goods": {
      "nested": {
        "path": "item.meta.tags"
      },
      "aggs": {
        "name": {
          "terms": {
            "field": "item.meta.tags.id"
          },
          "aggs": {
            "name": {
              "terms": {
                "field": "item.meta.tags.name"
              }
            }
          }
        }
      }
    }
  }
}

結果は次のようになります。

   "aggregations": {
      "baked_goods": {
         "doc_count": 9,
         "name": {
            "doc_count_error_upper_bound": 0,
            "sum_other_doc_count": 0,
            "buckets": [
               {
                  "key": 123,
                  "doc_count": 3,
                  "name": {
                     "doc_count_error_upper_bound": 0,
                     "sum_other_doc_count": 0,
                     "buckets": [
                        {
                           "key": "biscuits",
                           "doc_count": 3
                        }
                     ]
                  }
               },
               {
                  "key": 456,
                  "doc_count": 2,
                  "name": {
                     "doc_count_error_upper_bound": 0,
                     "sum_other_doc_count": 0,
                     "buckets": [
                        {
                           "key": "cakes",
                           "doc_count": 2
                        }
                     ]
                  }
               },
               .....
48
Andrei Stefan