Потребность во вложенном типе (Nested Type)
Для того, чтобы понять зачем это нужно рассмотрим пример.
Добавляем водителей, которые находятся в разных городах и работают в разных компаниях:
POST denormalized_cars/_bulk
{"index":{"_id":1}}
{"id":"1","title":"True","drivers":[{"name":"Egor Hdasda","company":{"country":{"name":"Shymkent"},"name":"Ebobo"}},{"name":"Gabdi Popopo","company":{"country":{"name":"Astana"},"name":"Olx"}}]}
{"index":{"_id":2}}
{"id":"2","title":"False","drivers":[{"name":"Gabdi Overton","company":{"country":{"name":"Shymkent"},"name":"Globex"}},{"name":"Egor Fghgfhgfh","company":{"country":{"name":"Almaty"},"name":"Olx"}}]}
{"index":{"_id":3}}
{"id":"3","title":"False","drivers":[{"name":"Egor Hdasda","company":{"country":{"name":"Shymkent"},"name":"Ebobo"}},{"name":"Gabdi Popopo","company":{"country":{"name":"Astana"},"name":"Olx"}},{"name":"Tim Roes","company":{"country":{"name":"Japan"},"name":"Kiwi"}}]}
Делаем запрос для выборки водителя Egor, работающего в Olx:
GET denormalized_cars/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"drivers.name": "egor"
}
},
{
"match": {
"drivers.company.name.keyword": "Olx"
}
}
]
}
}
}
А в итоге получаем ответ, в котором все водители (у правильного в title прописано true).
Теперь разберёмся почему собственно так вышло. Поля name и company.name являются внутренними объектами JSON поля массива drivers. Когда вы индексируете документ в Elasticsearch, объект JSON разделяется в соответствии с внутренними требованиями Lucene. Ожидаемая связь между name и company.name теряется. Т.е они разбиваются на 2 несвязанных поля.
Для того, чтобы не было таких ситуаций как раз и используется вложенной тип.
Вложенный тип данных
Создаём индекс используя nested:
PUT nested_cars
{
"mappings": {
"properties": {
"id": {
"type": "keyword"
},
"title": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword"
}
}
},
"drivers": {
"type": "nested",
"properties": {
"name": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword"
}
}
},
"company": {
"type": "object",
"properties": {
"name": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword"
}
}
},
"country": {
"type": "object",
"properties": {
"name": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword"
}
}
}
}
}
}
}
}
}
}
}
}
POST nested_cars/_bulk
{"index":{"_id":1}}
{"id":"1","title":"False","drivers":[{"name":"Egor Hdasda","company":{"country":{"name":"Shymkent"},"name":"Ebobo"}},{"name":"Gabdi Popopo","company":{"country":{"name":"Astana"},"name":"Olx"}}]}
{"index":{"_id":2}}
{"id":"2","title":"True","drivers":[{"name":"Gabdi Overton","company":{"country":{"name":"Shymkent"},"name":"Globex"}},{"name":"Egor Fghgfhgfh","company":{"country":{"name":"Almaty"},"name":"Olx"}}]}
{"index":{"_id":3}}
{"id":"3","title":"False","drivers":[{"name":"Egor Hdasda","company":{"country":{"name":"Shymkent"},"name":"Ebobo"}},{"name":"Gabdi Popopo","company":{"country":{"name":"Astana"},"name":"Olx"}},{"name":"Tim Roes","company":{"country":{"name":"Japan"},"name":"Kiwi"}}]}
И делаем запрос используя nested:
GET nested_cars/_search
{
"query": {
"nested": {
"path": "drivers",
"query": {
"bool": {
"must": [
{
"match": {
"drivers.name": "egor"
}
},
{
"match": {
"drivers.company.name.keyword": "Olx"
}
}
]
}
}
}
}
}
И получаем в итоге только один документ с правильным водителем:
"title" : "True",
"drivers" : [
{
"name" : "Gabdi Overton",
"company" : {
"country" : {
"name" : "Shymkent"
},
"name" : "Globex"
}
},
{
"name" : "Egor Fghgfhgfh",
"company" : {
"country" : {
"name" : "Almaty"
},
"name" : "Olx"
}
}
]
В итоге
- Вложенный тип позволяет индексировать и запрашивать массивы объектов независимо друг от друга.
- Обновление вложенного объекта требует полной переиндексации корневого объекта и всех его других вложенных объектов.
Комментарии