#elasticsearch
Вопрос:
Я хочу вернуть документы, которые включают только некоторые элементы полей массива.
Например, у меня есть два документа заказа:
{
"orderNumber":"ORD-111",
"items":[{"name":"part-1","status":"new"},
{"name":"part-2","status":"paid"}]
}
{
"orderNumber":"ORD-112",
"items":[{"name":"part-3","status":"paid"},
{"name":"part-4","status":"supplied"}]
}
Я хочу создать запрос, чтобы мой результат включал все документы заказа, но только с элементами, которые соответствуют {«статус»:»поставлено»}.
Результат должен выглядеть так:
{
"orderNumber":"ORD-111",
"items":[]
}
{
"orderNumber":"ORD-112",
"items":[{"name":"part-4","status":"supplied"}]
}
Ответ №1:
Вы можете использовать вложенный запрос вместе с inner_hits
тем, чтобы получить в результате только соответствующие значения массива
Добавление рабочего примера
Сопоставление индексов:
{
"mappings": {
"properties": {
"items": {
"type": "nested"
}
}
}
}
Поисковый запрос:
{
"query": {
"nested": {
"path": "items",
"query": {
"bool": {
"must": [
{
"match": {
"items.status": "supplied"
}
}
]
}
},
"inner_hits": {}
}
}
}
Результат поиска:
"hits": [
{
"_index": "67890614",
"_type": "_doc",
"_id": "2",
"_score": 1.2039728,
"_source": {
"orderNumber": "ORD-112",
"items": [
{
"name": "part-3",
"status": "paid"
},
{
"name": "part-4",
"status": "supplied"
}
]
},
"inner_hits": {
"items": {
"hits": {
"total": {
"value": 1,
"relation": "eq"
},
"max_score": 1.2039728,
"hits": [
{
"_index": "67890614",
"_type": "_doc",
"_id": "2",
"_nested": {
"field": "items",
"offset": 1
},
"_score": 1.2039728,
"_source": {
"name": "part-4",
"status": "supplied" // note this
}
}
]
}
}
}
}
]
Комментарии:
1. @Дэнни Барак, у вас была возможность ознакомиться с ответом, с нетерпением жду ваших отзывов 🙂
2. Спасибо @ESCOder, я знаком и понимаю этот подход. Я все еще задаюсь вопросом, следует ли устанавливать сопоставление перед созданием индекса или его можно установить и для существующего индекса. Другое дело, как будет работать сортировка после фильтрации.
3. @DannyBarack вам необходимо создать сопоставление перед индексированием данных, вы не можете обновить это сопоставление в существующем индексе
Ответ №2:
Elasticsearch удаляет соответствующее поле, поэтому не может определить, какой элемент в массиве был фактическим, который соответствует.
Как уже было сказано ранее, вы можете использовать вложенные запросы.
Как сглаживаются массивы объектов Elasticsearch не имеет понятия о внутренних объектах. Поэтому он сглаживает иерархии объектов в простой список имен полей и значений. Например, рассмотрим следующий документ:
PUT my-index-000001/_doc/1
{
"group" : "fans",
"user" : [
{
"first" : "John",
"last" : "Smith"
},
{
"first" : "Alice",
"last" : "White"
}
]
}
Поле пользователя динамически добавляется как поле типа объект.
Предыдущий документ будет внутренне преобразован в документ, который больше похож на этот:
{
"group" : "fans",
"user.first" : [ "alice", "john" ],
"user.last" : [ "smith", "white" ]
}
Пользователь.первый и пользователь.последние поля сглаживаются в многозначные поля, и связь между Алисой и белым теряется. Этот документ неверно соответствовал бы запросу для Алисы И Смита:
GET my-index-000001/_search
{
"query": {
"bool": {
"must": [
{ "match": { "user.first": "Alice" }},
{ "match": { "user.last": "Smith" }}
]
}
}
}
Чтобы ответить на ваш вопрос:
Если вам нужно индексировать массивы объектов и поддерживать независимость каждого объекта в массиве, используйте вложенный тип данных вместо объектного типа данных.
Внутренне вложенные объекты индексируют каждый объект в массиве как отдельный скрытый документ, что означает, что каждый вложенный объект может быть запрошен независимо от других с помощью вложенного запроса:
PUT my-index-000001
{
"mappings": {
"properties": {
"user": {
"type": "nested"
}
}
}
}
PUT my-index-000001/_doc/1
{
"group" : "fans",
"user" : [
{
"first" : "John",
"last" : "Smith"
},
{
"first" : "Alice",
"last" : "White"
}
]
}
GET my-index-000001/_search
{
"query": {
"nested": {
"path": "user",
"query": {
"bool": {
"must": [
{ "match": { "user.first": "Alice" }},
{ "match": { "user.last": "Smith" }}
]
}
}
}
}
}
GET my-index-000001/_search
{
"query": {
"nested": {
"path": "user",
"query": {
"bool": {
"must": [
{ "match": { "user.first": "Alice" }},
{ "match": { "user.last": "White" }}
]
}
},
"inner_hits": {
"highlight": {
"fields": {
"user.first": {}
}
}
}
}
}
}
Поле пользователя отображается как вложенный тип вместо объекта типа.
Этот запрос не совпадает, потому что Алиса и Смит не находятся в одном и том же вложенном объекте.
Этот запрос совпадает, потому что Алиса и Уайт находятся в одном и том же вложенном объекте.
inner_hits позволяют нам выделить соответствующие вложенные документы.
Взаимодействие с вложенными документами Вложенные документы могут быть:
запрос выполняется с помощью вложенного запроса. анализируется с помощью вложенных и обратных вложенных агрегаций. сортируется с помощью вложенной сортировки. извлечено и выделено вложенными внутренними ссылками. Поскольку вложенные документы индексируются как отдельные документы, доступ к ним возможен только в рамках вложенного запроса, вложенных/обратных агрегаций или вложенных внутренних обращений.
при использовании этого подхода учитывайте производительность, поскольку она на порядок дороже.
для получения более подробной информации
вы можете проверить источник: https://www.elastic.co/guide/en/elasticsearch/reference/current/nested.html