从根上理解elasticsearch(lucene)查询原理(2)-lucene常见查询类型原理分析
大家好,我是蓝胖子,在上一节我提到要想彻底搞懂elasticsearch 慢查询的原因,必须搞懂lucene的查询原理,所以在上一节我分析了lucene查询的整体流程,除此以外,还必须要搞懂各种查询类型内部是如何工作,比如比较复杂的查询是将一个大查询分解成了小查询,然后通过对小查询的结果进行合并得到最终结果。
今天就来看看几种比较常见的查询其内部的工作原理。
BooleanQuery 查询分析
首先来看下布尔查询,拿下面这段代码举例,我用lucene写了一个布尔查询的例子,布尔查询由两个term查询组成,其中一个term是用must,一个term用的是should。
BooleanQuery.Builder query = new BooleanQuery.Builder();
query.add(new TermQuery(new Term(field1, "w3")), BooleanClause.Occur.MUST);
query.add(new TermQuery(new Term(field2, "xx")), BooleanClause.Occur.SHOULD);
int[] expDocNrs = {2, 3, 1, 0};
queriesTest(query.build(), expDocNrs);
布尔查询会将两个term查询的倒排链进行合并,得到最终结果。上一节有提到,计分逻辑是通过bulkScore.score方法实现的。在bulkScore.score方法内部 ,需要先遍历筛选出符合条件的文档,然后对该文档进行计分,无论是筛选出符合条件的文档,还是对文档计分,都与weight对象创建的scorer对象有关,遍历用到的是DocIdSetIterator,计分用到的是score() 方法,scorer涉及到的方法如下,

其中计分方法score是在scorer抽象类又继承的一个Scorable 抽象类中,如下所示
public abstract class Scorer extends Scorable {
...
}

在遍历倒排列表取出文档id时,会调用DocIdSetIterator 的nextDoc 方法取出当前文档id,并将便利指针移动到倒排列表的下一个文档id处。
但是布尔查询往往是多个条件的组合查询,它不可能是只遍历一个倒排链表,所以布尔查询的实现中,针对查询条件生成了特殊的scorer对象,比如ConjunctionScorer 交集scorer,它会将查询条件组合起来,并且利用子查询的DocIdSetIterator 构造新的DocIdSetIterator 用于遍历筛选出符合条件的文档id。ConjunctionScorer 的nextDoc方法就相当于是在执行多个倒排链表合并的过程。
关于倒排链表的合并过程就不在这篇文档继续展开了。除此以外,布尔查询构建的scorer对象还有 并集DisjunctionSumScorer,差集ReqExclScorer,ReqOptSumScorer。它们的nextDoc方法也都是在做遍历倒排链表取出文档id的操作,不过遍历合并倒排链表的逻辑各有不同。
所以,如果你的布尔查询命中结果比较多,并且需要计分的话, 会导致在进行倒排链表合并操作时花费比较长的时间。比如我之前碰到的一个慢查询,经过profile的分析如下,布尔查询在next_doc操作上耗时比较长,next_doc对于布尔查询而言是在进行倒排链表的合并。

而对于布尔查询的子查询term查询你会发现耗时基本是花在了advance操作上。因为倒排列表合并过程中会有很多移动遍历指针的操作也就是advance操作,所以在倒排列表比较长时,要想完整遍历合并多个倒排列表则会有很多advance操作。

MultiTermQuery 查询分析
接着看另外一个常见的查询类型MultiTermQuery,它的查询重写分好几种类型,具体的重写类型区别可以查看官方文 https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-multi-term-rewrite.html
这里我拿其中一种 CONSTANT_SCORE_BLENDED_REWRITE 举例,这也是在复杂查询例如
默认使用的重写类型。
wildcardQuery这些模糊匹配,正则匹配差询首先是构建自动状态机,然后默认会将查询重写成为了CONSTANT_SCORE_BLENDED_REWRITE类型的MultiTermQuery查询。
之后在创建weight的scorer对象时,会将词典term dictionary中的term与自动状态机做匹配,选出符合条件的term,根据term的个数判断是将查询重写为布尔查询还是直接构建bitset用于后续计分时进行迭代遍历。
符合条件的term 大于16个,则会进行bitset的构建,构建过程则是将符合条件的term对应的倒排列表取出来加到一个bitset中。这个过程是比较耗时的,特别是term对应的倒排列表过大或者term数量过多时,耗时会非常长。注意这个构建过程是发生在scoer对象创建的时候,即build_scorer阶段。拿我之前遇到的一个慢查询举例,这是一个匹配到的term数量比较多的wildcardQuery,
下面是执行的DSL语句,
{"size":1000,"query":{"bool":{"filter":[{"term":{"owner_uid":{"value":712377485,"boost":1.0}}},{"term":{"pid":{"value":0,"boost":1.0}}},{"wildcard":{"name":{"wildcard":"*","boost":1.0}}},{"exists":{"field":"vgroup","boost":1.0}}],"adjust_pure_negative":true,"boost":1.0}},"_source":{"includes":["name"],"excludes":[]}}
经过profile分析可以看到wildcardQuery已经被重写为了MultiTermQueryConstantScoreWrapper,耗时过长最大的阶段则是在build_scorer阶段,对每个阶段不太熟悉的话可以翻看我前一篇文章 https://mp.weixin.qq.com/s/Drhs6lKPYy8vDHa2RouiyA
注意像wildcardQuery,前缀匹配这些查询都会构建自动状态机,构建自动状态机的过程在匹配规则文本比较长时,非常消耗cpu,生产上注意限制匹配规则文本长度,并且构建自动状态机花费的时长不会体现在profile输出结果中。

从根上理解elasticsearch(lucene)查询原理(2)-lucene常见查询类型原理分析的更多相关文章
- 从查询重写角度理解elasticsearch的高亮原理
一.高亮的一些问题 elasticsearch提供了三种高亮方式,前面我们已经简单的了解了elasticsearch的高亮原理; 高亮处理跟实际使用查询类型有十分紧密的关系,其中主要的一点就是muti ...
- 从原理上理解MySQL的优化建议
从原理上理解MySQL的优化建议 预备知识 B+树索引 mysql的默认存储引擎InnoDB使用B+树来存储数据的,所以在分析优化建议之前,了解一下B+树索引的基本原理. 上图是一个B+树索引示意图, ...
- 微服务实战(三):以MySQL为例,从原理上理解那些所谓的数据库军规
原文链接:微服务化的数据库设计与读写分离(来源:刘超的通俗云计算) 数据库永远是应用最关键的一环,同时越到高并发阶段,数据库往往成为瓶颈,如果数据库表和索引不在一开始就进行良好的设计,则后期数据库横向 ...
- 图解|从根上彻底理解MySQL的索引
这是图解MySQL的第4篇文章,这篇文章会让你 明白什么是索引,彻底理解B+树和索引的关系: 彻底理解主键索引.普通索引.联合索引: 了解什么是HASH索引,InnoDB和MyISAM索引的不同实现方 ...
- 读《深入理解Elasticsearch》点滴-查询二次评分
理解二次评分 二次评分是指重新计算查询返回文档中指定个数文档的得分,es会截取查询返回的前N个,并使用预定义的二次评分方法来重新计算他们的得分 小结 有时候,我们需要显示查询结果,并且使得页面上靠前文 ...
- 读《深入理解Elasticsearch》点滴-查询模版(结合官网手册,版本5.1)
1.为什么使用查询模版 让应用程序开发者只需要把查询传递给elasticsearch,而不需要考虑查询语句的构造.查询DSL语法.查询结果过滤等细节知识. 2.使用版本5.1,查询模版在5.6中发生变 ...
- 深入理解ElasticSearch(PDF版 内含目录)
深入理解ElasticSearch 介绍: 本书涵盖了Elasticsearch的许多中高级功能,并介绍了缓存.ApacheLucene库以及监控等模块的内部运作机制.其中,还涉及一些实用案例,比如配 ...
- Elasticsearch 通关教程(四): 分布式工作原理
前言 通过前面章节的了解,我们已经知道 Elasticsearch 是一个实时的分布式搜索分析引擎,它能让你以一个之前从未有过的速度和规模,去探索你的数据.它被用作全文检索.结构化搜索.分析以及这三个 ...
- 如何在 Ubuntu 14.04 上安装 Elasticsearch,Logstash 和 Kibana
介绍 在本教程中,我们将去的 Elasticsearch 麋鹿堆栈安装 Ubuntu 14.04 — — 那就是,Elasticsearch 5.2.x,Logstash 2.2.x 和 Kibana ...
- ElasticSearch高可用集群环境搭建和分片原理
1.ES是如何实现分布式高并发全文检索 2.简单介绍ES分片Shards分片技术 3.为什么ES主分片对应的备分片不在同一台节点存放 4.索引的主分片定义好后为什么不能做修改 5.ES如何实现高可用容 ...
随机推荐
- [远程Call]32位远程多参数带返回调用
[远程Call]32位远程多参数带返回调用 引子 在Windows上可以使用CreateRemoteThread实现远程Call,但是有不带返回值且只能传递一个参数的限制. 解决思路 将多个参数利用V ...
- 标题:在Godot中使用Node2D创建自定义的Label
在Godot游戏引擎中,我们经常需要在游戏中显示文本信息.通常,我们可以使用Label节点来实现这一点.但是,在某些情况下,你可能希望更灵活地控制文本的显示和样式.在本篇博客中,我们将学习如何通过使用 ...
- GaussDB技术解读系列:高安全之密态等值
本文分享自华为云社区< DTCC 2023专家解读 | GaussDB技术解读系列:高安全之密态等值>,作者:GaussDB 数据库. 近日,在第14届中国数据库技术大会(DTCC2023 ...
- 《Kali渗透基础》07. 弱点扫描(一)
@ 目录 1:漏洞发现 1.1:Exploit-DB 1.2:searchsploit 1.3:nmap 2:漏洞管理 3:弱点扫描类型 4:漏洞基本概念 4.1:CVSS 4.2:CVE 4.3:O ...
- 《SQL与数据库基础》02. SQL-DDL
目录 DDL 库管理 表管理 本文以 MySQL 为例 DDL 库管理 查看有哪些数据库: SHOW DATABASES; 使用某个数据库: USE 数据库名; 查看当前使用的数据库: SELECT ...
- Node.js 使用 officecrypto-tool 读取加密的 Excel (xls, xlsx) 和 Word( docx)文档
Node.js 使用 officecrypto-tool 读取加密的 Excel (xls, xlsx) 和 Word( docx)文档, 还支持 xlsx 和 docx 文件的加密(具体使用看文档) ...
- 【.NET8】访问私有成员新姿势UnsafeAccessor(上)
前言 前几天在.NET性能优化群里面,有群友聊到了.NET8新增的一个特性,这个类叫UnsafeAccessor,有很多群友都不知道这个特性是干嘛的,所以我就想写一篇文章来带大家了解一下这个特性. 其 ...
- python实现简单的爬虫功能
前言Python是一种广泛应用于爬虫的高级编程语言,它提供了许多强大的库和框架,可以轻松地创建自己的爬虫程序.在本文中,我们将介绍如何使用Python实现简单的爬虫功能,并提供相关的代码实例. 如何实 ...
- 用go封装一下二级认证功能
用go封装一下二级认证 本篇为用go设计开发一个自己的轻量级登录库/框架吧 - 秋玻 - 博客园 (cnblogs.com)的二级认证业务篇,会讲讲二级认证业务的实现,给库/框架增加新的功能. 源码: ...
- docker常用命令-docker网络
docker命令详解 docker search 在docker hub中搜索镜像: docker pull 从docker镜像源服务器拉取指定镜像或者库镜像: docker push 推送指定镜像或 ...