嵌套查询编辑

包装另一个查询以搜索嵌套字段。

nested查询将嵌套字段对象搜索为单独的文档,就像它们被索引一样。如果一个对象匹配搜索,nested查询将返回根父文档。

示例请求编辑

索引设置编辑

要使用nested查询,您的索引必须包含一个嵌套字段映射。例如

resp = client.indices.create(
    index="my-index-000001",
    body={"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)
PUT /my-index-000001
{
  "mappings": {
    "properties": {
      "obj1": {
        "type": "nested"
      }
    }
  }
}

示例查询编辑

resp = 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",
            }
        }
    },
)
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)
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,则 Elasticsearch 会在path是未映射字段时返回错误。

您可以使用此参数查询可能不包含字段path的多个索引。

注意事项编辑

脚本查询的上下文编辑

如果您在嵌套查询中运行script查询,您只能访问嵌套文档中的文档值,而不能访问父文档或根文档。

多级嵌套查询编辑

要了解多级嵌套查询的工作原理,首先您需要一个具有嵌套字段的索引。以下请求定义了具有嵌套makemodel字段的drivers索引的映射。

resp = 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"},
                            },
                        },
                    },
                }
            }
        }
    },
)
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)
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",
    body={
        "driver": {
            "last_name": "McQueen",
            "vehicle": [
                {"make": "Powell Motors", "model": "Canyonero"},
                {"make": "Miller-Meteor", "model": "Ecto-1"},
            ],
        }
    },
)
print(resp)

resp = 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"},
            ],
        }
    },
)
print(resp)
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 response0 = await client.index({
  index: 'drivers',
  id: '1',
  body: {
    driver: {
      last_name: 'McQueen',
      vehicle: [
        {
          make: 'Powell Motors',
          model: 'Canyonero'
        },
        {
          make: 'Miller-Meteor',
          model: 'Ecto-1'
        }
      ]
    }
  }
})
console.log(response0)

const response1 = await 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'
        }
      ]
    }
  }
})
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"
            }
        ]
    }
}

现在,您可以使用多级嵌套查询根据makemodel字段匹配文档。

resp = 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"
                                        }
                                    },
                                ]
                            }
                        },
                    }
                },
            }
        }
    },
)
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)
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",
    body={"mappings": {"properties": {"comments": {"type": "nested"}}}},
)
print(resp)

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

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

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

resp = client.search(
    index="my-index",
    body={
        "query": {
            "nested": {
                "path": "comments",
                "query": {
                    "bool": {
                        "must_not": [
                            {"term": {"comments.author": "nik9000"}}
                        ]
                    }
                },
            }
        }
    },
)
print(resp)
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
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",
    body={
        "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
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"
            }
          ]
        }
      }
    ]
  }
}