Ответ
Поля типа 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 полей увеличивает размер индекса и немного замедляет запросы, поэтому их следует применять только тогда, когда сохранение связей внутри объектов массива действительно необходимо.
Ответ 18+ 🔞
О, слушай, а вот есть в Elasticsearch такая штука, которая с первого взгляда кажется простой, а потом бац — и ты уже сидишь и думаешь: «Ёпта, а почему мой запрос находит какую-то дичь?». Это всё про поля типа nested, сука.
Представь себе, у тебя есть документ с отзывами, ну, обычное дело:
{
"reviews": [
{ "author": "John", "rating": 5 },
{ "author": "Alice", "rating": 1 }
]
}
И вроде бы всё логично: Джон — молодец, поставил пятёрку, а Алиса — хитрая жопа, вкатила единицу. Но Elasticsearch по умолчанию, этот, блядь, умник, поступает как полный распиздяй: он берёт и «уплощает» этот массив. В итоге внутри индекса получается каша:
"reviews.author": ["John", "Alice"],
"reviews.rating": [5, 1]
Связь между полями — на хуй! И вот ты такой пишешь запрос: «Найди мне, где автор John и рейтинг 1». А эта мудя тебе радостно подсовывает документ выше! Потому что John в массиве есть, и 1 в массиве есть. А то, что это разные объекты — да похуй, блядь. Вот это пиздец, да? Запрос врёт, как сивый мерин.
Так вот, чтобы не было такого пиздеца, и придумали nested. Это как сказать Elasticsearch: «Э, сабака сука, не размазывай мне всё в одну кучу, индексируй каждый объект в массиве отдельно, как скрытый документ!».
1. Сначала настраиваешь маппинг, чтоб всё было чётко:
PUT /products
{
"mappings": {
"properties": {
"reviews": {
"type": "nested"
}
}
}
}
Всё, теперь reviews — не просто объект, а nested. Связи внутри каждого отзыва сохранятся.
2. А чтобы искать по этому полю, нужно использовать специальный nested query:
GET /products/_search
{
"query": {
"nested": {
"path": "reviews",
"query": {
"bool": {
"must": [
{ "match": { "reviews.author": "John" }},
{ "range": { "reviews.rating": { "gte": 4 }}}
]
}
}
}
}
}
Смотри, какой красивый запрос. Он ищет ВНУТРИ одного вложенного документа. То есть найдёт только те продукты, где есть отзыв именно от John И именно с рейтингом 4 или выше. А наш предыдущий пример, где John (5) и Alice (1) — уже не подойдёт, потому что это два разных вложенных документа. Ура, блядь, логика восторжествовала!
Но, конечно, за всё хорошее надо платить. Nested поля жрут больше памяти и слегка тормозят запросы. Так что юзай их с умом, только когда реально нужно сохранить связь между полями внутри объекта. А то накрутишь этих nested на овердохуища — и потом будешь чесать репу, почему индекс раздулся как шарик, а поиск еле ползёт. В общем, думай головой, а не жопой.