大家好,我是蓝胖子,在上一节我提到要想彻底搞懂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常见查询类型原理分析的更多相关文章

  1. 从查询重写角度理解elasticsearch的高亮原理

    一.高亮的一些问题 elasticsearch提供了三种高亮方式,前面我们已经简单的了解了elasticsearch的高亮原理; 高亮处理跟实际使用查询类型有十分紧密的关系,其中主要的一点就是muti ...

  2. 从原理上理解MySQL的优化建议

    从原理上理解MySQL的优化建议 预备知识 B+树索引 mysql的默认存储引擎InnoDB使用B+树来存储数据的,所以在分析优化建议之前,了解一下B+树索引的基本原理. 上图是一个B+树索引示意图, ...

  3. 微服务实战(三):以MySQL为例,从原理上理解那些所谓的数据库军规

    原文链接:微服务化的数据库设计与读写分离(来源:刘超的通俗云计算) 数据库永远是应用最关键的一环,同时越到高并发阶段,数据库往往成为瓶颈,如果数据库表和索引不在一开始就进行良好的设计,则后期数据库横向 ...

  4. 图解|从根上彻底理解MySQL的索引

    这是图解MySQL的第4篇文章,这篇文章会让你 明白什么是索引,彻底理解B+树和索引的关系: 彻底理解主键索引.普通索引.联合索引: 了解什么是HASH索引,InnoDB和MyISAM索引的不同实现方 ...

  5. 读《深入理解Elasticsearch》点滴-查询二次评分

    理解二次评分 二次评分是指重新计算查询返回文档中指定个数文档的得分,es会截取查询返回的前N个,并使用预定义的二次评分方法来重新计算他们的得分 小结 有时候,我们需要显示查询结果,并且使得页面上靠前文 ...

  6. 读《深入理解Elasticsearch》点滴-查询模版(结合官网手册,版本5.1)

    1.为什么使用查询模版 让应用程序开发者只需要把查询传递给elasticsearch,而不需要考虑查询语句的构造.查询DSL语法.查询结果过滤等细节知识. 2.使用版本5.1,查询模版在5.6中发生变 ...

  7. 深入理解ElasticSearch(PDF版 内含目录)

    深入理解ElasticSearch 介绍: 本书涵盖了Elasticsearch的许多中高级功能,并介绍了缓存.ApacheLucene库以及监控等模块的内部运作机制.其中,还涉及一些实用案例,比如配 ...

  8. Elasticsearch 通关教程(四): 分布式工作原理

    前言 通过前面章节的了解,我们已经知道 Elasticsearch 是一个实时的分布式搜索分析引擎,它能让你以一个之前从未有过的速度和规模,去探索你的数据.它被用作全文检索.结构化搜索.分析以及这三个 ...

  9. 如何在 Ubuntu 14.04 上安装 Elasticsearch,Logstash 和 Kibana

    介绍 在本教程中,我们将去的 Elasticsearch 麋鹿堆栈安装 Ubuntu 14.04 — — 那就是,Elasticsearch 5.2.x,Logstash 2.2.x 和 Kibana ...

  10. ElasticSearch高可用集群环境搭建和分片原理

    1.ES是如何实现分布式高并发全文检索 2.简单介绍ES分片Shards分片技术 3.为什么ES主分片对应的备分片不在同一台节点存放 4.索引的主分片定义好后为什么不能做修改 5.ES如何实现高可用容 ...

随机推荐

  1. [ABC140E] Second Sum

    2023-02-13 题目 题目传送门 翻译 翻译 难度&重要性(1~10):4 题目来源 AtCoder 题目算法 双向链表 解题思路 \(1.\) 当我们用从小到大的顺序来求解时,把原来求 ...

  2. 《Web安全基础》03. SQL 注入

    @ 目录 1:简要 SQL 注入 2:MySQL 注入 2.1:信息获取 2.2:跨库攻击 2.3:文件读写 2.4:常见防护 3:注入方法 3.1:类型方法明确 3.2:盲注 3.3:编码 3.4: ...

  3. 数据可视化【原创】vue+arcgis+threejs 实现流光立体墙效果

    本文适合对vue,arcgis4.x,threejs,ES6较熟悉的人群食用. 效果图: 素材: 主要思路: 先用arcgis externalRenderers封装了一个ExternalRender ...

  4. QA|selenium在send_keys时报错dict object has no attribute ''|UI自动化测试

    Q:selenium在send_keys时报错dict object has no attribute 'send_keys',如下图 增加了print(type(e1))发现确实是字典类型,怪了,按 ...

  5. IDEFICS 简介: 最先进视觉语言模型的开源复现

    引言 Code Llama 是为代码类任务而生的一组最先进的.开放的 Llama 2 模型,我们很高兴能将其集成入 Hugging Face 生态系统!Code Llama 使用与 Llama 2 相 ...

  6. 记一次 .NET 某电力系统 内存暴涨分析

    一:背景 1. 讲故事 前些天有位朋友找到我,说他生产上的程序有内存暴涨情况,让我帮忙看下怎么回事,最简单粗暴的方法就是让朋友在内存暴涨的时候抓一个dump下来,看一看大概就知道咋回事了. 二:Win ...

  7. Solution -「洛谷 P5046」「YunoOI 2019 模拟赛」Yuno loves sqrt technology I

    Description Link. 无修改区间求逆序对. Solution 首先有一个显然的 \(\Theta(N\sqrt{N}\log_{2}N)\) 做法,由于过不了所以我就不废话. 其实有了 ...

  8. TCP vs UDP:揭秘可靠性与效率之争

    概述 今天我们开始主要讲解TCP的相关知识点.在之前讲解分层章节的时候,我们提到过一个重要观点.在网络层及以下几层,更多的是让主机与主机建立连接,也就是说你的电脑需要知道另一台电脑在哪里才能连接上它. ...

  9. .NET周刊【10月第1期 2023-10-01】

    国内文章 .NET应用如何防止被反编译 https://www.cnblogs.com/Can-daydayup/p/17736700.html 本文主要讲述了如何防止.NET应用被反编译.虽然无法完 ...

  10. dig 简明教程

    哈喽大家好,我是咸鱼 不知道大家在日常学习或者工作当中用 dig 命令多不多 dig 是 Domain Information Groper 的缩写,对于网络管理员和在域名系统(DNS)领域工作的小伙 ...