ES原理解读

摘要:本篇文章仅仅是谈谈个人对ES原理的理解,可能理解不对的地方,欢迎大家指出。

  • 概念

ES就是elasticsearch,专门做文本搜索,其重要组件是Lucence。

Lucence就是一个jar包,它的主要功能就是提供封装好的各种索引算法、生成倒排索引等。

ES是基于Lucene的搜索服务器,它提供了一个分布式多用户能力的全问搜索引擎,且ES支持RestFulweb风格的url访问。ES是基于Java开发的开源搜索引擎,设计用于云计算,能够达到实时搜索,稳定、可靠、快速。此外,ES还提供了数据聚合分析功能,但在数据分析方面,es的时效性不是很理想,在企业应用中一般还是用于搜索。ES自2016年起已经超过Solr等,称为排名第一的搜索引擎应用。

与数据库对比

RDBS                    ES

数据库(database) 索引(index)

表(table)          类型(type)(ES6.0之后被废弃,es7中完全删除)

表结构(schema) 映射(mapping)

行(row)            文档(document)

列(column)      字段(field)

值                   term

索引              反向索引

SQL                  查询DSL

SELECT * FROM table GET http://.....

UPDATE table SET      PUT  http://......

DELETE              DELETE  http://......

Node:一般指的是一个es服务实例(通常就是在一台机器上)。

Cluster:集群,即由多个es服务组成的服务群组,由多个es实例共同对外提供服务。

primary shard:主分片,用来存储数据,多分片会对数据进行切割,比如id 1 2 3 4 5,现在有两个分片,id 1 3 5 可能存储在分片1上 而id 2 4 则存储在分片2 上。

replica shard:副本分片,即主分片的备份分片,个人认为有两个目的,一个是为了提高查询效率,第二个是保证数据的高可用。

索引:

名词:即上面提到的与RDBS对应为database的概念。

动词:相当于数据库中的insert into的概念,索引(动词)一个文档(一条数据)到索引(名词)中这样这条数据才能被查找到,其实就是在数据中插入一条数据的意思。

倒排索引:相当于RDBS中索引的概念,目的是为了能够快速查找到文档(某一条数据),只是倒排索引的实现比不是B-Tree。

创建过程:

        客户端发往任意节点,创建索引请求会先转为bulk请求,执行createIndex,如果当前节点不是主节点,它然后先去请求master节点。master节点验证索引创建的请求,然后内部算出一个新的集群信息ClusterState,执行executeIngestAndBulk,发往主分片节点,主分片所在数据节点根据ClusterState创建对应的索引。

  • 基本原理
  • 写入过程:
  1. 客户端选择一个node发送请求过去,这个node就是coordinating node(协调节点)
  2. 协调节点接受数据,并根据路由规则对数据进行路由,不同的数据会路由到不同的节点,即将数据发送到给它分配的存储节点上。
  3. 实际节点接受数据并进行处理,完成后将数据同步到副本节点。
  4. 协调节点等待主节点和副本节点处理,当这些节点都处理完成后,协调节点将处理成功的结果返回给客户端。
  • 读取过程:
  1. 客户端发送查询请求到任意节点,也就是上面的协调节点。
  2. 协调节点对查询id(doc id)进行hash路由将请求转发到对应的节点,目的是要能找到id数据所在的节点,此时值得注意的是:发送的时候会进行轮询,在主节点和副本节点上任意选取节点,目的是进行负载均衡。
  3. 当被请求的数据节点查找到数据后,将数据返回给协调节点,协调节点再将数据整理(合并啊、排序啊 等等的)返回给客户端。

以上是es的进本理论和原理,应该还算比较清楚,下面看下存储、搜索、更新、删除等的深入原理

  • 深入原理
  • 文档存储过程:
  1. 数据写入buffer(基本所有的程序写数据都会有这一步),同时将数据写入translog日志文件,此时文档是不可被检索的,因为es还没有生成必要的检索条件。
  2. Translog日志文件其实就是文档的另一个备份,作用有两个(可以在看完文档存储过程后再回头看一下):
  3. 当系统宕机后重启,es会重新加载日志文件中的文档,根据commit point加载需要被加载的文档,生成segment file。
  4. 系统没有宕机的时候,当日志文件超出规定大小,或者超过一定时间30min,es就会强制使用flush操作将segment持久化到磁盘。
  5. 当buffer中的数据量达到一定的量,或者到以一定的时间,es会将buffer中的数据refresh到segment file(段)中,同时更新commint point,此刻数据其实还没有被持久化到磁盘,值得注意的是如果buffer中没有数据此时即使是到了refresh的时间点es也不会进行refresh的。
  6. Segment(段)在被创建写入时会生成对应倒排索引用于索引数据。
  7. Refresh过程中会将segment写入到os cache中,os cache并不是磁盘,而是操作系统级别的缓存,当完成这一步的时候,文档检索将会被打开,此时文件就能就被检索了。
  8. 写入os cache后buffer就不需要了,为了节省空间它将会被立即清理。
  9. 重复接受数据-写入buffer-refresh-生成translog-生成segment
  10. 此时translog越来越大,则会触发commint操作,不过当到了一定的时间30min后也会进行commit。
  11. Commit也叫flush,就是将segment持久化到磁盘,当触发了flush后,buffer中可能存在数据,此时需要将现有的数据执行refush、生成log、segment等操作。
  12. 每个commit都会标识此次commit point有哪些segment是可用的,比如更新的时候原有的segment就是delete状态,重入一条segment。

主要过程图和关系

  • 文档删除和更新
  1. 删除时的commint会生成一个.del文件,这个文件里面会将那些被删除的文档标识为delete,那么在搜索的时候对于客户端而言是检索不到了但是在es中是可以匹配到的只是在返回的时候被过滤,当segment发生合并时,被删除的文档不会被合并,因为没有必要。
  2. 更新时,会先将原有的doc标识为delete,然后重新生成segment并重新写入,注意并不是对segment更新重排,但是其中会有版本记录。
  3. 记住一点:es中的文档是不能被更改的,所有的操作都是写操作。

  • 逆向索引、倒排索引

前面说的倒排索引的作用类似于B-Tree,都是为了能够快速定位数据,如果对其实现算法有兴趣的可以自己看看,我这里只说它在es中的应用。

Position:位置,即一个doc在es中的存储位置,也可以说一行数据在一个index(名词)的一个type(类型、库表)中的位置。

Posting List:位置列表就是一个term(值)在所在doc的位置列表

Position index:位置索引,就是一个term(一个值)与Posting List等的映射关系,说白了就是一个字典。

Term Dictionary:值的字典,为了能快速找到某个term,es添加了值的字典概念,也就是经过排序后的term可以使用二分法快速找到。

Term index:值索引,B-tree基本就是做到了字典哪个阶段,但是海量数据场景的情况下并不适用,比如字典过大放哪,是放内存还是disk,于是就使用了值索引,它就相当于字典的索引页,比如查a开头的term,可以先知道a大概在多少页,Term index就是这么应用的。

FST:压缩技术,能让Term index以极小的空间存储在内存中。

个人认为关系应该是这样的:

·  在Lucene中,单个倒排索引文件被称作Segment。Segment是不可变更的。多个Segment汇总在一起,称为Lucene的Index,其对应的就是ES中的Shard

·  当有新文档写入时,会生成新Segment,查找时会同时查找多个Segments,并且对结果进行汇总。Lucene中有个Commit Point文件,用来记录所有Segments信息。

·  删除文档的信息,会保存在.del文件中。在搜索时,返回的结果会根据.del中记录的文档信息,将其过滤掉。

  1. 没有必要给逆向索引加锁,因为不允许被更改,只有读操作,所以就不用考虑多线程导致互斥等问题。
  2. 索引一旦被加载到了缓存中,大部分访问操作都是对内存的读操作,省去了访问磁盘带来的io开销。
  3. 因为逆向索引的不可变性,所有基于该索引而产生的缓存也不需要更改,因为没有数据变更,这就是为什么更新的时候是将原来的segment删除重新生成segment。
  4. 使用逆向索引可以压缩数据,减少磁盘io及对内存的消耗。

Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐