Elasticsearch系列(15)Query之连接查询

1. 前言

在Elasticsearch这种分布式系统上执行完全类似SQL风格的连接查询代价比较高,作为替代,Elasticsearch提供了两种可水平伸缩的连接(Join)形式的查询。

  • 嵌套查询(nested query)
  • has_child和has_parent查询

2. 嵌套查询

嵌套查询(nested query)搜索嵌套(nested)类型的字段对象,就好像它们被索引为单独的文档一样。如果一个对象匹配搜索条件,嵌套查询将返回对象所在的父文档。
首先创建包含嵌套类型的映射的索引,示例如下:

PUT /my_index_01
{
    "mappings" : {
        "properties" : {
            "my_object" : {
                "type" : "nested"
            }
        }
    }
}
PUT /my_index_01/_doc/1
{
    "my_object" : [
      {"name": "blue", "count": 10},
      {"name": "red", "count": 1},
      {"name": "yellow", "count": 20}
    ]
}

通过嵌套查询,示例如下:

GET /my_index_01/_search
{
    "query":  {
        "nested" : {
            "path" : "my_object",
            "query" : {
                "bool" : {
                    "must" : [
                      { "match" : {"my_object.name" : "blue"} },
                      { "range" : {"my_object.count" : {"gt" : 5}} }
                    ]
                }
            },
            "score_mode" : "avg"
        }
    }
}
nested查询顶级参数
  • path:(必需的,string)要搜索的嵌套对象的路径。
  • query:(必需的,查询object)
    (1)在路径中的嵌套对象上运行的查询。
    (2)可以使用包含完整路径(带点符号)搜索嵌套字段,比如my_object.name。
    (3)自动支持并检测多层嵌套,内部嵌套查询自动匹配相关嵌套级别。
  • score_mode:(可选的,string)表示匹配子对象的分数如何影响父文档的相关性分数。参数有效值如下:
    (1)avg(默认):使用所有匹配子对象的相关性得分的平均值。
    (2)max:使用所有匹配子对象中相关性得分最高值。
    (3)min:使用所有匹配子对象中相关性得分最低值。
    (4)none:不使用匹配子对象的相关性得分,设置父文档相关性得分为0。
    (5)sum:将所有匹配子对象的相关性得分相加。
  • ignore_unmapped:(可选的,boolean)表示是否忽略未映射的path字段。如果设置为true,那么Elasticsearch遇到未映射的path字段输入值将会忽略错误,并且不返回任何文档。默认值为false,默认情况下,如果path字段输入值未映射,Elasticsearch将返回一个错误。
多级嵌套查询

首先定义一个多级嵌套索引并索引数据,示例如下:

PUT /my_index_02
{
  "mappings": {
    "properties": {
      "driver": {
        "type": "nested",
        "properties": {
          "last_name": {
            "type": "text"
          },
          "vehicle": {
            "type": "nested",
            "properties": {
              "make": {
                "type": "text"
              },
              "model": {
                "type": "text"
              }
            }
          }
        }
      }
    }
  }
}
PUT /my_index_02/_doc/1
{
  "driver": {
    "last_name": "McQueen",
    "vehicle": [
      {
        "make": "Powell Motors",
        "model": "Canyonero"
      },
      {
        "make": "Miller-Meteor",
        "model": "Ecto-1"
      }
    ]
  }
}
PUT /my_index_02/_doc/2?refresh
{
  "driver": {
    "last_name": "Hudson",
    "vehicle": [
      {
        "make": "Mifune",
        "model": "Mach Five"
      },
      {
        "make": "Miller-Meteor",
        "model": "Ecto-1"
      }
    ]
  }
}

多级嵌套查询,示例如下:

GET /my_index_02/_search
{
  "query": {
    "nested": {
      "path": "driver",
      "query": {
        "nested": {
          "path": "driver.vehicle",
          "query": {
            "bool": {
              "must": [
                {"match": { "driver.vehicle.make": "Powell Motors" }},
                {"match": { "driver.vehicle.model": "Canyonero" }}
              ]
            }
          }
        }
      }
    }
  }
}

3. has_child查询

如果连接(join)的子文档与所输入的查询匹配,那么返回父文档,可以使用连接(join)字段映射在同一个索引的文档之间创建父子关系,如果要使用has_child查询,索引必须包含一个连接(join)字段映射。
使用has_child查询,首先创建包含连接(join)类型字段的索引,示例如下:

PUT /my_index_03
{
  "mappings": {
    "properties": {
      "my_num": {
        "type": "keyword"
      },
      "view_count": {
        "type": "integer"
      },
      "my-join-field": {
        "type": "join",
        "relations": {
          "parent": "child"
        }
      }
    }
  }
}

然后索引父文档和子文档,示例如下:

# 创建父文档
PUT /my_index_03/_doc/1
{"my_num":"001", "view_count": 10, "my-join-field":{"name":"parent"}}
# 创建子文档,parent指定父文档id
PUT /my_index_03/_doc/2?routing=1&refresh
{
  "my_num": "002",
  "view_count": 5,
  "my-join-field": {
    "name": "child",
    "parent": "1"
  }
}

使用has_child查询来查询文档中子文档匹配条件的文档,示例如下:

GET my_index_03/_search
{
  "query": {
    "has_child": {
      "type": "child",
      "query": {
        "match_all": {}
      },
      "max_children": 10,
      "min_children": 1,
      "score_mode": "min"
    }
  }
}
has_child查询顶级参数
  • type:(必需的,string)指定连接子关系的名称。
  • query:(必需的,查询object)在type字段指定名称的子文档上运行的查询。如果其子文档与搜索匹配,查询将返回父文档。
  • max_children:(可选的,integer)父文档中匹配的最大子文档数。如果父文档超过了这个限制,则从搜索结果中排除它。
  • min_children:(可选的,integer)父文档中匹配所需的最小子文档数。如果父文档不满足此限制,则从搜索结果中排除它。
  • score_mode:(可选的,string)表示匹配子文档的分数如何影响父文档的相关性分数。参数有效值如下:
    (1)none(默认):不使用匹配子文档的相关性得分,查询返回的父文档相关性得分为0。
    (2)max:使用所有匹配子文档中相关性得分最高值。
    (3)min:使用所有匹配子文档中相关性得分最低值。
    (4)avg:使用所有匹配子文档的相关性得分的平均值。
    (5)sum:将所有匹配子文档的相关性得分相加。
  • ignore_unmapped:(可选的,boolean)表示是否忽略未映射的type字段。默认值为false,默认情况下,如果type字段输入值未映射,Elasticsearch将返回一个错误。
排序
  • 不支持标准排序选项对has_child查询的结果进行排序。
  • 如果需要对返回的文档进行排序,可以使用function_score查询并按_score排序。例如,下面的查询根据子文档的view_count字段对返回的文档进行排序,示例如下:
GET my_index_03/_search
{
  "query": {
    "has_child": {
      "type": "child",
      "query": {
        "function_score": {
          "script_score": {
            "script": "_score * doc['view_count'].value"
          }
        }
      },
      "score_mode": "max"
    }
  }
}

4. has_parent查询

如果连接(join)的父文档与所输入的查询匹配,那么返回子文档,可以使用连接(join)字段映射在同一个索引的文档之间创建父子关系。如果要使用has_parent查询,索引必须包含一个连接(join)字段映射。(与has_child查询用法类似)
使用has_parent查询,查询my_index_03索引中,文档的父文档中字段“my_num”值为“001”的子文档,示例如下:

GET /my_index_03/_search
{
  "query": {
    "has_parent": {
      "parent_type": "parent",
      "query":{"term":{"my_num":{"value":"001"}}}
    }
  }
}

返回匹配的子文档,结果片段如下:

has_parent查询顶级参数
  • parent_type:(必需的,string)指定连接父关系的名称。
  • query:(必需的,查询object)在type字段指定名称的父文档上运行的查询。如果其父文档与搜索匹配,查询将返回子文档。
  • score:(可选的,boolean)表示是否将匹配父文档的相关性分数聚合到子文档中。默认值为false,默认情况下,Elasticsearch将忽略父文档的相关性得分。如果为true,则将匹配父文档的相关性得分聚合到子文档的相关性得分中。
  • ignore_unmapped:(可选的,boolean)表示是否忽略未映射的parent_type字段。默认值为false,默认情况下,如果parent_type字段输入值未映射,Elasticsearch将返回一个错误。
排序
  • 不支持标准排序选项对has_parent查询的结果进行排序。
  • 如果需要对返回的文档进行排序,可以使用function_score查询并按_score排序。例如,下面的查询根据父文档的view_count字段对返回的文档进行排序,示例如下:
GET /my_index_03/_search
{
  "query": {
    "has_parent": {
      "parent_type": "parent",
      "score" : true,
      "query" : {
          "function_score" : {
              "script_score": {
                  "script": "_score * doc['view_count'].value"
              }
          }
      }
    }
  }
}

5. 父ID查询

parent_id查询返回匹配指定父ID的子文档。
例如,在my_index_03索引中,查询父ID等于1的子文档,示例如下:

GET /my_index_03/_search
{
  "query": {
    "parent_id": {
      "type": "child",
      "id": "1"
    }
  }
}
parent_id查询顶级参数
  • type:(必需的,string)指定连接子关系的名称。
  • id:(必需的,string)父文档的ID。查询将返回这个父文档的子文档。。
  • ignore_unmapped:(可选的,boolean)表示是否忽略未映射的type字段。默认值为false,默认情况下,如果type字段输入值未映射,Elasticsearch将返回一个错误。

你可能感兴趣的:(Elasticsearch系列(15)Query之连接查询)