深入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,里面有indextranslog两个目录。前者对应的就是一个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 步骤

下面整个实验的步骤:

  1. 首先索引一个文档
  2. 文档内容同时写入了缓存和translog
  3. 手动执行refresh
  4. Elasticsearch创建segment 0
  5. 因为Lucene的实时搜索功能,此时doc已经可以被搜索到
  6. 再次索引一个文档并refresh
  7. 得到segment 1,同时新请求被追加到translog文件
  8. 手动执行flush
  9. 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:索引的创建的主要内容,如果未能解决你的问题,请参考以下文章

深入Elasticsearch:索引的创建

深入Elasticsearch:索引的创建

Elasticsearch-PHP 索引操作

深入elasticsearch源码之索引过程

Elasticsearch笔记九之优化

Elasticsearch | 深入理解