0%

ElasticSearch-Dynamic Mapping 和常见字段类型

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

1. Mapping

Mapping 类似数据库中的 schema 的定义,作用如下:

  • 定义索引中的字段的名称
  • 定义字段的数据类型,例如字符串、数字、布尔…
  • 定义倒排索引相关的配置(采用的 Analyzer、是否被索引)

Mapping 会把 JSON 文档映射成 Lucene 所需要的扁平格式,Mapping 中的字段一旦设定后,禁止直接修改。因为 Lucene 实现的倒排索引生成后不允许直接修改,需要重新建立新的索引,做 Reindex 操作。

2. 字段的数据类型

  • 简单类型:
    • text / keyword(文本字段中还会额外生成 Keyword 类型的 keyword 字段)
    • date
    • long
    • float
    • boolean
    • Ipv4 & Ipv6
  • 复杂类型-对象和嵌套对象
    • 对象类型 / 嵌套类型
  • 特殊类型
    • geo_point & geo_shape / percolator

如下所示示例:

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
// 创建索引和文档
PUT mapping_test/_doc/1
{
"uid" : "123",
"isVip" : false,
"isAdmin": "true",
"age":19,
"heigh":180.65
}
// 查询索引 mapping
GET mapping_test/_mapping

// 响应及其各字段的 type 值
{
"mapping_test" : {
"mappings" : {
"properties" : {
"age" : {
"type" : "long"
},
"heigh" : {
"type" : "float"
},
"isAdmin" : { // 不会转为 boolean,因为存入是 text
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"isVip" : {
"type" : "boolean"
},
"uid" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
}
}
}
}
}

3. Dynamic Mapping

我们知道在写入文档的时候,如果索引不存在会自动创建索引。由于 Dynamic Mapping 的机制,使得我们无须手动定义 Mappings。ElasticSearch 会自动根据文档信息推算出字段的类型。

但是有时候会推算的不对,例如地理位置信息。当类型设置不对时,会导致一些功能无法正常运行,例如 Range 查询。类型的自动识别规则如下:

JSON 类型ElasticSearch 类型
字符串1. 匹配日期格式,设置成 date
2. 配置数字设置为 float 或者 long,该选项默认关闭
3. 设置为 text,并且增加 keyword 子字段
布尔值boolean
浮点数float
整数long
对象object
数组由第一个非空数值的类型所决定
空值忽略

这里特别说明下,ElasticSearch 中不提供专门的数组类型,但是任何字段都可以包含多个相同类型的数值。例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 此时检索出来的 interests 是 text
PUT users/_doc/1
{
"name":"onebird",
"interests":"reading"
}

// 此时检索出来的 interests 是数组
PUT users/_doc/1
{
"name":"twobirds",
"interests":["reading","music"]
}

// mapping 中定义的为 text, 由第一个非空数值的类型所决定
GET users/_mapping

4. 控制 Dynamic Mapping

Mapping 可以通过设置 dynamic 的值来控制 Dynamic Mapping 是否可索引等操作,例如下述即是对 mapping_test 修改 dynamic 值为 false:

1
2
3
4
PUT mapping_test/_mapping
{
"dynamic": false
}

dynamic 不同值的规则如下:

  • 当 dynamic 设置为 true 时,一旦有新增字段的文档写入,Mapping 也同时被更新
  • dynamic 设置为 false 时,Mapping 不会被更新,新增字段的数据无法被索引,但是信息会出现在 _source 中
  • dynamic 设置为 strict 时,文档写入失败

当然正如我们开头所说的,对于 mapping 中已有的字段,一旦有数据写入,就不再支持修改字段的类型定义,需要重新建立新的索引,做 Reindex 操作。

下面演示相关示例:

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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
//新增文档
PUT dynamic_mapping_test/_doc/1
{
"newField":"someValue"
}
// 该字段可以被搜索,数据也在_source中出现
POST dynamic_mapping_test/_search
{
"query":{
"match":{
"newField":"someValue"
}
}
}

// 修改为dynamic false
PUT dynamic_mapping_test/_mapping
{
"dynamic": false
}

// 新增 anotherField
PUT dynamic_mapping_test/_doc/10
{
"anotherField":"someValue"
}

// 该字段不可以被搜索,因为dynamic已经被设置为false
POST dynamic_mapping_test/_search
{
"query":{
"match":{
"anotherField":"someValue"
}
}
}

// 不过anotherField依然存在文档里面
get dynamic_mapping_test/_doc/10

// 查询结果
{
"_index" : "dynamic_mapping_test",
"_type" : "_doc",
"_id" : "10",
"_version" : 1,
"_seq_no" : 1,
"_primary_term" : 1,
"found" : true,
"_source" : {
"anotherField" : "someValue"
}
}

// 修改为strict
PUT dynamic_mapping_test/_mapping
{
"dynamic": "strict"
}

// 写入数据出错,HTTP Code 400
PUT dynamic_mapping_test/_doc/12
{
"lastField":"value"
}
------ 本文结束------