为毛我还没过上小康生活捏?因为 ES 没学好。
4 Elasticsearch 为什么快?
为什么Elasticsearch/Lucene检索可以比MySQL快?
4.1 索引是个啥
索引(indexing):就是把一个 关键码 与它对应的 数据记录位置 相关联的过程,不同的索引有不同的关联方式。
4.2 关系型数据库的 B-Tree 索引
二叉树查找效率是logN,同时插入新的节点不必移动全部节点,所以用树型结构存储索引,能同时兼顾插入和查询的性能。因此在这个基础上,再结合磁盘的读取特性(顺序读/随机读),传统关系型数据库采用了B-Tree/B+Tree这样的数据结构。
4.2.1 MyISAM索引
MyISAM表的索引和数据是分离的,索引保存在”表名.MYI”文件内,而数据保存在“表名.MYD”文件内。
4.2.2 InnoDB索引
首先检索辅助索引获得主键,然后用主键到主索引中检索获得记录。
4.3 Lucene 索引
4.3.1 Inverted Index(倒排索引)
Lucene 实现快速搜索的核心就是倒排索引,那什么是倒排索引呢?
这里每一行是一个document,每个document都有一个docid,那么给这些document建立的倒排索引
一个字段有一个自己的倒排索引。18,20 这些叫做 term,而 [1,3] 就是posting list。Posting list就是一个 int 的数组,存储了所有符合某个 term 的文档 id。
4.3.2 Term Dictionary
为了能快速找到某个term,将所有的term排序 排序后:Carla, Sara, Elin, Ada, Patty 用二分查找的方式查找 term,这个就是 term dictionary。 有了 term dictionary 之后,可以用 logN 次磁盘查找得到目标。 为了尽量少的读磁盘,但是磁盘的随机读操作仍然是非常昂贵的(一次random access大概需要10ms的时间),有必要把一些数据缓存到内存里。但是整个 term dictionary 本身又太大了,无法完整地放到内存里。 于是就有了 term index。
4.3.3 Term Index
term index 实际为一棵 tire 树,只存 term 的一些前缀。 通过 term index 可以快速地定位到 term dictionary 的某个偏移量, 然后从这个位置再往后顺序查找。 再加上一些压缩技术,使得用内存缓存整个 term index 变成可能。
4.3.4 索引流程
前端在搜索框输入书籍名称,点击查询。后台的 ES 对书籍名称进行分词,形成一个或多个 term。用 term 去查询内存中的 term index,定位到磁盘中的快速地定位到 term dictionary 的某个偏移量,然后从这个位置再往后顺序查找,找到倒排表。通过倒排表找到对应文档在磁盘中的地址,然后根据地址找到文档值。
4.4 总结
现在我们可以回答 “ 为什么 Elasticsearch/Lucene 检索可以比MySQL快 ” 了。
Mysql 只有 term dictionary 这一层,是以树的方式存储在磁盘上的。检索一个 term 对磁盘进行若干次的 random access(随机访问)。而 Lucene 在 term dictionary 的基础上添加了 term index 来加速检索,term index 以树的形式缓存在内存中。从 term index 查到对应的 term dictionary 的 block 位置之后,再去磁盘上找 term,大大减少了磁盘的 random access 次数。
额外值得一提的两点是:前缀树
term index 在内存中是以 FST(finite state transducers)的形式保存的,其特点是非常节省内存。Term dictionary 在磁盘上是以分 block 的方式保存的,一个 block 内部利用公共前缀压缩,比如都是Ab开头的单词就可以把Ab省去。这样 term dictionary 可以更节约磁盘空间。
5 分片
Elasticsearch基础知识——集群、节点、索引、分片
5.1 概念
如果一个索引具有很大的数据量,它的数据量可能会超出单个节点的容量限制(硬盘容量),而且单个节点数据量过大,执行性能也会随之下降,每个搜索请求的执行效率都会降低。
为了解决上述问题, Elasticsearch 提出了分片的概念,索引将划分成多份,称为分片(shard)。默认情况下,一个索引具有一个主分片,一个主分片有一个副分片。(7.x版本之前,一个索引默认有 5 个主分片和 1 个副分片)。
一个 Elasticsearch 索引是分片的集合。Elasticsearch 中的分片其实就是 Lucene 索引,一个 Lucene 索引最大可存放2,147,483,519 个文档。一个分片默认存储原始文档的内容,再加上一些额外的信息,如词条字典和词频。
此外,一个 Lucene 索引由一个或多个 segment 构成,每个 segment 本质上就是一个倒排索引。
下图为 lucene 索引存储结构概念图
在lucene 中,同时还会维护一个文件 commit point,用来记录当前所有可用的 segment,当我们在这个 commit point 上进行搜索时,就相当于在它下面的 segment 中进行搜索,每个 segment 返回自己的搜索结果,然后进行汇总返回给用户。
当索引一个文档的时候,文档会被存储到一个主分片中。那 Elasticsearch 如何知道一个文档应该存放到哪个分片中呢?真相就是下面的公式:
shard = hash(routing) % number_of_primary_shards
routing 是一个可变值,默认是文档的 _id ,也可以设置成一个自定义的值。 routing 通过 hash 函数生成一个数字,然后这个数字再除以 number_of_primary_shards (主分片的数量)后得到余数 。这个分布在 0 到 number_of_primary_shards-1 之间的余数,就是我们所寻求的文档所在分片的位置。
5.2 分片的作用
分片的主要用处:水平划分数据;多个分片并行执行,提高性能
副本分片主要用处:数据备份;副本分片本身也是一个功能齐全的独立分片,当有查询请求时,既可以在主分片中完成查询,也可以在副本分片中完成查询,当然数据添加、更新的操作只能在主分片中完成。
副本分片与主分片需要分配在不同的节点上,一是为了更好的均衡负载,不同节点上二是节点发生故障时,主分片和副本分片一起故障,没法保证高可用性。所以 Elasticsearch 集群最好要有 2 个节点或以上。
6 分词
7 适用场景
8 项目实战
Elasticsearch 6.2.2 项目应用及操作 (项目实战)
9 Elasticsearch 的祖先 Lucene
Lucene 默认情况下会对所有的数据都进行索引
10 Elasticsearch 的优缺点
1.3.1 优势
(1) 横向可扩展性:只需要增加一台服务器,做一点儿配置,启动一下ES进程就可以并入集群;
(2) 分片机制提供更好的分布性:同一个索引分成多个分片(shard),采用分而治之的方式来提升处理效率;
(3) 高可用:提供复制(replica)机制,一个分片可以设置多个复制,使得某台服务器宕机的情况下,集群仍旧可以照常运行,并会把由于服务器宕机丢失的复制恢复到其它可用节点上;类似于 HDFS 的复制机制(HDFS中默认是3份复制)。
1.3.2 不足
(1) 各节点的一致性问题:其默认的机制是通过多播机制,同步元数据信息,但是在比较繁忙的集群中,可能会由于网络的阻塞,或者节点处理能力达到饱和导致各节点元数据不一致——也就是所谓的脑裂问题,这样会使集群处于不一致状态;
多播机制是个啥呢?
单播:一对一。私聊。
广播:一对所有。公司大群。
组播(多播):一对一组。部门群。
(2) 不支持事务