Elasticsearch的原理和架构

概述

主要竞争对手是slor
主要参考
https://www.elastic.co/guide/cn/elasticsearch/guide/current

字典

实现字典可以采取以下的数据结构,他们个有优缺点

  • 排序列表Array/List 使用二分法查找,不平衡
  • HashMap/TreeMap 性能高,内存消耗大,几乎是原始数据的三倍
  • Skip List 跳跃表,可快速查找词语,在lucene、redis、Hbase等均有实现。相对于TreeMap等结构,特别适合高并发场景(Skip List介绍)
  • Trie 适合英文词典,如果系统中存在大量字符串且这些字符串基本没有公共前缀,则相应的trie树将非常消耗内存(数据结构之trie树)
  • Double Array Trie 适合做中文词典,内存占用小,很多分词工具均采用此种算法(深入双数组Trie)
  • Ternary Search Tree 三叉树,每一个node有3个节点,兼具省空间和查询快的优点(Ternary Search Tree)
  • Finite State Transducers (FST) 一种有限状态转移机,Lucene 4有开源实现,并大量使用

FST的原理建议访问这个页面
http://examples.mikemccandless.com/fst.py?terms=mop%2F0%0D%0Amoth%2F1%0D%0Apop%2F2%0D%0Astar%2F3%0D%0Astop%2F4%0D%0Atop%2F5%0D%0Azzz%2F10%0D%0A&cmd=Build+it%21

mop/0(/为被索引项目)
moth/1
pop/2
star/3
stop/4
top/5
zzz/10
的构建结果是
这里写图片描述
通过FST,可以快速判断一个字符是否存在,并可以快速找到索引项。同时能充分利用前缀和后缀,节省存储空间。
索引项目的ID等于沿途路径之和。

Lucene

Lucene的目的是建立一个全文检索的工具包。

显然上面针对一个个字母建立fst是不靠谱的(保存指针的空间你足够保存好几个字符了)。所以,上述的每一个字母在实际应用中是代表一个“词“。这就需要分词器。Lucene支持多种分词器。通过分词器,可以查找文件的若干词。

如果说一般的索引是指,“文章号”对“文章中所有关键词”。
那么倒排索引把这个关系倒过来,变成:“关键词”对“拥有该关键词的所有文章号”。所谓倒排索引,一般是通过FST和SkipLIst实现的。

Lucene不但应用于ES上,也应用于ES的主要竞争对手solr上。

ElasticSearch的原理

  • 索引(Index)
    ES将数据存储于一个或多个索引中,索引是具有类似特性的文档的集合。

  • 类型(Type)
    类型是索引内部的逻辑分区(category/partition),然而其意义完全取决于用户需求。因此,一个索引内部可定义一个或多个类型(type)。

  • 文档(Document)
    文档是索引和搜索的原子单位,它是包含了一个或多个域(Field)的容器,基于JSON格式进行表示。文档由一个或多个域组成,每个域拥有一个名字及一个或多个值,有多个值的域通常称为“多值域”。每个文档可以存储不同的域集,但同一类型下的文档至应该有某种程度上的相似之处。

  • SHARD

  1. index包含多个shard
  2. 每个shard都是一个最小工作单元,承载部分数据;每个shard都是一个lucene实例,有完整的建立索引和处理请求的能力。
  3. 增减节点时,shard会自动在nodes中负载均衡
  4. primary shard和replica shard,每个document肯定只存在于某一个primary shard以及其对应的replica shard中,不可能存在于多个primary shard
  5. replica shard是primary shard的副本,负责容错,以及承担读请求负载
  6. primary shard的数量在创建索引的时候就固定了,replica shard的数量可以随时修改
  7. primary shard的默认数量是5,replica默认是1,默认有10个shard,5个primary shard,5个replica shard
  8. primary shard不能和自己的replica shard放在同一个节点上(否则节点宕机,primary shard和副本都丢失,起不到容错的作用),但是可以和其他primary shard的replica shard放在同一个节点上
  • SEGMENT
    elasticsearch中每个shard每隔1秒都会refresh一次,每次refresh都会生成一个新的segment.一个segment对应着硬盘或者缓存(内存充当文件系统的)的一个文件,占用一个文件描述符。

  • translog
    事务日志,在每一次对 Elasticsearch 进行操作时均进行了日志记录。作为临时文件存储在硬盘上。理想中应该是任何一次写入都刷入磁盘,但是性能考虑不可能。实际上是每几秒中调用一次fsync刷到磁盘来提高吞吐量。这当然带来了丢失数据的可能。

存储过程

  • 第一步,新增的数据只存储在translog和内存中的buffer中
    在这里插入图片描述

  • 第二步,refresh操作。清空buffer中的数据(translog数据不变),新建segment并式segment可以被检索的到。refresh操作会创建新的段,ES中默认每秒中进行一次refresh。
    在这里插入图片描述
    顺便一题,ES检索数据会同时检索buffer和segment,这样保证数据每一次都能拿到最新的数据。

  • 第三步,不断累积数据,重复数据写到buffer和translog,清空buffer移入新segment的过程。
    在这里插入图片描述

  • 第四步,一定时间后,执行flush操作。清空buffer,translog,所有segment处于commit状态
    在这里插入图片描述

索引合并(segment合并)

每个shard每秒生成一个文件,如果我们不合并,后果肯定是不忍直视的。显而易见的事实是,段越多,搜索也就越慢。
下图显示ES尝试将两个已经提交和一个未提交的段进行合并。
在这里插入图片描述

一旦合并,旧的segment将被删除。
在这里插入图片描述

段合并极为消耗资源,所以一般情况下ES会对段合并消耗的资源加以限制。

ElasticSearch的架构

客户端请求可以发送到集群的任何节点,每个节点都知道任意文档所处的位置,然后转发这些请求,收集数据,返回给客户端,处理客户端请求的节点成为协调节点。
Elasticsearch基于Java编写,最新版本6.2.x要求Java 8。
ES提供REST API给用户用于日常管理,端口是9100。不过一般情况下,我们都会安装插件Elasticsearch Head。

为什么使用FST

HashMap的Key,Value,Entry等都以对象的形式存储,因此对象的额外占用内存很多。但HashMap一般有比较快的查询速度。

FST压缩率一般在3倍~20倍之间,相对于TreeMap/HashMap的膨胀3倍,内存节省就有9倍到60倍(摘自https://blog.csdn.net/whinah/article/details/9980893)

使用132762个<英文单词, 随机正整数>键值对(txt文件,2313KB)来构造FST和HashMap,对比结果如下:

FST HashMap 比较
在这里插入图片描述
参考文献:
https://blog.csdn.net/zx2011302580235/article/details/88594342

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值