嵌套查询
编辑嵌套查询
编辑包装另一个查询以搜索嵌套字段。
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
。自动支持并检测多级嵌套,从而产生一个内部嵌套查询,以自动匹配相关的嵌套级别,而不是根,如果它存在于另一个嵌套查询中。
有关示例,请参阅多级嵌套查询。
-
score_mode
-
(可选,字符串)指示匹配的子对象的得分如何影响根父文档的相关性得分。有效值为
-
avg
(默认) - 使用所有匹配的子对象的平均相关性得分。
-
max
- 使用所有匹配的子对象的最高相关性得分。
-
min
- 使用所有匹配的子对象的最低相关性得分。
-
none
- 不使用匹配的子对象的相关性得分。该查询为父文档分配
0
的分数。 -
sum
- 将所有匹配的子对象的相关性得分相加。
-
-
ignore_unmapped
-
(可选,布尔值)指示是否忽略未映射的
path
且不返回任何文档,而不是返回错误。默认为false
。如果为
false
,则如果path
是未映射的字段,Elasticsearch 将返回错误。您可以使用此参数来查询可能不包含字段
path
的多个索引。
注释
编辑多级嵌套查询
编辑要了解多级嵌套查询的工作原理,首先需要一个具有嵌套字段的索引。以下请求定义了带有嵌套 make
和 model
字段的 drivers
索引的映射。
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" } ] } }
您现在可以使用多级嵌套查询来匹配基于 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
查询匹配文档中的一个或多个嵌套对象,它将返回该文档作为命中项。即使文档中的其他嵌套对象与查询不匹配,也是如此。当使用包含内部 must_not
子句的 nested
查询时,请记住这一点。
使用inner_hits
参数查看哪些嵌套对象与 nested
查询匹配。
例如,以下搜索使用带有内部 must_not
子句的外部 nested
查询。
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" } ] } } ] } }