在复杂条件搜索上,为什么MySQL只能被ES吊打?

熟悉 MySQL 的同学一定都知道,MySQL 对于复杂条件查询的支持并不好 。MySQL 最多使用一个条件涉及的索引来过滤,然后剩余的条件只能在遍历行过程中进行内存过滤,对这个过程不了解的同学可以先行阅读一下MySQL 复杂 where 语句分析 。
上述这种处理复杂条件查询的方式因为只能通过一个索引进行过滤,所以需要进行大量的 I/O 操作来读取行数据,并消耗 CPU 进行内存过滤,导致查询性能的下降 。
而 ElasticSearch 因其特性,十分适合进行复杂条件查询,是业界主流的复杂条件查询场景解决方案,广泛应用于订单和日志查询等场景 。
下面我们就一起来看一下,为什么 ElasticSearch 适合进行复杂条件查询 。
ElasticSearch 简介
Elasticsearch 是开源的实时分布式搜索分析引擎,内部使用 Lucene 做索引与搜索 。它提供"准实时搜索"能力,并且能动态集群规模,弹性扩容 。

在复杂条件搜索上,为什么MySQL只能被ES吊打?

文章插图
Elasticsearch 使用 Lucene 作为其全文搜索引擎,用于处理纯文本的数据,但 Lucene 只是一个库,提供建立索引、执行搜索等接口,但不包含分布式服务,这些正是 Elasticsearch 做的 。
下面,我们来介绍一下 ElasticSearch 的相关概念 。为了便于初学者理解,我们先将 ElasticSearch 中的概念和 MySQL 中的概念大致地进行对应 。但是二者在具体细节上还是有很多差异的,大家深入了解 ElasticSearch 就会将二者区分清楚,不能强行对比等同 。
在复杂条件搜索上,为什么MySQL只能被ES吊打?

文章插图
ElasticSearch 中的索引 Index 类似于 MySQL 中的数据库 Database;
ElasticSearch 中的类型 Type 类似于 MySQL 中的表 Table;需要注意,这个概念在 7.x 版本中被完全删除,而且概念上和 Table 也有较大差异;
ElasticSearch 中的文档 Document 类似于 MySQL 中的数据行 Row,每个文档由多个字段 Filed 组成,这个Filed 就类似于 MySQL 的 Column;
ElasticSearch 中的映射 MApping 是对索引库中的索引字段及其数据类型进行定义,类似于关系型数据库中的表结构 Schema;
ElasticSearch 使用自己的领域语言 Query DSL 来进行增删改查,而 MySQL 使用 SQL 语言进行上诉操作 。
ElasticSearch 还有一系列有关其分布式特性的概念,我们这里就暂不介绍了,等后续学习到其分布式特性时在进行介绍 。
倒排索引
MySQL 有 B+ 树索引,而 ElasticSearch 则是倒排索引 (Inverted Index),它通过倒排索引来实现比 MySQL 更快的过滤和复杂条件的查询,此外,全文搜索功能也是依赖倒排索引才能实现 。下面,我们就具体来看一下何为倒排索引 。
倒排索引按照维基百科的描述,是存储文档内容到文档位置映射关系的数据库索引结构 。不过只看定义,我是有点迷惑,这不是和 MySQL 的非主键索引类似嘛,为什么要叫它“倒排”呢?这个问题我目前也为搞清楚,可能要等到后续了解了其具体实现才能理解 。
我们还是以书籍检索为例,假设有以下数据,每一行就是一个 Document,每个 Document 由 id,ISBN 号,作者名称和评分组成 。
在复杂条件搜索上,为什么MySQL只能被ES吊打?

文章插图
给上述数据按照 ISBN 和 Author 建立的倒排索引如下所示 。倒排索引是每个字段分开建立的,相互独立 。有两个专门的术语,分别是索引 Term 和倒排表 Posting List 。字段的值就是 Term,比如 N0007,而 Term 对应的文档 ID 的列表就是 Posting List,对应图中红色的部分 。
在复杂条件搜索上,为什么MySQL只能被ES吊打?

文章插图
一般 Term 都是按照顺序排序的,比如 Author 名称就是按照字母序进行了排序,排序之后,当我们搜索某一个 Term 时,就不需要从头遍历,而是采用二分查找 。一系列排序后的 Term 就组成了索引表 Term Dictionary 。
但是 Term Dictionary 往往很大,无法完整放入内存,这是为了更快的查询,还需要再给它创建索引,也就是 Term Index。
ElasticSearch 使用 Burst-Trie 结构来实现 Term Index,它是一种前缀树 Trie 的一种变种,它主要是将后缀进行了压缩,降低了Trie的高度,从而获取更好查询性能 。
Term Index 并不需要像 MySQL 的索引一样,包含所有的 Term,而是包含的是这些 Term 的前缀 。它就类似于字典的查询目录,可以进行快速定位到 Term Dictionary 的某一位置,然后再从这个位置向后查询 。
综上,Alice,Alf,Arlan,Bob,Tom 等词的倒排索引如下所示 。绿色部分是 Term Index,蓝色部分是 Term Dictionary,红色部分是 Posting List 。


推荐阅读