拥有子文档查询
has_child
查询返回其子文档与特定查询匹配的父文档。您可以通过使用 join 字段类型,在同一索引中的文档之间建立父子关系。
has_child
查询由于其执行的连接操作,比其他查询慢。随着指向不同父文档的匹配子文档数量增加,性能会下降。搜索中的每个 has_child
查询都可能显著影响查询性能。如果您优先考虑速度,请避免使用此查询或尽可能限制其使用。
示例
在运行 has_child
查询之前,您的索引必须包含一个 join 字段,以便建立父子关系。索引映射请求使用以下格式
PUT /example_index
{
"mappings": {
"properties": {
"relationship_field": {
"type": "join",
"relations": {
"parent_doc": "child_doc"
}
}
}
}
}
在此示例中,您将配置一个包含表示产品及其品牌的文档的索引。
首先,创建索引并建立 brand
和 product
之间的父子关系
PUT testindex1
{
"mappings": {
"properties": {
"product_to_brand": {
"type": "join",
"relations": {
"brand": "product"
}
}
}
}
}
索引两个父(品牌)文档
PUT testindex1/_doc/1
{
"name": "Luxury brand",
"product_to_brand" : "brand"
}
PUT testindex1/_doc/2
{
"name": "Economy brand",
"product_to_brand" : "brand"
}
索引三个子(产品)文档
PUT testindex1/_doc/3?routing=1
{
"name": "Mechanical watch",
"sales_count": 150,
"product_to_brand": {
"name": "product",
"parent": "1"
}
}
PUT testindex1/_doc/4?routing=2
{
"name": "Electronic watch",
"sales_count": 300,
"product_to_brand": {
"name": "product",
"parent": "2"
}
}
PUT testindex1/_doc/5?routing=2
{
"name": "Digital watch",
"sales_count": 100,
"product_to_brand": {
"name": "product",
"parent": "2"
}
}
要搜索子文档的父文档,请使用 has_child
查询。以下查询返回制造手表的父文档(品牌)
GET testindex1/_search
{
"query" : {
"has_child": {
"type":"product",
"query": {
"match" : {
"name": "watch"
}
}
}
}
}
响应返回两个品牌
{
"took": 15,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 2,
"relation": "eq"
},
"max_score": 1,
"hits": [
{
"_index": "testindex1",
"_id": "1",
"_score": 1,
"_source": {
"name": "Luxury brand",
"product_to_brand": "brand"
}
},
{
"_index": "testindex1",
"_id": "2",
"_score": 1,
"_source": {
"name": "Economy brand",
"product_to_brand": "brand"
}
}
]
}
}
检索内部匹配项
要返回匹配查询的子文档,请提供 inner_hits
参数
GET testindex1/_search
{
"query" : {
"has_child": {
"type":"product",
"query": {
"match" : {
"name": "watch"
}
},
"inner_hits": {}
}
}
}
响应的 inner_hits
字段中包含子文档
{
"took": 52,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 2,
"relation": "eq"
},
"max_score": 1,
"hits": [
{
"_index": "testindex1",
"_id": "1",
"_score": 1,
"_source": {
"name": "Luxury brand",
"product_to_brand": "brand"
},
"inner_hits": {
"product": {
"hits": {
"total": {
"value": 1,
"relation": "eq"
},
"max_score": 0.53899646,
"hits": [
{
"_index": "testindex1",
"_id": "3",
"_score": 0.53899646,
"_routing": "1",
"_source": {
"name": "Mechanical watch",
"sales_count": 150,
"product_to_brand": {
"name": "product",
"parent": "1"
}
}
}
]
}
}
}
},
{
"_index": "testindex1",
"_id": "2",
"_score": 1,
"_source": {
"name": "Economy brand",
"product_to_brand": "brand"
},
"inner_hits": {
"product": {
"hits": {
"total": {
"value": 2,
"relation": "eq"
},
"max_score": 0.53899646,
"hits": [
{
"_index": "testindex1",
"_id": "4",
"_score": 0.53899646,
"_routing": "2",
"_source": {
"name": "Electronic watch",
"sales_count": 300,
"product_to_brand": {
"name": "product",
"parent": "2"
}
}
},
{
"_index": "testindex1",
"_id": "5",
"_score": 0.53899646,
"_routing": "2",
"_source": {
"name": "Digital watch",
"sales_count": 100,
"product_to_brand": {
"name": "product",
"parent": "2"
}
}
}
]
}
}
}
}
]
}
}
有关检索内部匹配项的更多信息,请参阅 内部匹配项。
参数
下表列出了 has_child
查询支持的所有顶级参数。
参数 | 必需/可选 | 描述 |
---|---|---|
类型 | 必需 | 指定在 join 字段映射中定义的子关系名称。 |
查询 | 必需 | 在子文档上运行的查询。如果子文档匹配查询,则返回父文档。 |
忽略未映射 | 可选 | 指示是否忽略未映射的 type 字段,不返回文档而不是抛出错误。在查询多个索引时可以提供此参数,其中一些索引可能不包含 type 字段。默认值为 false 。 |
最大子文档数 | 可选 | 父文档的最大匹配子文档数。如果超出,则父文档将从搜索结果中排除。 |
最小子文档数 | 可选 | 父文档包含在结果中所需的最小匹配子文档数。如果未达到,则父文档将被排除。默认值为 1 。 |
评分模式 | 可选 | 定义匹配子文档的评分如何影响父文档的评分。有效值包括 - none :忽略子文档的相关性评分,并为父文档分配 0 分。- avg :使用所有匹配子文档的平均相关性评分。- max :将匹配子文档中的最高相关性评分分配给父文档。- min :将匹配子文档中的最低相关性评分分配给父文档。- sum :累加所有匹配子文档的相关性评分。默认值为 none 。 |
内部命中 | 可选 | 如果提供,则返回匹配查询的底层命中(子文档)。 |
排序限制
has_child
查询不支持使用标准排序选项对结果进行排序。如果您需要按子文档中的字段对父文档进行排序,可以使用 function_score
查询并按父文档的评分进行排序。
在前面的示例中,您可以根据子产品的 sales_count
对父文档(品牌)进行排序。此查询将评分乘以子文档的 sales_count
字段,并将匹配子文档中的最高相关性评分分配给父文档
GET testindex1/_search
{
"query": {
"has_child": {
"type": "product",
"query": {
"function_score": {
"script_score": {
"script": "_score * doc['sales_count'].value"
}
}
},
"score_mode": "max"
}
}
}
响应包含按子文档 sales_count
最高值排序的品牌
{
"took": 6,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 2,
"relation": "eq"
},
"max_score": 300,
"hits": [
{
"_index": "testindex1",
"_id": "2",
"_score": 300,
"_source": {
"name": "Economy brand",
"product_to_brand": "brand"
}
},
{
"_index": "testindex1",
"_id": "1",
"_score": 150,
"_source": {
"name": "Luxury brand",
"product_to_brand": "brand"
}
}
]
}
}
后续步骤
- 了解更多关于 检索内部匹配项 的信息。