文章目录
ElasticSearch Query DSL(五)
连接查询
在像ElasticSearch这样的分布式搜索引擎上执行完整的SQL连接查询是非常昂贵的。相反ElasticSearch提供了两种形式的连接查询,这样的查询被设计用来水平扩展的。
- 嵌套查询:文档可能包含
nested
类型的字段。这些字段被用来索引对象数组,其中每个对象都可以作为独立的文档进行查询。 has child
和has parent
:join field relationship
字段连接关系可以存在一个单独索引内的文档之间。has child
查询返回子文档与指定查询匹配的父文档,而has_parent
查询返回父文档与指定查询匹配的子文档
提示:设置search.allow_expensive_queries
为false
,关闭连接查询
嵌套查询
包装另一个查询用来搜索嵌套字段
nested
查询搜索嵌套字段,就好像搜索一个独立的索引文档一样。如果对象与搜索匹配,则嵌套查询会返回root parent
的文档。
查询例子
使用嵌套查询之前,你必须包含一个nested
映射。例如:
curl -X PUT "localhost:9200/my-index-000001?pretty" -H 'Content-Type: application/json' -d'
{
"mappings": {
"properties": {
"obj1": {
"type": "nested"
}
}
}
}
'
以下嵌套查询例子:
curl -X GET "localhost:9200/my-index-000001/_search?pretty" -H 'Content-Type: application/json' -d'
{
"query": {
"nested": {
"path": "obj1",
"query": {
"bool": {
"must": [
{ "match": { "obj1.name": "blue" } },
{ "range": { "obj1.count": { "gt": 5 } } }
]
}
},
"score_mode": "avg"
}
}
}
'
<nested>
顶级参数
-
path:(必须,字符串),你希望查询的嵌套对象的路径
-
query:(必须,查询对象),你希望在
<path>
路径中的嵌套对象上运行的查询。如果嵌套对象匹配到搜索,nested
查询会返回root parent
文档。您可以使用包含完整路径的点表示法搜索嵌套字段,例如
obj1.name
自动支持多级嵌套,并检测多级嵌套,从而导致内部嵌套查询自动匹配相关嵌套级别
有关示例,请参阅
Multi-level nested queries
-
score_mode:(可选,字符串),指定匹配到的子对象的相关性分数如果影响root parent文档的相关性分数。有效值为:
- avg:(默认)
- max
- min
- none
- sum
-
ignored_umapped:(可选,布尔),是否忽略未映射的
<path>
并且不返回任何文档而不是错误。默认为false
。如果为 false,并且
<path>
是未映射的字段,则 Elasticsearch 将返回错误。您可以使用此参数查询可能不包含字段
<path>
的多个索引。
多级嵌套查询
要了解多级嵌套查询的工作原理,首先你需要具有一个嵌套字段的索引。以下请求为包含make
和model
嵌套字段的driver
索引定义映射。
curl -X PUT "localhost:9200/drivers?pretty" -H 'Content-Type: application/json' -d'
{
"mappings": {
"properties": {
"driver": {
"type": "nested",
"properties": {
"last_name": {
"type": "text"
},
"vehicle": {
"type": "nested",
"properties": {
"make": {
"type": "text"
},
"model": {
"type": "text"
}
}
}
}
}
}
}
}
'
然后,在索引中添加一些文档:
curl -X PUT "localhost:9200/drivers/_doc/1?pretty" -H 'Content-Type: application/json' -d'
{
"driver" : {
"last_name" : "McQueen",
"vehicle" : [
{
"make" : "Powell Motors",
"model" : "Canyonero"
},
{
"make" : "Miller-Meteor",
"model" : "Ecto-1"
}
]
}
}
'
curl -X PUT "localhost:9200/drivers/_doc/2?refresh&pretty" -H 'Content-Type: application/json' -d'
{
"driver" : {
"last_name" : "Hudson",
"vehicle" : [
{
"make" : "Mifune",
"model" : "Mach Five"
},
{
"make" : "Miller-Meteor",
"model" : "Ecto-1"
}
]
}
}
'
现在可以使用make
和model
嵌套字段来进行多级嵌套查询了:
curl -X GET "localhost:9200/drivers/_search?pretty" -H 'Content-Type: application/json' -d'
{
"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",
"_type" : "_doc",
"_id" : "1",
"_score" : 3.7349272,
"_source" : {
"driver" : {
"last_name" : "McQueen",
"vehicle" : [
{
"make" : "Powell Motors",
"model" : "Canyonero"
},
{
"make" : "Miller-Meteor",
"model" : "Ecto-1"
}
]
}
}
}
]
}
}
has child查询
返回与提供查询相匹配的子文档的父文档。你可以使用join
字段映射在相同索引内的文档之间创建父子关系。
提示:由于执行了join
查询,所以has child
相比其他查询性能要低。
查询例子
为了使用has child
查询,你的索引映射必须包含join
字段。
curl -X PUT "localhost:9200/my-index-000001?pretty" -H 'Content-Type: application/json' -d'
{
"mappings": {
"properties": {
"my-join-field": {
"type": "join",
"relations": {
"parent": "child"
}
}
}
}
}
'
开始查询:
curl -X GET "localhost:9200/_search?pretty" -H 'Content-Type: application/json' -d'
{
"query": {
"has_child": {
"type": "child",
"query": {
"match_all": {}
},
"max_children": 10,
"min_children": 2,
"score_mode": "min"
}
}
}
'
排序
你不能使用标准的排序选项对has child
查询结果进行排序。
如果您需要按子文档中的字段对返回的文档进行排序,请使用 function_score
查询并按 _score
排序。例如,以下查询按其子文档的 click_count 字段对返回的文档进行排序。
curl -X GET "localhost:9200/_search?pretty" -H 'Content-Type: application/json' -d'
{
"query": {
"has_child": {
"type": "child",
"query": {
"function_score": {
"script_score": {
"script": "_score * doc[\u0027click_count\u0027].value"
}
}
},
"score_mode": "max"
}
}
}
'
has parent查询
返回与提供查询相匹配的父文档的子文档。你可以使用join
字段映射在相同索引内的文档之间创建父子关系。
查询例子
为了使用has parent
查询,你的索引映射必须包含join
字段。
curl -X PUT "localhost:9200/my-index-000001?pretty" -H 'Content-Type: application/json' -d'
{
"mappings": {
"properties": {
"my-join-field": {
"type": "join",
"relations": {
"parent": "child"
}
},
"tag": {
"type": "keyword"
}
}
}
}
'
开始查询:
curl -X GET "localhost:9200/my-index-000001/_search?pretty" -H 'Content-Type: application/json' -d'
{
"query": {
"has_parent": {
"parent_type": "parent",
"query": {
"term": {
"tag": {
"value": "Elasticsearch"
}
}
}
}
}
}
'
排序
你不能使用标准的排序选项对has parent
查询结果进行排序。
如果您需要按子文档中的字段对返回的文档进行排序,请使用 function_score
查询并按 _score
排序。例如,以下查询按其子文档的 click_count 字段对返回的文档进行排序。
curl -X GET "localhost:9200/_search?pretty" -H 'Content-Type: application/json' -d'
{
"query": {
"has_parent": {
"parent_type": "parent",
"score": true,
"query": {
"function_score": {
"script_score": {
"script": "_score * doc[\u0027view_count\u0027].value"
}
}
}
}
}
}
'
parent ID查询
返回连接到特定父文档的子文档。可以使用连接字段映射在同一个索引中的文档之间创建父子关系。
查询例子
要使用parent_id
查询,您的索引必须包含一个连接字段映射。要了解如何为parent_id
查询设置索引,请尝试下面的示例。
使用连接字段映射创建索引。
curl -X PUT "localhost:9200/my-index-000001?pretty" -H 'Content-Type: application/json' -d'
{
"mappings": {
"properties": {
"my-join-field": {
"type": "join",
"relations": {
"my-parent": "my-child"
}
}
}
}
}
'
索引 ID 为 1 的父文档。
curl -X PUT "localhost:9200/my-index-000001/_doc/1?refresh&pretty" -H 'Content-Type: application/json' -d'
{
"text": "This is a parent document.",
"my-join-field": "my-parent"
}
'
索引父文档的子文档。
curl -X PUT "localhost:9200/my-index-000001/_doc/2?routing=1&refresh&pretty" -H 'Content-Type: application/json' -d'
{
"text": "This is a child document.",
"my_join_field": {
"name": "my-child",
"parent": "1"
}
}
'
开始查询
curl -X GET "localhost:9200/my-index-000001/_search?pretty" -H 'Content-Type: application/json' -d'
{
"query": {
"parent_id": {
"type": "my-child",
"id": "1"
}
}
}
'