Spec-Zone.ru › Elasticsearch 8
›Elasticsearch Guide [8.17] ›Query DSL ›Объединение запросов

Запрос nested

Оборачивает другой запрос для поиска полей nested.

Запрос nested ищет объекты вложенного поля как будто они индексированы как отдельные документы. Если объект соответствует поиску, запрос nested возвращает родительский документ корня.

Пример запроса

Настройка индекса

Для использования запроса nested ваш индекс должен включать отображение поля nested. Например:

resp = client.indices.create(
    index="my-index-000001",
    mappings={
        "properties": {
            "obj1": {
                "type": "nested"
            }
        }
    },
)
print(resp)
response = client.indices.create(
  index: 'my-index-000001',
  body: {
    mappings: {
      properties: {
        "obj1": {
          type: 'nested'
        }
      }
    }
  }
)
puts response
res, err := es.Indices.Create(
	"my-index-000001",
	es.Indices.Create.WithBody(strings.NewReader(`{
	  "mappings": {
	    "properties": {
	      "obj1": {
	        "type": "nested"
	      }
	    }
	  }
	}`)),
)
fmt.Println(res, err)
const response = await client.indices.create({
  index: "my-index-000001",
  mappings: {
    properties: {
      obj1: {
        type: "nested",
      },
    },
  },
});
console.log(response);
PUT /my-index-000001
{
  "mappings": {
    "properties": {
      "obj1": {
        "type": "nested"
      }
    }
  }
}

Пример запроса

resp = client.search(
    index="my-index-000001",
    query={
        "nested": {
            "path": "obj1",
            "query": {
                "bool": {
                    "must": [
                        {
                            "match": {
                                "obj1.name": "blue"
                            }
                        },
                        {
                            "range": {
                                "obj1.count": {
                                    "gt": 5
                                }
                            }
                        }
                    ]
                }
            },
            "score_mode": "avg"
        }
    },
)
print(resp)
response = client.search(
  index: 'my-index-000001',
  body: {
    query: {
      nested: {
        path: 'obj1',
        query: {
          bool: {
            must: [
              {
                match: {
                  "obj1.name": 'blue'
                }
              },
              {
                range: {
                  "obj1.count": {
                    gt: 5
                  }
                }
              }
            ]
          }
        },
        score_mode: 'avg'
      }
    }
  }
)
puts response
res, err := es.Search(
	es.Search.WithIndex("my-index-000001"),
	es.Search.WithBody(strings.NewReader(`{
	  "query": {
	    "nested": {
	      "path": "obj1",
	      "query": {
	        "bool": {
	          "must": [
	            {
	              "match": {
	                "obj1.name": "blue"
	              }
	            },
	            {
	              "range": {
	                "obj1.count": {
	                  "gt": 5
	                }
	              }
	            }
	          ]
	        }
	      },
	      "score_mode": "avg"
	    }
	  }
	}`)),
	es.Search.WithPretty(),
)
fmt.Println(res, err)
const response = await client.search({
  index: "my-index-000001",
  query: {
    nested: {
      path: "obj1",
      query: {
        bool: {
          must: [
            {
              match: {
                "obj1.name": "blue",
              },
            },
            {
              range: {
                "obj1.count": {
                  gt: 5,
                },
              },
            },
          ],
        },
      },
      score_mode: "avg",
    },
  },
});
console.log(response);
GET /my-index-000001/_search
{
  "query": {
    "nested": {
      "path": "obj1",
      "query": {
        "bool": {
          "must": [
            { "match": { "obj1.name": "blue" } },
            { "range": { "obj1.count": { "gt": 5 } } }
          ]
        }
      },
      "score_mode": "avg"
    }
  }
}

Параметры верхнего уровня для запроса nested

path
(Обязательно, строка) Путь к вложенному объекту, который вы хотите искать.
query

(Обязательно, объект запроса) Запрос, который вы хотите выполнить для вложенных объектов в path. Если объект соответствует поиску, запрос nested возвращает родительский документ корня.

Вы можете искать вложенные поля с помощью нотации точек, которая включает полный путь, например obj1.name.

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

См. Многоуровневые запросы nested для примера.

score_mode

(Необязательно, строка) Указывает, как баллы соответствия дочерних объектов влияют на релевантность корневого родительского документа. Допустимые значения:

avg (По умолчанию)
Используется средний балл релевантности всех соответствующих дочерних объектов.
max
Используется наивысший балл релевантности всех соответствующих дочерних объектов.
min
Используется наименьший балл релевантности всех соответствующих дочерних объектов.
none
Баллы релевантности соответствующих дочерних объектов не используются. Запрос присваивает родительским документам балл 0.
sum
Складываются баллы релевантности всех соответствующих дочерних объектов.
ignore_unmapped

(Необязательно, Булево) Указывает, игнорировать ли неотображенное поле path и не возвращать документы вместо ошибки. По умолчанию false.

Если false, Elasticsearch возвращает ошибку, если поле path не отображено.

Вы можете использовать этот параметр для запроса к нескольким индексам, которые могут не содержать поля path.

Примечания

Контекст запросов сценариев

Если вы выполняете запрос сценария script внутри вложенного запроса, вы можете получить доступ только к значениям документов из вложенного документа, а не из родительского или корневого документа.

Многоуровневые запросы nested

Чтобы увидеть, как работают многоуровневые запросы nested, сначала вам нужен индекс с вложенными полями. Следующий запрос определяет отображения для индекса drivers с вложенными полями make и model.

resp = client.indices.create(
    index="drivers",
    mappings={
        "properties": {
            "driver": {
                "type": "nested",
                "properties": {
                    "last_name": {
                        "type": "text"
                    },
                    "vehicle": {
                        "type": "nested",
                        "properties": {
                            "make": {
                                "type": "text"
                            },
                            "model": {
                                "type": "text"
                            }
                        }
                    }
                }
            }
        }
    },
)
print(resp)
response = client.indices.create(
  index: 'drivers',
  body: {
    mappings: {
      properties: {
        driver: {
          type: 'nested',
          properties: {
            last_name: {
              type: 'text'
            },
            vehicle: {
              type: 'nested',
              properties: {
                make: {
                  type: 'text'
                },
                model: {
                  type: 'text'
                }
              }
            }
          }
        }
      }
    }
  }
)
puts response
res, err := es.Indices.Create(
	"drivers",
	es.Indices.Create.WithBody(strings.NewReader(`{
	  "mappings": {
	    "properties": {
	      "driver": {
	        "type": "nested",
	        "properties": {
	          "last_name": {
	            "type": "text"
	          },
	          "vehicle": {
	            "type": "nested",
	            "properties": {
	              "make": {
	                "type": "text"
	              },
	              "model": {
	                "type": "text"
	              }
	            }
	          }
	        }
	      }
	    }
	  }
	}`)),
)
fmt.Println(res, err)
const response = await client.indices.create({
  index: "drivers",
  mappings: {
    properties: {
      driver: {
        type: "nested",
        properties: {
          last_name: {
            type: "text",
          },
          vehicle: {
            type: "nested",
            properties: {
              make: {
                type: "text",
              },
              model: {
                type: "text",
              },
            },
          },
        },
      },
    },
  },
});
console.log(response);
PUT /drivers
{
  "mappings": {
    "properties": {
      "driver": {
        "type": "nested",
        "properties": {
          "last_name": {
            "type": "text"
          },
          "vehicle": {
            "type": "nested",
            "properties": {
              "make": {
                "type": "text"
              },
              "model": {
                "type": "text"
              }
            }
          }
        }
      }
    }
  }
}

Затем добавьте некоторые документы в индекс drivers.

$params = [
    'index' => 'drivers',
    'id' => '1',
    'body' => [
        'driver' => [
            'last_name' => 'McQueen',
            'vehicle' => [
                [
                    'make' => 'Powell Motors',
                    'model' => 'Canyonero',
                ],
                [
                    'make' => 'Miller-Meteor',
                    'model' => 'Ecto-1',
                ],
            ],
        ],
    ],
];
$response = $client->index($params);
$params = [
    'index' => 'drivers',
    'id' => '2',
    'body' => [
        'driver' => [
            'last_name' => 'Hudson',
            'vehicle' => [
                [
                    'make' => 'Mifune',
                    'model' => 'Mach Five',
                ],
                [
                    'make' => 'Miller-Meteor',
                    'model' => 'Ecto-1',
                ],
            ],
        ],
    ],
];
$response = $client->index($params);
resp = client.index(
    index="drivers",
    id="1",
    document={
        "driver": {
            "last_name": "McQueen",
            "vehicle": [
                {
                    "make": "Powell Motors",
                    "model": "Canyonero"
                },
                {
                    "make": "Miller-Meteor",
                    "model": "Ecto-1"
                }
            ]
        }
    },
)
print(resp)

resp1 = client.index(
    index="drivers",
    id="2",
    refresh=True,
    document={
        "driver": {
            "last_name": "Hudson",
            "vehicle": [
                {
                    "make": "Mifune",
                    "model": "Mach Five"
                },
                {
                    "make": "Miller-Meteor",
                    "model": "Ecto-1"
                }
            ]
        }
    },
)
print(resp1)
response = client.index(
  index: 'drivers',
  id: 1,
  body: {
    driver: {
      last_name: 'McQueen',
      vehicle: [
        {
          make: 'Powell Motors',
          model: 'Canyonero'
        },
        {
          make: 'Miller-Meteor',
          model: 'Ecto-1'
        }
      ]
    }
  }
)
puts response

response = client.index(
  index: 'drivers',
  id: 2,
  refresh: true,
  body: {
    driver: {
      last_name: 'Hudson',
      vehicle: [
        {
          make: 'Mifune',
          model: 'Mach Five'
        },
        {
          make: 'Miller-Meteor',
          model: 'Ecto-1'
        }
      ]
    }
  }
)
puts response
{
	res, err := es.Index(
		"drivers",
		strings.NewReader(`{
	  "driver": {
	    "last_name": "McQueen",
	    "vehicle": [
	      {
	        "make": "Powell Motors",
	        "model": "Canyonero"
	      },
	      {
	        "make": "Miller-Meteor",
	        "model": "Ecto-1"
	      }
	    ]
	  }
	}`),
		es.Index.WithDocumentID("1"),
		es.Index.WithPretty(),
	)
	fmt.Println(res, err)
}

{
	res, err := es.Index(
		"drivers",
		strings.NewReader(`{
	  "driver": {
	    "last_name": "Hudson",
	    "vehicle": [
	      {
	        "make": "Mifune",
	        "model": "Mach Five"
	      },
	      {
	        "make": "Miller-Meteor",
	        "model": "Ecto-1"
	      }
	    ]
	  }
	}`),
		es.Index.WithDocumentID("2"),
		es.Index.WithRefresh("true"),
		es.Index.WithPretty(),
	)
	fmt.Println(res, err)
}
const response = await client.index({
  index: "drivers",
  id: 1,
  document: {
    driver: {
      last_name: "McQueen",
      vehicle: [
        {
          make: "Powell Motors",
          model: "Canyonero",
        },
        {
          make: "Miller-Meteor",
          model: "Ecto-1",
        },
      ],
    },
  },
});
console.log(response);

const response1 = await client.index({
  index: "drivers",
  id: 2,
  refresh: "true",
  document: {
    driver: {
      last_name: "Hudson",
      vehicle: [
        {
          make: "Mifune",
          model: "Mach Five",
        },
        {
          make: "Miller-Meteor",
          model: "Ecto-1",
        },
      ],
    },
  },
});
console.log(response1);
PUT /drivers/_doc/1
{
  "driver" : {
        "last_name" : "McQueen",
        "vehicle" : [
            {
                "make" : "Powell Motors",
                "model" : "Canyonero"
            },
            {
                "make" : "Miller-Meteor",
                "model" : "Ecto-1"
            }
        ]
    }
}

PUT /drivers/_doc/2?refresh
{
  "driver" : {
        "last_name" : "Hudson",
        "vehicle" : [
            {
                "make" : "Mifune",
                "model" : "Mach Five"
            },
            {
                "make" : "Miller-Meteor",
                "model" : "Ecto-1"
            }
        ]
    }
}

Теперь вы можете использовать многоуровневый запрос nested для соответствия документам на основе полей make и model.

resp = client.search(
    index="drivers",
    query={
        "nested": {
            "path": "driver",
            "query": {
                "nested": {
                    "path": "driver.vehicle",
                    "query": {
                        "bool": {
                            "must": [
                                {
                                    "match": {
                                        "driver.vehicle.make": "Powell Motors"
                                    }
                                },
                                {
                                    "match": {
                                        "driver.vehicle.model": "Canyonero"
                                    }
                                }
                            ]
                        }
                    }
                }
            }
        }
    },
)
print(resp)
response = client.search(
  index: 'drivers',
  body: {
    query: {
      nested: {
        path: 'driver',
        query: {
          nested: {
            path: 'driver.vehicle',
            query: {
              bool: {
                must: [
                  {
                    match: {
                      'driver.vehicle.make' => 'Powell Motors'
                    }
                  },
                  {
                    match: {
                      'driver.vehicle.model' => 'Canyonero'
                    }
                  }
                ]
              }
            }
          }
        }
      }
    }
  }
)
puts response
res, err := es.Search(
	es.Search.WithIndex("drivers"),
	es.Search.WithBody(strings.NewReader(`{
	  "query": {
	    "nested": {
	      "path": "driver",
	      "query": {
	        "nested": {
	          "path": "driver.vehicle",
	          "query": {
	            "bool": {
	              "must": [
	                {
	                  "match": {
	                    "driver.vehicle.make": "Powell Motors"
	                  }
	                },
	                {
	                  "match": {
	                    "driver.vehicle.model": "Canyonero"
	                  }
	                }
	              ]
	            }
	          }
	        }
	      }
	    }
	  }
	}`)),
	es.Search.WithPretty(),
)
fmt.Println(res, err)
const response = await client.search({
  index: "drivers",
  query: {
    nested: {
      path: "driver",
      query: {
        nested: {
          path: "driver.vehicle",
          query: {
            bool: {
              must: [
                {
                  match: {
                    "driver.vehicle.make": "Powell Motors",
                  },
                },
                {
                  match: {
                    "driver.vehicle.model": "Canyonero",
                  },
                },
              ],
            },
          },
        },
      },
    },
  },
});
console.log(response);
GET /drivers/_search
{
  "query": {
    "nested": {
      "path": "driver",
      "query": {
        "nested": {
          "path": "driver.vehicle",
          "query": {
            "bool": {
              "must": [
                { "match": { "driver.vehicle.make": "Powell Motors" } },
                { "match": { "driver.vehicle.model": "Canyonero" } }
              ]
            }
          }
        }
      }
    }
  }
}

Запрос возвращает следующий ответ:

{
  "took" : 5,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 3.7349272,
    "hits" : [
      {
        "_index" : "drivers",
        "_id" : "1",
        "_score" : 3.7349272,
        "_source" : {
          "driver" : {
            "last_name" : "McQueen",
            "vehicle" : [
              {
                "make" : "Powell Motors",
                "model" : "Canyonero"
              },
              {
                "make" : "Miller-Meteor",
                "model" : "Ecto-1"
              }
            ]
          }
        }
      }
    ]
  }
}

must_not и nested запросы

Если запрос nested соответствует одному или нескольким вложенным объектам в документе, он возвращает документ как результат. Это применимо даже если другие вложенные объекты в документе не соответствуют запросу. Имейте это в виду при использовании запроса nested, который содержит внутреннее условие must_not.

Используйте параметр inner_hits, чтобы увидеть, какие вложенные объекты соответствуют запросу nested.

Например, следующий запрос использует внешний запрос nested с внутренним условием must_not.

resp = client.indices.create(
    index="my-index",
    mappings={
        "properties": {
            "comments": {
                "type": "nested"
            }
        }
    },
)
print(resp)

resp1 = client.index(
    index="my-index",
    id="1",
    refresh=True,
    document={
        "comments": [
            {
                "author": "kimchy"
            }
        ]
    },
)
print(resp1)

resp2 = client.index(
    index="my-index",
    id="2",
    refresh=True,
    document={
        "comments": [
            {
                "author": "kimchy"
            },
            {
                "author": "nik9000"
            }
        ]
    },
)
print(resp2)

resp3 = client.index(
    index="my-index",
    id="3",
    refresh=True,
    document={
        "comments": [
            {
                "author": "nik9000"
            }
        ]
    },
)
print(resp3)

resp4 = client.search(
    index="my-index",
    query={
        "nested": {
            "path": "comments",
            "query": {
                "bool": {
                    "must_not": [
                        {
                            "term": {
                                "comments.author": "nik9000"
                            }
                        }
                    ]
                }
            }
        }
    },
)
print(resp4)
response = client.indices.create(
  index: 'my-index',
  body: {
    mappings: {
      properties: {
        comments: {
          type: 'nested'
        }
      }
    }
  }
)
puts response

response = client.index(
  index: 'my-index',
  id: 1,
  refresh: true,
  body: {
    comments: [
      {
        author: 'kimchy'
      }
    ]
  }
)
puts response

response = client.index(
  index: 'my-index',
  id: 2,
  refresh: true,
  body: {
    comments: [
      {
        author: 'kimchy'
      },
      {
        author: 'nik9000'
      }
    ]
  }
)
puts response

response = client.index(
  index: 'my-index',
  id: 3,
  refresh: true,
  body: {
    comments: [
      {
        author: 'nik9000'
      }
    ]
  }
)
puts response

response = client.search(
  index: 'my-index',
  body: {
    query: {
      nested: {
        path: 'comments',
        query: {
          bool: {
            must_not: [
              {
                term: {
                  'comments.author' => 'nik9000'
                }
              }
            ]
          }
        }
      }
    }
  }
)
puts response
const response = await client.indices.create({
  index: "my-index",
  mappings: {
    properties: {
      comments: {
        type: "nested",
      },
    },
  },
});
console.log(response);

const response1 = await client.index({
  index: "my-index",
  id: 1,
  refresh: "true",
  document: {
    comments: [
      {
        author: "kimchy",
      },
    ],
  },
});
console.log(response1);

const response2 = await client.index({
  index: "my-index",
  id: 2,
  refresh: "true",
  document: {
    comments: [
      {
        author: "kimchy",
      },
      {
        author: "nik9000",
      },
    ],
  },
});
console.log(response2);

const response3 = await client.index({
  index: "my-index",
  id: 3,
  refresh: "true",
  document: {
    comments: [
      {
        author: "nik9000",
      },
    ],
  },
});
console.log(response3);

const response4 = await client.search({
  index: "my-index",
  query: {
    nested: {
      path: "comments",
      query: {
        bool: {
          must_not: [
            {
              term: {
                "comments.author": "nik9000",
              },
            },
          ],
        },
      },
    },
  },
});
console.log(response4);
PUT my-index
{
  "mappings": {
    "properties": {
      "comments": {
        "type": "nested"
      }
    }
  }
}

PUT my-index/_doc/1?refresh
{
  "comments": [
    {
      "author": "kimchy"
    }
  ]
}

PUT my-index/_doc/2?refresh
{
  "comments": [
    {
      "author": "kimchy"
    },
    {
      "author": "nik9000"
    }
  ]
}

PUT my-index/_doc/3?refresh
{
  "comments": [
    {
      "author": "nik9000"
    }
  ]
}

POST my-index/_search
{
  "query": {
    "nested": {
      "path": "comments",
      "query": {
        "bool": {
          "must_not": [
            {
              "term": {
                "comments.author": "nik9000"
              }
            }
          ]
        }
      }
    }
  }
}

Запрос возвращает:

{
  ...
  "hits" : {
    ...
    "hits" : [
      {
        "_index" : "my-index",
        "_id" : "1",
        "_score" : 0.0,
        "_source" : {
          "comments" : [
            {
              "author" : "kimchy"
            }
          ]
        }
      },
      {
        "_index" : "my-index",
        "_id" : "2",
        "_score" : 0.0,
        "_source" : {
          "comments" : [
            {
              "author" : "kimchy"              
            },
            {
              "author" : "nik9000"             
            }
          ]
        }
      }
    ]
  }
}

Этот вложенный объект соответствует запросу. В результате запрос возвращает родительский документ объекта как результат.

Этот вложенный объект не соответствует запросу. Поскольку другой вложенный объект в том же документе соответствует запросу, запрос все равно возвращает родительский документ как результат.

Чтобы исключить документы с вложенными объектами, которые соответствуют запросу nested, используйте внешнее условие must_not.

resp = client.search(
    index="my-index",
    query={
        "bool": {
            "must_not": [
                {
                    "nested": {
                        "path": "comments",
                        "query": {
                            "term": {
                                "comments.author": "nik9000"
                            }
                        }
                    }
                }
            ]
        }
    },
)
print(resp)
response = client.search(
  index: 'my-index',
  body: {
    query: {
      bool: {
        must_not: [
          {
            nested: {
              path: 'comments',
              query: {
                term: {
                  'comments.author' => 'nik9000'
                }
              }
            }
          }
        ]
      }
    }
  }
)
puts response
const response = await client.search({
  index: "my-index",
  query: {
    bool: {
      must_not: [
        {
          nested: {
            path: "comments",
            query: {
              term: {
                "comments.author": "nik9000",
              },
            },
          },
        },
      ],
    },
  },
});
console.log(response);
POST my-index/_search
{
  "query": {
    "bool": {
      "must_not": [
        {
          "nested": {
            "path": "comments",
            "query": {
              "term": {
                "comments.author": "nik9000"
              }
            }
          }
        }
      ]
    }
  }
}

Запрос возвращает:

{
  ...
  "hits" : {
    ...
    "hits" : [
      {
        "_index" : "my-index",
        "_id" : "1",
        "_score" : 0.0,
        "_source" : {
          "comments" : [
            {
              "author" : "kimchy"
            }
          ]
        }
      }
    ]
  }
}

© 2023-2025 Elasticsearch
As of September 2024, Elasticsearch is available under a choice of three licenses: the Server Side Public License (SSPL), the Elastic License, or the AGPLv3 (OSI approved).
Elasticsearch and the Elasticsearch logo are trademarks of Elasticsearch B.V., registered in the U.S. and in other countries.
https://www.elastic.co/guide/en/elasticsearch/reference/8.17/query-dsl-nested-query.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API