从根上理解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如何实现高可用容 ...
随机推荐
- typora使用教程&高级用法&Markdown
typora使用教程&高级用法&Markdown typora介绍 哇啦哇啦哇啦哇,,,,,,,,,,,,, 提示:小白看不懂的话,建议哔哩哔哩搜索"遇见狂神说", ...
- Jenkins 相关配置
https://www.cnblogs.com/zylyehuo/ 参考链接 解决:Jenkins: signature verification failed in update site 'def ...
- 如何调用api接口获取到商品数据
要调用API接口获取商品数据,需要进行以下步骤: 确定API接口 首先需要确定要使用的API接口,可以通过搜索引擎或者相关文档来查找适合的API接口.以淘宝开放平台为例,可以使用淘宝的商品信息查询AP ...
- 自定义注解,实现请求缓存【Spring Cache】
前言 偶尔看到了spring cache的文章,我去,实现原理基本相同,哈哈,大家可以结合着看看. 简介 实际项目中,会遇到很多查询数据的场景,这些数据更新频率也不是很高,一般我们在业务处理时,会对这 ...
- 使用GPU搭建支持玛雅(Maya)和Adobe AI,DW,PS的职校云计算机房
背景 学校为职业学校,计算机教室需要进行Maya.Adobe Illustrator.Adobe Dreamweaver.Adobe PhotoShop等软件的教学.每个教室为35用户.资源需求为4核 ...
- Vue源码学习(七):合并生命周期(混入Vue.Mixin)
好家伙, 1.使用场景 现在来,来想一下,作为一个使用Vue的开发者,假设现在我们要使用created(),我们会如何使用 1.1. .vue文件中使用 <template> < ...
- modbus转profinet网关连接ABB变频器在博图程序案例
modbus转profinet网关连接ABB变频器在博图程序案例 在博图里PLC无需编程利用兴达易控modbus转Profinet网关将ABB变频器接入到西门子网络中,用到设备为西门子1200PLC, ...
- 一个关于 i++ 和 ++i 的面试题打趴了所有人
前言 都说大城市现在不好找工作,可小城市却也不好招人. 我们公司招了挺久都没招到,主管感到有些心累. 我提了点建议,是不是面试问的太深了,在这种小城市,能干活就行. 他说自己问的面试题都很浅显,如果答 ...
- 6. 用Rust手把手编写一个wmproxy(代理,内网穿透等), 通讯协议源码解读篇
用Rust手把手编写一个wmproxy(代理,内网穿透等), 通讯协议源码解读篇 项目 ++wmproxy++ gite: https://gitee.com/tickbh/wmproxy githu ...
- Python socket实现简单聊天,同步输入和接收消息
查的资料很多都是必须等待接收数据后才能再次输入.做了修改,使用多线程的形式,实现一边输入,一边接收 服务端代码 import socket import threading import sys im ...