Что такое поля типа `nested` в Elasticsearch и какую проблему они решают?

Ответ

Поля типа nested в Elasticsearch позволяют индексировать массивы объектов таким образом, чтобы сохранить внутреннюю связь между полями каждого объекта в массиве.

Проблема, которую решает nested

По умолчанию Elasticsearch "уплощает" массивы объектов. Рассмотрим документ с отзывами:

{
  "reviews": [
    { "author": "John", "rating": 5 },
    { "author": "Alice", "rating": 1 }
  ]
}

При стандартном индексировании (тип object) данные сохранятся так:

"reviews.author": ["John", "Alice"],
"reviews.rating": [5, 1]

Связь между автором и его оценкой теряется. Из-за этого запрос "найти документы, где автор John и рейтинг 1" ошибочно найдет этот документ, так как оба значения присутствуют в соответствующих массивах, хоть и в разных объектах.

Как nested решает эту проблему

Тип nested заставляет Elasticsearch индексировать каждый объект в массиве как отдельный, скрытый внутренний документ. Это сохраняет связи.

1. Определение маппинга:

PUT /products
{
  "mappings": {
    "properties": {
      "reviews": {
        "type": "nested" 
      }
    }
  }
}

2. Поиск по nested полю:

Для запросов к таким полям используется специальный nested query. Он ищет совпадения в рамках одного внутреннего документа.

GET /products/_search
{
  "query": {
    "nested": {
      "path": "reviews",
      "query": {
        "bool": {
          "must": [
            { "match": { "reviews.author": "John" }},
            { "range": { "reviews.rating": { "gte": 4 }}}
          ]
        }
      }
    }
  }
}

Этот запрос найдет только те продукты, где есть отзыв от John с рейтингом 4 или выше. Запрос на author: "John" и rating: 1 уже не найдет документ из примера выше, что является корректным поведением.

Важно: Использование nested полей увеличивает размер индекса и немного замедляет запросы, поэтому их следует применять только тогда, когда сохранение связей внутри объектов массива действительно необходимо.