Агрегат ElasticSearch для вложенного поля со сценарием

У меня есть следующее сопоставление в моем индексе ElasticSearch (упрощенное, поскольку другие поля не имеют значения):

      {
  "test": {
    "mappings": {
      "properties": {
        "name": {
          "type": "keyword"
        },
        "entities": {
          "type": "nested",
          "properties": {
            "text_property": {
              "type": "text"
            },
            "float_property": {
              "type": "float"
            }
          }
        }
      }
    }
  }
}

Данные выглядят так (опять же упрощенно):

      [
  {
    "name": "a",
    "entities": [
      {
        "text_property": "foo",
        "float_property": 0.2
      },
      {
        "text_property": "bar",
        "float_property": 0.4
      },
      {
        "text_property": "baz",
        "float_property": 0.6
      }
    ]
  },
  {
    "name": "b",
    "entities": [
      {
        "text_property": "foo",
        "float_property": 0.9
      }
    ]
  },
  {
    "name": "c",
    "entities": [
      {
        "text_property": "foo",
        "float_property": 0.2
      },
      {
        "text_property": "bar",
        "float_property": 0.9
      }
    ]
  }
]

Я пытаюсь выполнить агрегацию ведра по максимальному значению для каждого документа. Таким образом, для приведенного выше примера желаемым ответом будет следующее:

      ...
{
  "buckets": [
    {
      "key": "0.9",
      "doc_count": 2
    },
    {
      "key": "0.6",
      "doc_count": 1
    }
  ]
}

как документ aнаибольшее вложенное значение для float_property0,6, bэто 0,9 и cэто 0,9.

Я пробовал использовать смесь nestedа также aggs, вместе с runtime_mappings, но я не уверен, в каком порядке их использовать и возможно ли это вообще.

2 ответа

Я создал индекс с вашими сопоставлениями, изменив тип float_property на double.

      PUT testindex
{
 "mappings": {
      "properties": {
        "name": {
          "type": "keyword"
        },
        "entities": {
          "type": "nested",
          "include_in_parent": true, 
          "properties": {
            "text_property": {
              "type": "text"
            },
            "float_property": {
              "type": "double"
            }
          }
        }
      }
    }
}

Добавлено «include_in_parent»: true для «вложенного» типа.

Проиндексировали документы:

      PUT testindex/_doc/1
{
    "name": "a",
    "entities": [
      {
        "text_property": "foo",
        "float_property": 0.2
      },
      {
        "text_property": "bar",
        "float_property": 0.4
      },
      {
        "text_property": "baz",
        "float_property": 0.6
      }
    ]
  }
 
PUT testindex/_doc/2
{
    "name": "b",
    "entities": [
      {
        "text_property": "foo",
        "float_property": 0.9
      }
    ]
  }
  
PUT testindex/_doc/3 
{
    "name": "c",
    "entities": [
      {
        "text_property": "foo",
        "float_property": 0.2
      },
      {
        "text_property": "bar",
        "float_property": 0.9
      }
    ]
  }

Затем агрегация терминов по вложенному полю:

      POST testindex/_search
{
  "from": 0,
  "size": 30,
  "query": {
    "match_all": {}
  },
  "aggregations": {
    "entities.float_property": {
      "terms": {
        "field": "entities.float_property"
      }
    }
  }
}

Это дает результат агрегации, как показано ниже:

      "aggregations" : {
    "entities.float_property" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 0,
      "buckets" : [
        {
          "key" : 0.2,
          "doc_count" : 2
        },
        {
          "key" : 0.9,
          "doc_count" : 2
        },
        {
          "key" : 0.4,
          "doc_count" : 1
        },
        {
          "key" : 0.6,
          "doc_count" : 1
        }
      ]
    }
  }

Мне удалось понять это в конце концов.

Две вещи, которые я не понял, были:

  1. Вы можете предоставить scriptвместо fieldключ к агрегации ведра.
  2. Вместо использования запросов вы можете получить доступ к вложенным значениям напрямую, используя params._source.

Сочетание этих двух вещей позволило мне написать правильный запрос:

      {
  "size": 0,
  "aggs": {
    "max.float_property": {
      "terms": {
        "script": "double max = 0; for (item in params._source.entities) { if (item.float_property > max) { max = item.float_property; }} return max;"
      }
    }
  }
}

Ответ:

      {
  ...
  "aggregations": {
    "max.float_property": {
      "doc_count_error_upper_bound": 0,
      "sum_other_doc_count": 0,
      "buckets": [
        {
          "key": "0.9",
          "doc_count": 2
        },
        {
          "key": "0.6",
          "doc_count": 1
        }
      ]
    }
  }
}

Однако я запутался, потому что думал, что правильный способ доступа к полям - использовать nestedтип запроса. К сожалению, для этого очень мало документации, поэтому я все еще не уверен, является ли это предполагаемым/правильным способом агрегирования вложенных полей со сценариями.