Подтвердить что ты не робот

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

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

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

Это отлично работает, я получаю результаты, которые я хочу. Однако мне требуется как идентификатор тега, так и имя, чтобы сделать что-нибудь полезное. Я изучил, как это сделать, решения выглядят так:

  • Объединить поля при индексировании
  • A script, чтобы объединить поля
  • Вложенная агрегация

Вариант один и два не доступны для меня, поэтому я собираюсь с 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 раз для 500 000 документов). До сих пор самым быстрым решением было обнулить результат вручную.

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

Спасибо за то, что сделали это так!

4b9b3361

Ответ 1

По внешнему виду ваш tags не nested. Чтобы эта агрегация работала, вам понадобится nested, чтобы была связь между id и a name. Без nested список id - это просто массив, а список name - это другой массив:

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