1、前言api
上一篇说了这篇要讲解Search机制,可是在这个以前咱们要明白下文件是怎么存储的,咱们先来说文件的存储而后再来探究机制;缓存
2、文档存储
并发
以前说过文档是存储在分片上的,这里要思考一个问题:文档是经过什么方式去分配到分片上的?咱们来思考以下几种方式:async
1.经过文档与分片取模实现,这样作的好处在于能够将文档平均分配到因此的分片上;性能
2.随机分配固然也能够,这种可能形成分配不均,照成空间浪费;日志
3.轮询这种是最不可取的,采用这种你须要创建文档与分片的映射关系,这样会致使成本太大;blog
通过一轮强烈的思考,咱们选择方案1,没错你想对了,这里Elasticsearch也和咱们思考的是同样的,咱们来揭露下他分配的公式:排序
shard_num = hash(_routing)%num_primary_shards索引
routing是一个关键参数,默认是文档id,能够自行指定;队列
number_of_primary_shard 主分片数;
以前咱们介绍过节点的类型,接下来咱们来介绍下,当文档建立时候的流程:
假设的状况:1个主节点和2个数据节点,1个副本:
文档的建立:
1.客户端向节点发起建立文档的请求;
2.经过routing计算文档存储的分片,查询集群确认分片在数据节点1上,而后转发文档到数据节点1;
3.数据节点1接收到请求建立文档,同时发送请求到该住分片的副本;
4.主分片的副本接收到请求则开始建立文档;
5.副本分片文档完成之后发送成功的通知给主分片;
6.当主分片接收到建立完成的信息之后,发送给节点建立成功的通知;
7.节点返回结果给客户端;
3、Search机制
搜索的类型其实有2种:Query Then Ferch和DFS Query Then Ferch,当咱们明白如何存储文件的是时候,再去理解这两种查询方式会很简单;
Query Then Ferch
Search在执行的时候分为两个步骤运做Query(查询)和Fetch(获取),基本流程以下:
1.将查询分配到每一个分片;
2.找到全部匹配的文档,并在当前的分片的文档使用Term/Document Frequency信息进行打分;
3.构建结果的优先级队列(排序,分页等);
4.将结果的查询到的数据返回给请求节点。请注意,实际文档还没有发送,只是分数;
5.将全部分片的分数在请求节点上合并和排序,根据查询条件选择文档;
6.最后从筛选出的文档所在的各个分片中检索实际的文档;
7.结果将返回给客户端;
DFS Query Then Ferch
DFS是在进行真正的查询以前, 先把各个分片的词频率和文档频率收集一下, 而后进行词搜索的时候, 各分片依据全局的词频率和文档频率进行搜索和排名,基本流程以下:
1.提早查询每一个shard,询问Term和Document frequency;
2.将查询分配到每一个分片;
3.找到全部匹配到的文档,而且在全部分片的文档使用Term/Document Frequency信息进行打分;
4.构建结果的优先级队列(排序,分页等);
5.将结果的查询到的数据返回给请求节点。请注意,实际文档还没有发送,只是分数;
6.来自全部分片的分数合并起来,并在请求节点上进行排序,文档被按照查询要求进行选择;
7.最终,实际文档从他们各自所在的独立的分片上检索出来;
8.结果被返回给客户端;
总结下,根据上面的两种查询方式来看的DFS查询得分明显会更接近真实的得分,可是DFS 在拿到全部文档后再重新完整的计算一次相关性算分,耗费更多的cpu和内存,执行性能也比较低下,通常不建议使用。使用方式以下:
另外要是当文档数据很少的时候能够考虑使用一个分片;
这个地方咱们在作一些深刻的思考:咱们搜索的时候是经过倒排索引,可是倒排索引一旦创建是不能修改的,这样作有那些好处坏处?
好处:
1.不用考虑并发写入文件的问题,杜绝锁机制带来的性能问题;
2.文件再也不更改,能够充分利用文件系统缓存,只需载入一次,只要内容足够,对该文件的读取都会从内存中读取,性能高;
坏处:
写入新文档时,必须从新构建倒排索引文件,而后替换老文件后,新文档才能被检索,致使文档实时性差;
问题:
对于新插入文档的时候写入倒排索引,致使倒排索引重建的问题,假如根据新文档来从新构建倒排索引文件,而后生成一个新的倒排索引文件,再把用户的原查询切掉,切换到新的倒排索引。这样开销会很大,会致使实时性很是差。
Elasticsearch如何解决文件搜索的实时性问题:
新文档直接生成新的倒排索引文件,查询的时候同时查询全部的倒排文件,而后作结果的汇总计算便可,ES是是经过Lucene构建的,Lucene就是经过这种方案处理的,咱们介绍下Luncene构建文档的时候的结构:
1.Luncene中单个倒排索引称为Segment,合在一块儿称为Index,这个Index与Elasticsearch概念是不相同的,Elasticsearch中的每一个Shard对应一个Lucene Index;
2.Lucene会有个专门文件来记录全部的Segment信息,称为Commit Point,用来维护Segment的信息;
Segment写入磁盘的时候过程当中也是比较慢的,Elasticsearch提供一个Refresh机制,是经过文件缓存的机制实现的,接下咱们介绍这个过程:
1.在refresh以前的文档会先存储在一个Buffer里面,refresh时将Buffer中的全部文档清空,并生成Segment;
2.Elasticsearch默认每1秒执行一次refresh,所以文档的实时性被提升到1秒,这也是Elasticsearch称为近实时(Near Real Time)的缘由;
Segment写入磁盘前若是发生了宕机,那么其中的文档就没法恢复了,怎么处理这个问题?
Elasticsearch引入translog(事务日志)机制,translog的写入也能够设置,默认是request,每次请求都会写入磁盘(fsync),这样就保证全部数据不会丢,但写入性能会受影响;若是改为async,则按照配置触发trangslog写入磁盘,注意这里说的只是trangslog自己的写盘。Elasticsearch启动时会检查translog文件,并从中恢复数据;
还有一种机制flush机制,负责将内存中的segment写入磁盘和删除旧的translog文件;
新增的时候搞定了,那删除和更新怎么办?
删除的时候,Lucene专门维护一个.del文件,记录全部已经删除的文档,del文件上记录的是文档在Lucene内部的id,查询结果返回前过滤掉.del中的全部文档;
更新就简单了,先删除而后再建立;
随着Segment增长,查询一次会涉及不少,查询速度会变慢,Elasticsearch会定时在后台进行Segment Merge的操做,减小Segment的数量,经过force_merge api能够手动强制作Segment Merge的操做;
另外能够参考下这篇文段合并;
4、下节预告
原本还想说下聚合、排序方面的查询,可是看篇幅也差很少了,留点时间出去浪,最近不光要撒狗粮,也要撒知识,国庆节期间准备完成Elastic Stack系列,下面接下来还会有4-5篇左右,欢迎你们加群438836709,欢迎你们关注我公众号!