Elasticsearch 联结查询(joining queries)

Neil Zhu,简书ID Not_GOD,University AI 创始人 & Chief Scientist,致力于推进世界人工智能化进程。制定并实施 UAI 中长期增长战略和目标,带领团队快速成长为人工智能领域最专业的力量。
作为行业领导者,他和UAI一起在2014年创建了TASA(中国最早的人工智能社团), DL Center(深度学习知识中心全球价值网络),AI growth(行业智库培训)等,为中国的人工智能人才建设输送了大量的血液和养分。此外,他还参与或者举办过各类国际性的人工智能峰会和活动,产生了巨大的影响力,书写了60万字的人工智能精品技术内容,生产翻译了全球第一本深度学习入门书《神经网络与深度学习》,生产的内容被大量的专业垂直公众号和媒体转载与连载。曾经受邀为国内顶尖大学制定人工智能学习规划和教授人工智能前沿课程,均受学生和老师好评。

在像 Elasticsearch 这样的分布式计算系统执行全 SQL 风格的联结操作代价昂贵。相应地,Elasticsearch 提供了两种形式的联结可以实现水平规模的扩展。

  • 嵌套查询 nested query:文档包含 nested 类型的字段。这些字段用来索引数组对象,其中每个对象作为独立的文档可以被检索(使用 nested 查询)。
  • has_childhas_parent 查询:父子关系可以在一个单独的索引中的两个文档类型间存在。has_child 查询返回了父文档,其子文档匹配了特定的查询。而 has_parent 查询返回子文档,其父文档匹配了特定的查询。

参考 terms-lookup mechanism,也可以让你从另一个文档中值中构建一个 terms 查询。

Nested Query

嵌套查询可以查询嵌套的对象/文档(参考 nested mapping)。查询是针对当做是内部按照分隔的文档索引的嵌套对象/文档进行的,返回根 parent 文档(或者 parent 嵌套映射)。这里是一个映射的例子:

{
    "type1" : {
        "properties" : {
            "obj1" : {
                "type" : "nested"
            }
        }
    }
}

这里是一个嵌套查询的例子:

{
    "nested" : {
        "path" : "obj1",
        "score_mode" : "avg",
        "query" : {
            "bool" : {
                "must" : [
                    {
                        "match" : {"obj1.name" : "blue"}
                    },
                    {
                        "range" : {"obj1.count" : {"gt" : 5}}
                    }
                ]
            }
        }
    }
}

这个查询的 path 指向了嵌套的对象路径,而 query 或者 filter 包含了会在匹配了直接的路径并且和根 parent 文档连接的嵌套的文档上运行。注意,任何在这个查询内部引用的字段必须使用完整的路径。

score_mode 使得我们可以设置内部 children 匹配影响 parent 文档。默认是 avg,但是也可以设置为 summinmaxnone

多层嵌套自动支持,检查,并产生一个内部的嵌套查询来自动匹配相关的嵌套层级(不是根 root)如果存在在另一个嵌套查询中。

Has Child Query

has_child 过滤器接受一个查询和 child 类型来执行,产生 parent 文档拥有匹配查询的 child 文档。这里是例子:

{
    "has_child" : {
        "type" : "blog_tag",
        "query" : {
            "term" : {
                "tag" : "something"
            }
        }
    }
}

打分能力

has_child 查询同样有打分的支持。支持的模式有 minmaxtotalavg 或者 none。默认的模式是 none 会产生同样的行为。如果打分模式设成了另外一种,那么所有匹配的 child 文档的分数都会被聚合在关联的 parent 文档上。打分类型可以使用 score_mode 字段在 has_child 查询内部指定:

{
    "has_child" : {
        "type" : "blog_tag",
        "score_mode" : "sum",
        "query" : {
            "term" : {
                "tag" : "something"
            }
        }
    }
}

Min/Max Children

has_child 查询允许我们指定最小/最大数目的 children 需要匹配来让 parent doc 被当做是一个匹配:

{
    "has_child" : {
        "type" : "blog_tag",
        "score_mode" : "sum",
        "min_children": 2, 
        "max_children": 10, 
        "query" : {
            "term" : {
                "tag" : "something"
            }
        }
    }
}

min_childrenmax_children 都是可选的。

min_childrenmax_children 参数可以和 score_mode 参数组合使用。

Has Parent Query

has_parent 查询接受查询和 parent 类型。查询是在 parent 文档空间上进行的,这个是通过 parent 类型指定的。该查询返回和关联的 parent 文档匹配的 child 文档。剩下的设置都和 has_child 查询相同。

{
    "has_parent" : {
        "parent_type" : "blog",
        "query" : {
            "term" : {
                "tag" : "something"
            }
        }
    }
}

打分能力

has_parent 同样也有打分支持。支持的打分类型就是 score 或者 none。默认是 none,忽略了来自 parent 文档的分数。这里的分数和 has_parent 查询相同。如果打分类型设置为 score,那么匹配的 parent 文档的分数就被聚合在 child 文档中属于匹配的 parent 文档。打分模式可以使用 score_modehas_parent query 中指定:

{
    "has_parent" : {
        "parent_type" : "blog",
        "score_mode" : "score",
        "query" : {
            "term" : {
                "tag" : "something"
            }
        }
    }
}

推荐阅读更多精彩内容