先自上而下,后自底向上的介绍 ElasticSearch 的底层工作原理,试图答复以下问题:
- 为什么我的搜寻
*foo-bar*
无奈匹配foo-bar
? - 为什么减少更多的文件会压缩索引(Index)?
- 为什么 ElasticSearch 占用很多内存?
版本
elasticsearch 版本: elasticsearch-2.2.0
云上的集群
集群里的盒子
云外面的每个红色正方形的盒子代表一个节点——Node。
节点之间
在一个或者多个节点间接,多个绿色小方块组合在一起造成一个 ElasticSearch 的索引。
索引里的小方块
在一个索引下,散布在多个节点里的绿色小方块称为分片——Shard。
Shard=Lucene Index
一个 ElasticSearch 的 Shard 实质上是一个 Lucene Index。这篇 ElasticSearch 具体应用教程,外部分享时被老大褒扬了
Lucene 是一个 Full Text 搜寻库(也有很多其余模式的搜寻库),ElasticSearch 是建设在 Lucene 之上的。接下来的故事要说的大部分内容实际上是 ElasticSearch 如何基于 Lucene 工作的。超具体 116 页 Elasticsearch 实战文档!高清可下载
图解 Lucene
Mini 索引——segment
在 Lucene 外面有很多小的 segment,咱们能够把它们看成 Lucene 外部的 mini-index。
Segment 外部
有着许多数据结构
- Inverted Index
- Stored Fields
- Document Values
- Cache
最最重要的 Inverted Index
Inverted Index 次要包含两局部:
- 一个有序的数据字典 Dictionary(包含单词 Term 和它呈现的频率)。
- 与单词 Term 对应的 Postings(即存在这个单词的文件)。
当咱们搜寻的时候,首先将搜寻的内容合成,而后在字典里找到对应 Term,从而查找到与搜寻相干的文件内容。Elasticsearch 查问数据的工作原理是什么?
查问“the fury”
主动补全(AutoCompletion-Prefix)
如果想要查找以字母“c”结尾的字母,能够简略的通过二分查找(Binary Search)在 Inverted Index 表中找到例如“choice”、“coming”这样的词(Term)。ElasticSearch 亿级数据检索案例实战!
低廉的查找
如果想要查找所有蕴含“our”字母的单词,那么零碎会扫描整个 Inverted Index,这是十分低廉的。
在此种状况下,如果想要做优化,那么咱们面对的问题是如何生成适合的 Term。
问题的转化
对于以上诸如此类的问题,咱们可能会有几种可行的解决方案:
* suffix -> xiffus *
如果咱们想当前缀作为搜寻条件,能够为 Term 做反向解决。
(60.6384, 6.5017) -> u4u8gyykk
对于 GEO 地位信息,能够将它转换为 GEO Hash。
123 -> {1-hundreds, 12-tens, 123}
对于简略的数字,能够为它生成多重模式的 Term。
解决拼写错误
一个 Python 库 为单词生成了一个蕴含谬误拼写信息的树形状态机,解决拼写错误的问题。
Stored Field 字段查找
当咱们想要查找蕴含某个特定题目内容的文件时,Inverted Index 就不能很好的解决这个问题,所以 Lucene 提供了另外一种数据结构 Stored Fields 来解决这个问题。实质上,Stored Fields 是一个简略的键值对 key-value。默认状况下,ElasticSearch 会存储整个文件的 JSON source。
Document Values 为了排序,聚合
即便这样,咱们发现以上构造依然无奈解决诸如:排序、聚合、facet,因为咱们可能会要读取大量不须要的信息。
所以,另一种数据结构解决了此种问题:Document Values。这种构造实质上就是一个列式的存储,它高度优化了具备雷同类型的数据的存储构造。
为了提高效率,ElasticSearch 能够将索引下某一个 Document Value 全副读取到内存中进行操作,这大大晋升访问速度,然而也同时会消耗掉大量的内存空间。
总之,这些数据结构 Inverted Index、Stored Fields、Document Values 及其缓存,都在 segment 外部。
搜寻产生时
搜寻时,Lucene 会搜寻所有的 segment 而后将每个 segment 的搜寻后果返回,最初合并出现给客户。
Lucene 的一些个性使得这个过程十分重要:
- Segments 是不可变的(immutable)
- Delete? 当删除产生时,Lucene 做的只是将其标记地位为删除,然而文件还是会在它原来的中央,不会产生扭转
- Update? 所以对于更新来说,实质上它做的工作是:先删除,而后从新索引(Re-index)
- 随处可见的压缩
- Lucene 十分善于压缩数据,基本上所有教科书上的压缩形式,都能在 Lucene 中找到。
- 缓存所有的所有
- Lucene 也会将所有的信息做缓存,这大大提高了它的查问效率。
缓存的故事
当 ElasticSearch 索引一个文件的时候,会为文件建设相应的缓存,并且会定期(每秒)刷新这些数据,而后这些文件就能够被搜寻到。
随着工夫的减少,咱们会有很多 segments,
所以 ElasticSearch 会将这些 segment 合并,在这个过程中,segment 会最终被删除掉
这就是为什么减少文件可能会使索引所占空间变小,它会引起 merge,从而可能会有更多的压缩。
举个栗子
有两个 segment 将会 merge
这两个 segment 最终会被删除,而后合并成一个新的 segment
这时这个新的 segment 在缓存中处于 cold 状态,然而大多数 segment 依然放弃不变,处于 warm 状态。
以上场景常常在 Lucene Index 外部产生的。
在 Shard 中搜寻
ElasticSearch 从 Shard 中搜寻的过程与 Lucene Segment 中搜寻的过程相似。
与在 Lucene Segment 中搜寻不同的是,Shard 可能是散布在不同 Node 上的,所以在搜寻与返回后果时,所有的信息都会通过网络传输。
须要留神的是:
1 次搜寻查找 2 个 shard = 2 次别离搜寻 shard
对于日志文件的解决
当咱们想搜寻特定日期产生的日志时,通过依据工夫戳对日志文件进行分块与索引,会极大进步搜寻效率。
当咱们想要删除旧的数据时也十分不便,只需删除老的索引即可。
在上种状况下,每个 index 有两个 shards
如何 Scale
shard 不会进行更进一步的拆分,然而 shard 可能会被转移到不同节点上
所以,如果当集群节点压力增长到肯定的水平,咱们可能会思考减少新的节点,这就会要求咱们对所有数据进行从新索引,这是咱们不太心愿看到的,所以咱们须要在布局的时候就思考分明,如何去均衡足够多的节点与有余节点之间的关系。
节点调配与 Shard 优化
- 为更重要的数据索引节点,调配性能更好的机器
- 确保每个 shard 都有正本信息 replica
路由 Routing
每个节点,每个都存留一份路由表,所以当申请到任何一个节点时,ElasticSearch 都有能力将申请转发到冀望节点的 shard 进一步解决。
一个实在的申请
Query
Query 有一个类型 filtered,以及一个 multi\_match 的查问
Aggregation
依据作者进行聚合,失去 top10 的 hits 的 top10 作者的信息
申请散发
这个申请可能被散发到集群里的任意一个节点
上帝节点
这时这个节点就成为以后申请的协调者(Coordinator),它决定:
- 依据索引信息,判断申请会被路由到哪个外围节点
- 以及哪个正本是可用的
- 等等
路由
在实在搜寻之前
ElasticSearch 会将 Query 转换成 Lucene Query
而后在所有的 segment 中执行计算
对于 Filter 条件自身也会有缓存
但 queries 不会被缓存,所以如果雷同的 Query 反复执行,应用程序本人须要做缓存
所以,
- filters 能够在任何时候应用
- query 只有在须要 score 的时候才应用
返回
搜寻完结之后,后果会沿着上行的门路向上逐层返回。
起源:https://www.cnblogs.com/richa…