物理结构
Shard-Segment
每个segment中包含
- Inverted Index
- a. 一个有序的数据字典 Dictionary(包括单词 Term 和它出现的频率)。
- b. 与单词 Term 对应的 Postings(即存在这个单词的文件)
- Stored Fields 单独把指定Field拉出来存储,查询时取值速度快,一般在从_source中获取代价比较大时指定(获取10个feild值是从_source中获取1个的10倍)
- Document Values
- Cache 动态索引
内存中加载Term index,硬盘存储Term字典+倒排表
实际上lucene的Term index采用了FST变种的trie树,既能前缀匹配也能后缀匹配,而且大大节省了空间
索引过程
如上图所示,为一个节点索引文档的流程:
- elasticsearch节点接收index请求,存入index buffer,同步存入磁盘transationlog后返回索引结果
- Refresh定时将index buffer数据生成segment,存入到操作系统缓存,此时没有fsync,清空indexbuffer,此时就可以被elasticsearch查询了,如果index buffer占满时,也会触发refresh,默认为jvm的10%。
- Flush定时将缓存中的segments写入到磁盘,删除transactionlog。如果transactionlog满时(512m),也会触发flush。
- 如果数据很多,segment的也很多,同时也可能由删除的文档,elasticsearch会定期将它们合并。
检索过程
- 内存加载的Term Index结构
| 1级 | 2级 | 3级 |
|---|---|---|
| 索引2023-03-01 | Shard1 | Term Index |
| 索引2023-03-01 | Shard2 | Term Index |
- 查询以索引为维度,在内存中匹配所有Shard的Term index的Trie,再去命中的Shard中的Dictionary和Posting List找到doc id,再去读doc。
Lucene 索引文件结构主要的分为:词典、倒排表、正向文件、DocValues等,如下图:
优化方法
ES写入优化
- 客户端优化:bulk批量操作,
- 清洗优化:Kafka削峰,部分场景丢弃_source,不存储非必要的大字段
- 服务端优化:
- tranlog:异步
- refresh优化:间隔、分词算法ik_smart、hanlp,设置字段不分词(type=keyword)
- 系统缓存:加内存、刷到ssd硬盘、量大的索引写入到同一集群
- merge:ssd、merge线程数、merge流量限制
- 副本同步:减少副本数
ES查询优化
query->filter …… shard数 数据层优化:数据切分