ElasticSearch架构原理
ElasticStack数据流#
ElasticSearch#
基本概念与MySQL的对比#
ElasticSearch | MySQL |
---|---|
Index | Database |
Type (未来将删除) | Table |
Document | Row |
Field | Column |
Mapping | Schema |
Everything is indexed | Index |
Query DSL | SQL |
GET HTTP | SELECT |
PUT HTTP | UPDATE |
倒排索引#
倒排索引项#
- 文档_id;
- 词频TF:token在文档中出现的次数,用于相关性评分;
- 位置Position:token在文档中分词的位置,用于match_phrase类型的查询;
- 偏移量Offset:记录token开始和结束的位置,实现高亮显示。
创建倒排索引#
对文档内容进行分词,形成一个个token(可以理解为单词),保存token和文档_id之间的关系。
检索倒排索引#
先对检索内容进行分词(适用于match查询方法,term/terms查询不分词),然后在倒排索引中寻找匹配的token,最后返回token对应的文档以及根据文档中token匹配情况给出的评分score。
分词器Analyzer#
在Elasticsearch中可通过内置分词器实现分词,也可以按需定制分词器。
Analyzer由三部分组成:
- Character Filters:原始文本处理,它的作用是整理字符串。如去除HTML,或者将&转化为and;
- Tokenizer:按照规则切分为单词。比如whitespace的分词器在遇到空格和标点的时候,可能会将文本进行拆分;
- Token Filters:对切分单词加工,如小写(lowercase token filter)、删除a,and和the等stopwords(stop token filter),增加同义词(synonym token filter)等。
利用ElasticSearch提供的webAPI可以查看索引中某一字段field对文本text的分词策略:
POST /[index]/_analyze
{
"field": [field],
"text": [text]
}
建立索引和类型#
- 在Elasticsearch集群中,节点是对等的,节点间会通过自己的一些规则选取集群的Master,Master节点会负责集群状态信息的改变,并同步给其他节点。
- 建立索引和类型的请求先发送到Master节点,Master建立完索引后,将集群状态同步至Slave节点。
- 只有建立索引和类型需要经过Master节点,数据的写入有一个简单的Routing规则,可以Route到集群中的任意节点,所以数据写入压力是分散在整个集群的。
分片内文档写入流程#

-
In-memory Buffer
在主分片节点上,文档会先被写入到内存(In-memory Buffer)中,此时数据还不能被搜索到。 -
Refresh
经过一段时间(refresh_interval)或者内存缓冲满了,Elasticsearch会将内存中的文档Refresh到文件系统缓存(Filesystem Cache)中,并清除内存中的对应文档。 -
Filesystem Cache
文档在文件系统缓存中被解析为Lucene的底层文件Segment中,同时建立倒排索引。这个时候文档是可以被搜索到的,因此减少了后续写入磁盘的大量时间,体现了Elasticsearch搜索的实时性(下图中的绿色和灰色图标分别代表已写入磁盘和未写入磁盘的文档)。
-
Segment
Lucene把每次生成的倒排索引,叫做一个段(Segment),它无法被修改,只能被合并和删除。另外使用一个Commit文件,记录索引内所有的Segment。由于每次打开一个Segment就会消耗一个文件句柄,随着Segment越来越多,将导致查询性能越来越差。这时,ElasticSearch后台会有一个单独线程专门合并Segment,将零碎的小的Segment合并成一个大的Segment。
-
Flush
将Segment写入磁盘中,更新Commit文件并删除文档对应的Translog文件。 -
Translog
Elasticsearch在把数据写入到Index Buffer的同时,其实还另外记录了一个Translog日志。它是以顺序写文件的形式写入到磁盘中的,速度较快。如果发生异常,Elasticsearch会从Commit位置开始,恢复整个Translog文件中的记录,保证数据一致性。
多个分片的文档写入#
确定文档存储位置#
计算方式:
shard = hash(routing) % number_of_primary_shards
每个文档都有一个routing参数,默认情况下就使用其 _id 值。将其 _id 值计算哈希后,对索引的主分片数取余,就得到了文档实际应该存储到的分片。因此索引的主分片数不可以随意修改,一旦主分片数改变,所有文档的存储位置计算结果都会发生改变,索引数据就完全不可读了。
同步副本#
- 客户端请求发送给Node 1节点,注意图中Node 1是Master节点,实际完全可以不是;
- Node 1用文档的 _id 取余计算得到应该将数据存储到shard 0上。通过Cluster State信息发现shard 0的主分片已经分配到了Node 3上。Node 1转发请求数据给Node 3;
- Node 3完成请求数据的索引过程,存入主分片 0。然后并行转发数据给分配有shard 0的副本分片的Node 1和Node 2。当收到任一节点汇报副本分片数据写入成功,Node 3即返回给初始的接收节点 Node 1,宣布数据写入成功。Node 1返回成功响应给客户端;
- 当集群中某个节点宕机,该节点上所有分片中的数据全部丢失(既有主分片,又有副分片)。丢失的副分片对数据的完整性没有影响,丢失的主分片在其他节点上的副分片会被选举成主分片;所以整个索引的数据完整性没有被破坏。
注:图中P代表主分片(Primary Shard),R代表副本(Replica Shard)。
根据_id查询文档#
GET /[index]/_doc/[_id]

- Elasticsearch集群中的任意节点都可以作为协调(Coordinating)节点接受请求,每个节点都知道集群中任一文档位置;
- 协调节点对文档的_id进行路由,从而判断该数据在哪个Shard,然后将请求转发给对应的节点,此时会使用随机轮询算法,在Primary Shard和Replica Shard中随机选择一个,从而对请求负载均衡;
- 处理请求的节点返回文档给协调节点;
- 协调节点返回文档给客户端。
根据字段值检索数据#
GET /[index]/_search?q=[field]: [value]

- Elasticsearch集群中的任意节点都可以作为协调(Coordinating)节点接受请求,每个节点都知道集群中任一文档位置;
- 协调节点进行分词等操作后,向所有的shard节点发送检索请求;
- ElasticSearch已建立字段的倒排索引,即可通过字段值检索到所在文档的_id。随后Shard将满足条件的数据(_id、排序字段等)信息返回给协调节点;
- 协调节点将数据重新进行排序,获取到真正需要返回的文档的_id。协调节点再次向对应的Shard发起请求(此时已经有_id 了,可以直接定位到对应的Shard);
- Shard将_id对应的文档的完整内容返回给协调节点;
- 协调节点获取到全部检索结果,返回给客户端。
上述流程和根据_id查询文档相比,只是多了一个从倒排索引中根据字段值寻找文档_id的过程,其中的4~6步与其完全相同。
作者:koktlzz
出处:https://www.cnblogs.com/koktlzz/p/14303609.html
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 25岁的心里话
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现