天天看点

《深入理解Elasticsearch(原书第2版)》一2.5.1 查询方式分类

本节书摘来华章计算机《深入理解elasticsearch(原书第2版)》一书中的第2章 ,第2.5.1节,[美]拉斐尔·酷奇(rafal ku) 马雷克·罗戈任斯基(marek rogoziski)著 张世武 余洪淼 商旦 译 更多章节内容可以访问云栖社区“华章计算机”公众号查看。

当然,对查询方式进行分类是一件艰难的任务,我们也不敢打包票说在这里给出的分类列表是唯一正确的。我们甚至可以说,如果你询问其他elasticsearch使用者,他们可能会给出自己的分类方式,或者声称每个查询方式都可以被归入多个类别。有趣的是,他们有可能是对的。我们也曾考虑过多种分类方式存在的情况,不过,最终我们认为,每个查询方式都可以被归入以下列出的一个或多个类别中。

基本查询:这类查询允许针对索引的一部分进行检索,其输入数据既可以分析也可以不做分析。这类查询的一个关键特征是,不支持在其内部再嵌套其他查询。基本查询的一个示例是term查询。

组合查询:在这类查询中可以包含其他查询和过滤器,比如bool查询和dismax查询。

无分析查询:这类查询不分析输入内容,直接将它们原样传递给lucene。term查询就是这类查询的一员。

全文检索查询:这类查询成员众多。许多查询都支持全文检索、输入内容分析、同时很可能支持可被lucene识别的查询语法。比如match查询。

模式匹配查询:这类查询都在查询语句中支持各种通配符。比如,前缀查询可以归入此类。

支持相似度操作的查询:这类查询拥有一个共同的特性—支持近似词语的匹配。这类查询的成员如fuzzy_like_this、more_like_this查询等。

支持打分操作的查询:这类查询非常重要,尤其是在和全文搜索查询组合使用的场景下。这个类别包括那些允许在查询时修改打分计算过程的查询方式。在第3章介绍的function_score查询可以归入此类。

位置敏感查询:这类查询允许我们使用索引中存储的词项位置信息。span_term查询就是一个很好的例子。

结构敏感查询:这类查询的工作基于结构数据,如父子文档结构。这个类别的一个例子是nested one查询。

当然,我们在这里只讨论查询分类,不探讨过滤器的分类。不过,对过滤器来说,你也可以使用相同的分类逻辑。让我们先把过滤器置之脑后。在距离阐释每种查询类别之前,我们先简短描述一下每种查询类别的目的。

1. 基本查询

在基本查询内部不可以包含其他查询,它们只有索引检索这一个用途。这类查询通常作为其他复杂查询的一部分或者单独传递给elasticsearch。你可以把基本查询比作修筑大厦的砖块,而大厦就是各种复杂查询。举个例子,如果你想匹配某个文档中的一个特定词项,且没有其他要求,可以考虑使用基本查询。本例中,match查询就能很好地满足需求,无需再跟其他查询组合使用。

归属于基本查询的一些查询方式举例如下:

match查询:一种(实际上指好几种)查询方式,适用于执行全文检索且需要对输入进行分析的场景。一般来说,当需要分析输入内容却不需要完整lucene查询语法支持时,可以使用这种查询方式。这种查询不需要进行查询语法解析,发生解析错误的概率极低,因此特别适合接收用户输入文本的场景。

match_all查询:这个查询匹配所有文档,常用于需要对所有索引内容进行归类处理的场景。

term查询:一种简单的、无需对输入进行分析的查询方式,可以查询单个词语。这种查询方式的使用场景包括针对不分词字段进行检索,比如在我们的测试代码中检索tags字段。term查询还经常跟过滤器配合使用,比如在我们的测试代码中针对category字段进行过滤操作。

简单查询分类可包括:match,multi_match,common,fuzzy_like_this,fuzzy_like_this_field,geoshape,ids,match_all,query_string,simple_query_string,range,prefix, regexp,span_term,term,terms,wildcard查询。

2. 组合查询

组合查询的唯一用途是把其他查询组合在一起使用。如果说简单查询是建造高楼的砖块,组合查询就是粘合这些砖块的水泥。我们可以把组合查询无穷嵌套,用来构建极其复杂的查询,唯一能够阻止我们这样嵌套的障碍是性能。

组合查询的一些示例和用法如下。

bool查询:最常用的组合查询方式之一。能够把多个查询用布尔逻辑组织在一起,可以控制查询的某个子查询部分是必须匹配、可以匹配还是不应该匹配。如果我们要把匹配不同查询条件的查询组合在一起使用,bool查询就是一个很好的选择。bool查询还可以用在这样的场景:我们希望结果文档的最终得分为所有子查询得分的和。

dis_max查询:一种非常有用的查询方式。这种查询的结果文档得分和最高权重的子查询打分高度相关,而不是如bool查询那样对所有子查询得分进行求和。dis_max查询返回匹配所有子查询的文档,并通过一个简单公式计算最终得分:max(各子查询的得分)+tie_breaker*(非最高得分子查询的得分之和)。如果你希望最高得分子查询能够在打分过程中起决定作用,dis_max查询是不二选择。

组合查询类别可包括这些查询方式:bool,boosting,constant_score,dis_max,filtered,function_score,has_child,has_parent,indices,nested,span_first,span_multi, span_first,span_multi,span_near,span_not,span_or,span_term,top_children查询。

3. 无分析查询

有一类查询不会被分析,而是直接传递给lucene索引。这意味着我们既不需要操心分析过程是否如我们期望的方式执行并生成合适的词项,也不需要针对特定的不分词字段执行查询。如果你把elasticsearch当作nosql数据库使用,这种查询方式就比较适合你。这类查询精确匹配传入的词语,不会使用语言分析器等工具对词语进行分词和其他处理。

以下示例可帮你理解无分析查询的目的。

term查询:即词项查询。当提及无分析查询时,最常用的无分析查询就是term查询。它可以匹配某个字段中的给定值。比如说,如果你希望匹配一个拥有特定标签(我们示例文档中的tags字段)的文档,可以使用term查询。

prefix查询:即前缀查询。另一种无需分析的查询方式。前缀查询常用于自动完成功能,用户输入一段文本,搜索系统返回所有以这个文本开头的文档。需要注意的是,尽管前缀查询没有被分析,elasticsearch还是对它进行了重写,以确保它能高速执行。

这类查询包括:common,ids,prefix,span_term,term,terms,wildcard查询。

4. 全文检索查询

当你需要构建类似google的查询界面时,可以使用这种查询类别。这类查询会根据索引映射配置对输入进行分析,支持lucene语法和打分计算等功能。一般来说,如果查询的一部分文本来自于用户输入,则可以从全文检索查询类别中选择其一,比如query_string、match或simpe_query_string查询。

全文检索查询类别的示例和用法如下。

属于本类的查询方式包括:match,multi_match,query_string,simple_query_string查询。

5. 模式匹配查询

elasticsearch直接或间接提供了一些支持通配符的查询方式,比如通配符查询(wildcard query)和前缀查询(prefix query)。除此之外,我们还可以使用正则表达式查询(regexp query),这种查询能够找出内容中包含给定模式的文档。

我们在之前已经展示过一个前缀查询的示例,因此在这里主要介绍一下正则表达式查询。如果想找出其词项匹配某个固定模式的文档,正则表达式查询是唯一的选择。举个例子,假定你的各种日志存储于elasticsearch中,可以使用正则表达式查询找出所有含有如下词项的日志记录:词项以“err”前缀开头、以“memory”结尾、中间可以有任意数量的字符。最后,需要注意的是,所有模式匹配查询如果包含可匹配海量词项的表达式,性能代价将十分高昂。

本类查询包括:prefix,regexp,wildcard查询。

6. 支持相似度操作的查询

我们认为这类查询是一些可以根据给定词项查找近似词项或文档的查询方式的集合。举例来说,假定我们需要找出包含“crimea”近似词项的文档,可以执行一个fuzzy查询。这类查询的另一个用途是提供类似“你是不是想找xxx”的功能。比如你希望找出文档标题和输入文本相似的文档,可以使用more_like_this查询。一般来说,你可以使用本类别下的某个查询来查找包含和给定输入近似词项或字段的文档。

属于这个类别的查询有:fuzzy_like_this,fuzzy_like_this_field,fuzzy,more_like_this,more_like_this_field查询。

7. 支持打分操作的查询

这是一组用于改善查询精度和相关度的查询方式。这类查询可以通过指定自定义权重因子或提供额外处理逻辑的方式来改变文档得分。这类查询的一个很好的例子是function_score查询。function_score查询可以让我们使用函数,从而通过数学计算的方式改变文档得分。举个例子,如果你希望离给定地理定位点越近的文档得分越高,则function_score查询可以帮助实现这个目的。

本类查询包括:boosting,constant_score,function_score,indices查询。

8. 位置敏感查询

这类查询不仅可以匹配特定词项,还能匹配词项的位置信息。elasticsearch提供的各种范围查询就是这类查询的典型代表。我们还可以把match_phrase查询归入本类,因为至少从某种程度上来说,它也需要考虑被索引词项的位置信息。如果需要找出一组和其他单词保持一定距离的单词,比如“找出以下文档,同时包含mastering和elasticsearch且这两个单词相互临近,其后不超过距离3的位置包含second和edition单词”,可以使用各种范围查询。不过,需要注意的是,这些范围查询将在未来版本的lucene库中将被移除,届时elasticsearch也不再提供支持。这是因为这些查询开销很大,需要消耗大量cpu资源才能保证正确处理。

本类查询包括:match_phrase,span_first,span_multi,span_near,span_not,span_or,span_term查询。

9. 结构敏感查询

最后一类查询是结构敏感查询(structure aware query)。这类查询包括:

nested查询

has_child查询

has_parent查询

top_children查询

一般来说,所有支持对文档结构进行检索并且不需要对文档数据进行扁平化处理的查询方式都可以归入此类。如果你正在寻找一种查询方式,能够在子文档或嵌套文档中进行查询,或查找属于给定父文档的子文档,则需要使用刚刚提及的查询方式之一。换句话说,如果需要处理文档中的数据关系,请选择使用这类查询。不过需要注意的是,尽管elasticsearch可以支持一些数据关系,但它毕竟不是真正的关系数据库。

继续阅读