Как получить агрегацию Elasticsearch с несколькими полями

Я пытаюсь найти связанные теги с тем, который в настоящее время просматривается. Каждый документ в нашем индексе помечен. Каждый тег состоит из двух частей-ID и текстового имени:

{
    ...
    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 и имя, чтобы сделать что-нибудь полезное. Я исследовал, как этого решения представляется:

  1. объединить поля при индексации
  2. сценарий, чтобы munge вместе поля
  3. вложенные агрегации

вариант один и два недоступны для меня, поэтому я собирался с 3, но он не отвечает ожидаемым образом. Учитывая следующий запрос (все еще поиск документов, также помеченных "печенье"):

{
    ...
    "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
                            }
                        ]
                    }
                }
            ]
        }
    }
}

вложенная агрегация включает в себя как поисковый термин и тег, который я ищу (возвращается в алфавитном порядке).

Я попытался смягчить это, добавив exclude к вложенной агрегации, но это слишком сильно замедлило запрос (около 100 раз для 500000 документов). До сих пор самым быстрым решением является де-dupe результат вручную.

каков наилучший способ получить агрегацию тегов с идентификатором тега и тегом имя в ответе?

Спасибо за это!

1 ответов


судя по всему, ваш tags - это не nested. Чтобы эта агрегация работала,вам понадобится nested так что существует связь между id и a 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
                        }
                     ]
                  }
               },
               .....