ElasticSearch倒排索引及其原理

  • 正排索引:文档ID到文档内容和单词的关联
  • 倒排索引:单词到文档ID的关系
    备注:ES对文档每个字段都有自己的倒排索引,可以指定某些字段不做索引,这样可以节省存储空间,缺点是这个字段无法被搜索。

倒排索引不可变性

倒排索引采用Immutable Design,一旦生成,不可更改。

  • 优点
    (1)无需考虑并发写文件的问题,避免了锁机制带来的性能问题
    (2)一旦读入内核的文件系统缓存,便留在那里。只要文件系统存有足够大的空间。大部分请求就会直接请求内存,不会命中磁盘,提升了很大的性能
  • 缺点
    不可变性也带来了另一个挑战,如果需要让一个新的文档可以被索引,需要重建整个索引。

倒排索引文件结构

lucene.png
  • 在Lucene中,单个倒排索引文件被称作Segment。Segment是不可变更的。多个Segment汇总在一起,称为Lucene的Index,其对应的就是ES中的Shard
  • 当有新文档写入时,会生成新Segment,查找时会同时查找多个Segments,并且对结果进行汇总。Lucene中有个Commit Point文件,用来记录所有Segments信息。
  • 删除文档的信息,会保存在.del文件中。在搜索时,返回的结果会根据.del中记录的文档信息,将其过滤掉。

ES索引文档的过程

  1. 请求发送到Coordinating Node,如果该节点不是Master节点,需要将该请求转发到Master.
    Master节点通过路由算法,确定该分片在哪个节点上:
    shard = hash(_routing) % (num_of_primary_shards)
    默认使用文档ID作为_routing值,也可以通过API指定_routing值

  2. 分片节点收到请求后,会将请求写入到Memory Buffer,然后定时(默认是每隔1秒)写入到Filesystem Cache(磁盘缓存),这个从Momery Buffer到Filesystem Cache(磁盘缓存)的过程就叫做Refresh。在写入Buffer的同时,会同时写一个Transaction Log(每个分片会有一个Log文件)。当做refresh时,Buffer会被清空,Transaction Log不会清空。

  3. ES每30分钟,会有一个Flush操作。该操作会调用fsync,将Filesystem Cache中的数据写入segment文件,旧的translog将被删除并开始一个新的translog

  4. ES会自动进行Merge操作,该操作会将多个Segment文件合并,在.del文件中被标记为删除的文档将不会被写入Segment,并且清空.del文件中的内容

ES Refresh

refresh.png
  • 创建索引时,数据并不会直接写入Segment文件,而是会先写入一个Index Buffer缓冲区。而将Index Buffer中数据写入Segment文件的过程就叫Refresh.
  • Refresh的频率默认是每秒一次。可通过index.refresh_interval进行配置。Refresh后,数据就可被搜索到了,这也是为什么ES被称为近实时搜索。
  • Index Buffer被占满时,也会触发Refresh,默认值是JVM的10%

Transaction Log

flush.png

Segment写入磁盘的过程相对耗时,所以借助文件系统缓存,Refresh时,先将Segment写入文件缓存中,以开放查询。但为了保证数据不会丢失,所以在创建索引时,会同时写Tansaction Log,类似操作日志。

在ES进行Refresh时,Index Buffer会被清空,Transaction Log不会清空。

ES Flush

flush2.png

Flush操作:

  1. 调用refresh,清空index buffer
  2. 清空transaction log

Flush触发条件:

  1. 默认30分钟调用一次
  2. Transaction Log 默认达到512M

ES Merge & Force Merge API

随着索引的不断创建,Segments文件会越来越多。ES会自动进行merge操作,将多个segments文件合并,以提高查询效率。但Merge是很重的操作,对磁盘有频繁IO操作,会对系统性能有影响。

除此之外,我们还可以通过api强制merge:

POST /my_index/_forcemerge?max_segements_num=1 
// max_num_segments:最终合并成多少个segments

我们还可以通过配置refresh的频率(refresh_interval),来适当减少Segments产生的数量。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容