检索服务之Elasticsearch
Elasticsearch是一个分布式的,RESTfual搜索和分析引擎,适用于存储、检索、管理数据。
**01 Lucene
**
https://lucene.apache.org/core/
Lucene是一个纯Java实现的,高性能搜索引擎库。它是一个工具包,不是完整的全文检索引擎,Elasticsearch是在Lucene基础上构建的全文检索引擎。
**02 倒排索引
**
倒排索引是Lucene全文检索的核心,考虑下面3个文档
1 hello everyone
2 this article is based on inverted index
3 which is hashmap like data structure
通过分词将每个文档的内容拆分成单独的词(也称为词条或Term),创建一个从词条到文档的索引,这个索引称为倒排索引。
词条(Term)
索引里的最小存储和查询单元,对于英文来说是一个单词,对于中文来说一般指分词后的一个词
字典(Dictionary)
是所有文档中出现过的全部词条的集合,字典中的每个词条具有指向倒排表的指针
倒排表(Post List)
出现某个词的全部文档的有序集合,每个记录称为一个倒排项(Posting),包括文档编号,出现位置,词频等信息
倒排文件(Inverted File)
所有词的倒排表顺序地存储在磁盘文件里,这个文件称之为倒排文件,倒排文件是存储倒排索引的物理文件
Elasticsearch还会为字典做一次索引,生成一棵Trie树,查询时先查询Trie树,然后在字典中顺序查找。
**03 索引分段
**
将一个索引文件拆分为多个子文件,每个子文件叫作段。每个段都是一个独立的可被搜索的数据集,并且段具有不变性,一旦索引的数据被写入硬盘,就不可再修改。
段的概念提出主要是因为在早期全文检索中为整个文档集合建立了一个很大的倒排索引,并将其写入磁盘中。如果索引有更新,就需要重新全量创建一个索引来替换原来的索引。这种方式在数据量很大时效率很低,并且由于创建一次索引的成本很高,所以对数据的更新不能过于频繁,也就不能保证时效性。
采用分段的存储模式,没有更新操作,在读写索引时几乎完全避免了锁的出现,大大提升了读写性能。段被写入到磁盘后会生成一个提交点,提交点是一个用来记录所有提交后段信息的文件。
为了提升写的性能,Elasticsearch并没有每新增一条数据就增加一个段到磁盘上,而是采用延迟写的策略。
-
新增文档时,写入内存缓存(此时搜索不可见)以及translog(用于故障恢复)
-
当内存缓存到达定量、refresh_inverval时间间隔(默认1秒,近实时搜索)或者主动调用refresh,刷新到文件系统缓存(in-memory segment),此时文档可搜索,但未提交
大规模新建索引或者初始建立索引时,关闭刷新(refresh_interval: -1);待索引建立完毕后,重新设置_refresh_interval
_ -
translog每隔一定时间会刷新到磁盘
-
每隔一定时间,translog大小到达定量或者主动调用flush,触发flush
-
刷新文件系统segment缓存到磁盘并生成提交点
-
清空translog
文档更新与删除
segment不可改变,所以文档并不能从之前的segment中移除或更新。删除文档时,在.del文件中标记(逻辑删除),查询时,获取到的结果在返回前会经过.del过滤。
更新=删除和新增,将旧的文档在.del文件中标记删除,然后文档的新版本被索引到一个新的段中。
**段的合并
**
随着文档不断加入索引,segment数目会越来越多,消耗文件描述符、搜索速度也会越来越慢,于是引入了段合并机制。
-
合并之后,会物理删除.del文件中标记的文档,减少文件数和空间占用,这对于频繁更新和删除的场景很有用
-
搜索时,每个段进行搜索,再汇总结果。减少段个数,可以减少查询和结果合并消耗,提升性能
04 集群
Elasticsearch集群搭建很简单,它不需要依赖第三方协调管理组件,自身通过Zen Discovery实现了集群的管理功能。
集群分为主节点和数据节点,数据节点负责数据的存储和相关的操作,所以数据节点对机器配置要求相对比较高。主节点负责索引创建、删除索引,集群其他节点的状态管理,主节点对集群的健康是非常重要的,通常节点不应该即是数据节点,又是主节点。
用户的请求可以发往任何一个节点,并由该节点负责分发请求、收集结果等操作,而不需要主节点转发。这种节点称为协调节点,协调节点是不需要指定和配置的,集群中的任何节点都可以充当协调节点的角色。
**05 分片与副本
**
Elasticsearch支持PB级全文搜索,当索引数据量太大时,Elasticsearch通过水平拆分的方式将一个索引数据拆分出来分配到不同的数据块上,每一个数据块称为一个分片(shard)。一个Elasticsearch index由一个或者多个分片组成,每个分片相当于一个Lucene index,类似于MySQL的分库分表。
分片路由方式
shard = hash(_id) % number_of_primary_shards(主分片数)
PUT /testIdx
{
"settings" : {
"number_of_shards" : 3, # 三个主分片
"number_of_replicas" : 1 # 每个主分片一个副本
}
}
每个分片必须至少有一个主分片和0到多个副本,副本就是对分片的拷贝,主分片和对应的副本分片是不会在同一个节点上的,所以副本分片数的最大值是N-1(其中N为节点数)。对索引的写操作(文档新建、更新和删除),必须在主分片上面完成,之后被复制到相关的副本分片。
大规模新建索引或者初始建立索引时,写入前设置副本数为0(number_of_replicas: 0),等完成写入后复原副本设置
分片是为了提高数据容量,分片做副本是为了提高集群的稳定性和提高并发量。

浙公网安备 33010602011771号