Link Search Menu Expand Document Documentation Menu

拥有子文档查询

has_child 查询返回其子文档与特定查询匹配的父文档。您可以通过使用 join 字段类型,在同一索引中的文档之间建立父子关系。

has_child 查询由于其执行的连接操作,比其他查询慢。随着指向不同父文档的匹配子文档数量增加,性能会下降。搜索中的每个 has_child 查询都可能显著影响查询性能。如果您优先考虑速度,请避免使用此查询或尽可能限制其使用。

示例

在运行 has_child 查询之前,您的索引必须包含一个 join 字段,以便建立父子关系。索引映射请求使用以下格式

PUT /example_index
{
  "mappings": {
    "properties": {
      "relationship_field": {
        "type": "join",
        "relations": {
          "parent_doc": "child_doc"
        }
      }
    }
  }
}

在此示例中,您将配置一个包含表示产品及其品牌的文档的索引。

首先,创建索引并建立 brandproduct 之间的父子关系

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"
        }
      }
    ]
  }
}

后续步骤

剩余 350 字符

有问题?

想做贡献?