0%

ElasticSearch-Index Template 和 Dynamic Template

1. Index Templates

相关阅读:https://www.elastic.co/guide/en/elasticsearch/reference/7.4/indices-templates.html

Index Templates 会帮助你设定 Mappings 和 Settings,并按照一定的规则自动匹配到新创建的索引上。其符合如下几点规则:

  • 模板仅在一个索引被新创建时才会产生作用,修改模板不会影响已创建的索引;
  • 可以设定多个索引模板,符合指定规则的索引会将模板进行 “merge”,其中模板所指定的 order 可以控制模板的合并顺序,order 值较大者的会覆盖较小者。
  • 应用创建索引时,用户所指定的 Settings 和 Mappings 会覆盖之前模板中的设定。

下面通过例子来讲解下。首先我们创建索引 mytemplate,具体如下所示:

1
2
3
4
5
PUT mytemplate/_doc/1
{
"someNumber":"1",
"someDate":"2019/01/01"
}

由于 ElasticSearch 默认支持对符合日期类型的字段自动转为 date 类型,所以 someDate 字段不是 text 类型,而是 date 类型:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
GET mytemplate/_mapping
// 结果
{
"mytemplate" : {
"mappings" : {
"properties" : {
"someDate" : {
"type" : "date",
"format" : "yyyy/MM/dd HH:mm:ss||yyyy/MM/dd||epoch_millis"
},
"someNumber" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
}
}
}
}
}

下面我们创建一个默认 Index Template,由于 index_patterns 字段设置的正则规则默认匹配所有索引,索引后续新创建的索引都会按照 template_default 模板来设置对应的 settings:

1
2
3
4
5
6
7
8
9
10
PUT _template/template_default
{
"index_patterns": ["*"], // 适用所有索引
"order" : 0,
"version": 1,
"settings": {
"number_of_shards": 1, // 设置一个分片
"number_of_replicas": 2 // 设置两个副本分片
}
}

例如下面添加一个索引,然后查询其 settings:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
PUT new_index/_doc/1
{
"someNumber":"1",
"someDate":"2019/01/01"
}

GET new_index/_settings

// 结果
{
"new_index" : {
"settings" : {
"index" : {
"creation_date" : "1673272193840",
"number_of_shards" : "1", // 一个分片
"number_of_replicas" : "2", // 两个副本分片
"uuid" : "cAZapaEtQ9Own7YCyR8kWQ",
"version" : {
"created" : "7040299"
},
"provided_name" : "new_index"
}
}
}
}

我们再创建一个模板,该模板仅匹配名称以 test 开头的索引。需要说明的是由于 template_test 指定的 order 为 1,所以后续创建的以 test 开头的索引将会使用到 template_test 模板,其中 number_of_replicas 将会覆盖为 3。另外 date_detection 由于设置为 false,将不再支持对符合日期规则的 text 文本转为 date 类型。由于 numeric_detection 设置为 true,将会对 text 类型的数值转为 long 类型数值。

1
2
3
4
5
6
7
8
9
10
11
12
13
PUT /_template/template_test
{
"index_patterns" : ["test*"],
"order" : 1,
"settings" : {
"number_of_shards": 1,
"number_of_replicas" : 3
},
"mappings" : {
"date_detection": false, // 日期格式检测,默认开启,会将字符串日期转成 date 类型
"numeric_detection": true // 数值检测,默认关闭,会将字符串数值转为数值
}
}

如下我们添加一个索引,并查询其 mapping 和 setting 值:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
PUT test_index/_doc/1
{
"someNumber":"1",
"someDate":"2019/01/01"
}

GET test_index/_mapping
// 响应
{
"test_index" : {
"mappings" : {
"date_detection" : false,
"numeric_detection" : true,
"properties" : {
"someDate" : { // 不再是 date 类型
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"someNumber" : {
"type" : "long" // 转为 long 类型
}
}
}
}
}

GET test_index/_settings
// 响应
{
"test_index" : {
"settings" : {
"index" : {
"creation_date" : "1673272800166",
"number_of_shards" : "1",
"number_of_replicas" : "3", // 三个副本分片
"uuid" : "Q__3CZOwR_yuTtrBL206vw",
"version" : {
"created" : "7040299"
},
"provided_name" : "test_index"
}
}
}
}

下面我们再显式设置索引的 testmy 的 settings,虽然其匹配 template_test 模板,但是显式指定的 settings 会覆盖模板中的设定:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
PUT testmy
{
"settings":{
"number_of_replicas":5
}
}

// settings
{
"testmy" : {
"settings" : {
"index" : {
"creation_date" : "1673273008702",
"number_of_shards" : "1",
"number_of_replicas" : "5",
"uuid" : "6twmxOU_Q76NvAgEUrEIHw",
"version" : {
"created" : "7040299"
},
"provided_name" : "testmy"
}
}
}
}

2. Dynamic Templates

相关阅读:https://www.elastic.co/guide/en/elasticsearch/reference/7.4/dynamic-mapping.html

Dynamic Templates 根据 ElasticSearch 识别的数据类型结合字段名称匹配规则来动态设定字段类型,例如将所有的字符串类型都设定为 keyword 类型,或将 is 开头的字段都设置成 boolean 类型等。

下面我们添加一个文档,默认情况下 firstName 和 isVIP 都是 text 类型,且都含有 keyword 类型子字段,mappings 结果如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
PUT my_index/_doc/1
{
"firstName":"Ruan",
"isVIP":"true"
}

// mappings 结果
{
"my_index" : {
"mappings" : {
"properties" : {
"firstName" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"isVIP" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
}
}
}
}
}

我们为索引 my_index 添加一个 Dynamic Templates,规则如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
PUT my_index
{
"mappings": {
"dynamic_templates": [
{
"strings_as_boolean": { // strings_as_boolean 模板名称
"match_mapping_type": "string", // 匹配的字段需要是字符串类型
"match":"is*", // 匹配的字段名称需要以 is 开头
"mapping": { // 匹配的字段会被映射成 boolean 类型
"type": "boolean"
}
}
},
{
"strings_as_keywords": {
"match_mapping_type": "string",
"mapping": {
"type": "keyword"
}
}
}
]
}
}

同理我们再添加一个文档试试,并查询其 mappings:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
PUT my_index/_doc/1
{
"firstName":"Ruan",
"isVIP":"true"
}
// mappings
{
"my_index" : {
"mappings" : {
"dynamic_templates" : [
{
"strings_as_boolean" : {
"match" : "is*",
"match_mapping_type" : "string",
"mapping" : {
"type" : "boolean"
}
}
},
{
"strings_as_keywords" : {
"match_mapping_type" : "string",
"mapping" : {
"type" : "keyword"
}
}
}
],
"properties" : {
"firstName" : {
"type" : "keyword" // firstName 是 keyword 类型
},
"isVIP" : {
"type" : "boolean" // isVIP 则是 boolean 类型
}
}
}
}
}

再举一个示例,如下我们创建一个名称为 dynamic_templates 的模板,其支持将 name 下面的字段和不包含 middle 的字段拷贝出来作为新的字段 full_name:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
PUT my_index
{
"mappings": {
"dynamic_templates": [
{
"full_name": {
"path_match": "name.*",
"path_unmatch": "*.middle",
"mapping": {
"type": "text",
"copy_to": "full_name"
}
}
}
]
}
}

我们添加对应的索引,可以发现可以通过 name 下面的 first 字段的值 John 检索到文档,而无法通过 middle 字段的值 Winston 检索得到:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
PUT my_index/_doc/1
{
"name": {
"first": "John",
"middle": "Winston",
"last": "Lennon"
}
}

// 如下检索得到文档
GET my_index/_search
{
"query": {
"match": {
"full_name": "John"
}
}
}

// 如下检索不到文档
GET my_index/_search
{
"query": {
"match": {
"full_name": "Winston"
}
}
}
------ 本文结束------