从根上理解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如何实现高可用容 ...
随机推荐
- 2.go语言基础类型漫游
本篇前瞻 本篇是go语言的基础篇,主要是帮助大家梳理一下go语言的基本类型,注意本篇有参考go圣经,如果你有完整学习的需求可以看一下,另外,go语言的基本类型比较简单,介绍过程就比较粗暴. 基本类型 ...
- C语言下载minGW地址
https://sourceforge.net/projects/mingw-w64/files/ 下载红框内即可
- 使用阿里云ECS和RDS搭建个人博客
一.ECS实例配置 1.重置云服务器ECS密码 前往ECS控制台,点击实例,找到刚才开通的ECS实例(找不到的话就看一下上方的地区是否是你的服务器的地域),点击右侧操作栏中的三个点,找到重置实例密码, ...
- 《Kali渗透基础》08. 弱点扫描(二)
@ 目录 1:OpenVAS / GVM 1.1:介绍 1.2:安装 1.3:使用 2:Nessus 2.1:介绍 2.2:安装 2.3:使用 3:Nexpose 本系列侧重方法论,各工具只是实现目标 ...
- springboot3框架搭建
Spring Boot 3.0.0已经发布一段时间了,越来越多的公司考虑将技术框架升级到最新版本,JDK也相应要求JDK17以上.对应Spring Boot 2.x的版本,建议先升级到Spring B ...
- Chrome 手机端网页如何使用开发者模式
chrome 手机端网页如何调试 在Chrome手机端,你可以使用Chrome开发者工具来调试网页.下面是一些步骤: 首先,确保你的手机已经开启开发者模式.打开USB调试功能或可以通过USB连接或无线 ...
- Solution -「CF 959E」Mahmoud and Ehab and the xor-MST
Description Link. 一完全图有 \(n\) 个节点 \(0,...,n-1\),其中边 \((i,j)\) 的权值为 \(i\oplus j\),其中 \(\oplus\) 为位异或操 ...
- DB2---创建返回结果集的函数
在数据验证中,经常遇到需返回结果集的操作,故整理一个返回结果集的DB2函数,便于后期查阅 1.准备测试表 /*创建测试表:设置结果集的属性为表字段*/ CREATE TABLE Test_EXWAST ...
- 其它——paramiko模块的使用
文章目录 paramiko 一 介绍 二 通过用户名密码方式远程执行命令 三 通过用户名密码方式上传下载文件 四 通过公钥私钥远程执行命令 五 通过公钥私钥远程上传下载文件 六 通过私钥字符串远程连接 ...
- 实战0-1,Java开发者也能看懂的大模型应用开发实践!!!
前言 在前几天的文章<续写AI技术新篇,融汇工程化实践>中,我分享说在RAG领域,很多都是工程上的实践,做AI大模型应用的开发其实Java也能写,那么本文就一个Java开发者的立场,构建实 ...