深入Elasticsearch:索引的创建
Posted cdai
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了深入Elasticsearch:索引的创建相关的知识,希望对你有一定的参考价值。
为了深入学习Elasticsearch和Lucene,本文从Elasticsearch索引的创建过程入手,对Refresh和Flush两个重要的API做一个小实验。从而理解Elasticsearch在接收到一个文档后,是如何对其进行索引的。了解了整个流程,后续我们再深入学习Lucene索引的内存数据结构和磁盘文件格式。注:本文使用Elasticsearch和Kibana 7.10.2。
1.实验环境
1.1 创建索引
创建索引lucene-learning
,设置shard数为1,关闭replica,同时关闭refresh和flush(强制间隔为一小时)。
PUT lucene-learning
{
"settings": {
"index": {
"number_of_shards": 1,
"number_of_replicas": 0,
"refresh_interval": -1,
"translog": {
"sync_interval": "3600s"
}
}
},
"mappings": {
"properties": {
"name": {
"type": "text"
},
"age": {
"type": "integer"
}
}
}
}
1.2 文件目录
从Elasticsearch的目录结构可以看出,索引名和文件夹名是对应的。因为lucene-learning
索引只有一个分片0,所以这里只有一个文件夹0
,里面有index
和translog
两个目录。前者对应的就是一个Lucene的索引(Elasticsearch的Shard等于Lucene的Index),这个文件夹完全由Lucene管理,Elasticsearch不会直接写这里的文件,所有交互应该都是通过Lucene API完成。而后者就是存放Elasticsearch的translog的文件夹了。此时这两个文件里还都没有什么实际内容,一会我们还会再查看它们。
GET _cat/indices?v
health status index uuid pri rep docs.count docs.deleted store.size pri.store.size
green open lucene-learning yGvjXskJQlql1-b2Sx2MHA 1 0 0 0 208b 208b
$ pwd
elasticsearch-7.10.2/data/nodes/0
$ 0 tree -I '_state|5Uwl-yHUTjiCMn9XrZgM-g' -L 5
.
├── indices
│ └── yGvjXskJQlql1-b2Sx2MHA
│ └── 0
│ ├── index
│ │ ├── segments_2
│ │ └── write.lock
│ └── translog
│ ├── translog-2.tlog
│ └── translog.ckp
└── node.lock
$ cat index/segments_2
?�segments
translog_uuidh8Y1UqnyT9ePnvkI4mMQ3Qlocal_checkpoint-1
history_uuidvic9U3IUSvWWP0rDi-fEpA
max_seq_no-1max_unsafe_auto_id_timestamp-1�(��38kZ
$ cat translog/translog-2.tlog
?�translogh8Y1UqnyT9ePnvkI4mMQ3Qy�roW
注:Elasticsearch内部可能做了一些处理,所以Lucene的segment版本号一上来就是2。但这个版本号看起来跟实际segment的序号没有直接关系。
2.实验设计
2.1 步骤
下面整个实验的步骤:
- 首先索引一个文档
- 文档内容同时写入了缓存和translog
- 手动执行refresh
- Elasticsearch创建segment 0
- 因为Lucene的实时搜索功能,此时doc已经可以被搜索到
- 再次索引一个文档并refresh
- 得到segment 1,同时新请求被追加到translog文件
- 手动执行flush
- segment 0和1都被fsync到磁盘,segments文件中的提交点被更新,translog被清空
2.2 解释
请参考第三部分实验过程以及这篇文章Guide to Refresh and Flush Operations in Elasticsearch。
3.实验过程
3.1 索引文档1
现在让我们索引一个文件:
PUT lucene-learning/_doc/1
{
"name": "Allen Hank",
"age": 30
}
即便还未refresh,按照Elasticsearch的设计,此时请求已经同时进入内存缓存和translog。否则一旦发生宕机,缓存中的请求都会丢失。一上来就写入translog,这样丢失的只是为落盘到translog文件的那些请求。此时segment文件没有变化,但能看到多了一些空Lucene文件。
$ pwd
elasticsearch-7.10.2/data/nodes/0/indices/yGvjXskJQlql1-b2Sx2MHA/0
$ tree -I '_state'
.
├── index
│ ├── _0.fdm
│ ├── _0.fdt
│ ├── _0_Lucene85FieldsIndex-doc_ids_0.tmp
│ ├── _0_Lucene85FieldsIndexfile_pointers_1.tmp
│ ├── segments_2
│ └── write.lock
└── translog
├── translog-2.tlog
└── translog.ckp
$ ll index
-rw-r--r-- 1 daichen staff 0B May 27 15:02 _0.fdm
-rw-r--r-- 1 daichen staff 0B May 27 15:02 _0.fdt
-rw-r--r-- 1 daichen staff 0B May 27 15:02 _0_Lucene85FieldsIndex-doc_ids_0.tmp
-rw-r--r-- 1 daichen staff 0B May 27 15:02 _0_Lucene85FieldsIndexfile_pointers_1.tmp
-rw-r--r-- 1 daichen staff 208B May 27 14:53 segments_2
-rw-r--r-- 1 daichen staff 0B May 27 14:53 write.lock
$ cat translog/translog-2.tlog
?�translogPpqSibBGQcK_Cowcf0190Q�$W
1_doc({
"name": "Allen Hank",
"age": 30
}
��������PQ�
【可选】如果现在搜索的话,是无法查到刚才的文档(注意这一步可能会影响下一步refresh的观察结果)。
POST lucene-learning/_search
{
"took" : 8,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 0,
"relation" : "eq"
},
"max_score" : null,
"hits" : [ ]
}
}
手动执行refresh后,可以看Lucene将各种文件合并为.cfe
和.cfs
两个compound文件(具体含义请参照附录),这意味着segment 0已经创建。但是它还没commit,这也是为什么segment_x文件并未发生变化。(如果前面执行过search,Elasticsearch似乎会自动flush)
POST lucene-learning/_refresh
{
"_shards" : {
"total" : 1,
"successful" : 1,
"failed" : 0
}
}
tree -I '_state'
.
├── index
│ ├── _0.cfe
│ ├── _0.cfs
│ ├── _0.si
│ ├── segments_2
│ └── write.lock
└── translog
├── translog-2.tlog
└── translog.ckp
3.2 索引文档2
再索引一个新文档。
PUT lucene-learning/_doc/2
{
"name": "Tom Hank",
"age": 25
}
$ tree -I '_state'
.
├── index
│ ├── _0.cfe
│ ├── _0.cfs
│ ├── _0.si
│ ├── _1.fdm
│ ├── _1.fdt
│ ├── _1_Lucene85FieldsIndex-doc_ids_2.tmp
│ ├── _1_Lucene85FieldsIndexfile_pointers_3.tmp
│ ├── segments_2
│ └── write.lock
└── translog
├── translog-2.tlog
└── translog.ckp
手动执行refresh,得到segment 1:
POST lucene-learning/_refresh
{
"_shards" : {
"total" : 1,
"successful" : 1,
"failed" : 0
}
}
$ tree -I '_state'
.
├── index
│ ├── _0.cfe
│ ├── _0.cfs
│ ├── _0.si
│ ├── _1.cfe
│ ├── _1.cfs
│ ├── _1.si
│ ├── segments_2
│ └── write.lock
└── translog
├── translog-2.tlog
└── translog.ckp
$ cat translog/translog-2.tlog
?�translogh8Y1UqnyT9ePnvkI4mMQ3Qy�roW
1_doc({
"name": "Allen Hank",
"age": 30
}
��������PQ�U
2_doc&{
"name": "Tom Hank",
"age": 25
}
����������X�
3.3 提交
执行flush后,segment数据文件才算真正落盘,此时可以看到segments版本号变为3,提交点包含了segment 0和1。注意因为操作系统本身的缓存,前几步看到的文件不一定真的保存到磁盘上,具体可以搜索系统调用write和fsync的关系。
POST lucene-learning/_flush
{
"_shards" : {
"total" : 1,
"successful" : 1,
"failed" : 0
}
}
$ tree -I '_state'
.
├── index
│ ├── _0.cfe
│ ├── _0.cfs
│ ├── _0.si
│ ├── _1.cfe
│ ├── _1.cfs
│ ├── _1.si
│ ├── segments_3
│ └── write.lock
└── translog
├── translog-3.tlog
└── translog.ckp
$ cat index/segments_3
?�segments
��F�ߝᰆ�4�[3
translog_uuidh8Y1UqnyT9ePnvkI4mMQ3Qmin_retained_seq_no0�ߝᰆ�4�Z�_1��F�ߝᰆ�4Lucene87��������������������������F�ߝᰆ�4�[local_checkpoint1max_unsafe_auto_id_timestamp-1
history_uuidvic9U3IUSvWWP0rDi-fEpA
max_seq_no1�(��!��9
$ cat translog/translog-3.tlog
?�translogh8Y1UqnyT9ePnvkI4mMQ3Qy�ro
以上是关于深入Elasticsearch:索引的创建的主要内容,如果未能解决你的问题,请参考以下文章