开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 22 天,点击查看活动详情
大家好,我是半夏之沫 😁😁 一名金融科技领域的JAVA系统研发😊😊
我希望将自己工作和学习中的经验以最朴实,最严谨的方式分享给大家,共同进步👉💓👈
👉👉👉👉👉👉👉👉💓写作不易,期待大家的关注和点赞💓👈👈👈👈👈👈👈👈
👉👉👉👉👉👉👉👉💓关注微信公众号【技术探界】 💓👈👈👈👈👈👈👈👈
前言
在Elasticsearch中,存储是面向文档(document)的,而文档存储的容器就叫做索引(index),表示一类文档。
每个索引在创建时,可以通过传参指定索引的mapping,而mapping就会定义当前索引下的文档的字段名称以及字段类型。
本文讨论的动态Mapping,即Dynamic Mapping,就是在向Elasticsearch写入文档时,索引不存在的情况下,Elasticsearch自动帮助我们创建索引并识别文档字段类型生成mapping。
那么就有如下问题:
- 类型如何完成自动识别;
- 能否修改动态生成的mapping。
本文将对上述问题进行解答。
Elasticsearch版本:7.2.1
正文
一. 类型如何完成自动识别
假如testdynamic索引不存在,然后通过如下语句向Elasticsearch插入文档。
PUT /testdynamic/_doc/1
{
"name": "Dog Lee",
"status": false,
"birthday": "2022-10-01T12:00:00.000+0800"
}
此时会自动创建testdynamic索引,并生成testdynamic的mapping。那么通过如下语句查看一下动态生成的mapping。
GET /testdynamic/_mapping
结果如下
{
"testdynamic" : {
"mappings" : {
"properties" : {
"birthday" : {
"type" : "date"
},
"name" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"status" : {
"type" : "boolean"
}
}
}
}
}
可以看到,Json中的字符串name字段被识别为了text类型,字符串birthday字段被识别为了date类型,以及布尔status字段被识别为了boolean类型。
Elasticsearch完成类型的自动识别,可以参照下表。
| Json数据类型 | Elasticsearch数据类型 |
|---|---|
| 整数 | long |
| 浮点数 | float |
| 布尔值 | boolean |
| 数组 | 取决于第一个非空值的类型 |
| 对象 | object |
| 空 | 忽略该字段 |
下表单独对Elasticsearch识别字符串Json数据类型进行总结。
| 字符串情况 | Elasticsearch数据类型 |
|---|---|
| 字符串满足日期格式 | date |
| 字符串满足数字格式 | long或者float |
| 其它 | text,并添加keyword字段 |
二. 能否修改动态生成的mapping
修改动态生成的mapping,这里的修改,指的是新增字段到已经存在的mapping中(mapping中已经存在的字段不允许修改的),主要由mapping的dynamic属性决定。
1. 将mapping的dynamic设置为true
如果将mapping的dynamic设置为true,则写入的文档有新增字段时,mapping就会被更新。如下进行演示。
首先将dynamic设置为true,语句如下。
PUT /testdynamic/_mapping
{
"dynamic": "true"
}
然后添加有新增字段age的文档,语句如下。
PUT /testdynamic/_doc/2
{
"name": "Lincoln",
"status": true,
"birthday": "2022-10-01T12:00:00.000+0800",
"age": 35
}
此时再查看一下testdynamic的mapping,结果如下。
{
"testdynamic" : {
"mappings" : {
"dynamic" : "true",
"properties" : {
"age" : {
"type" : "long"
},
"birthday" : {
"type" : "date"
},
"name" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"status" : {
"type" : "boolean"
}
}
}
}
}
可见新增字段age添加到了mapping中,且字段类型为long。此时新增字段是可以作为搜索条件的。语句如下。
GET /testdynamic/_search
{
"query": {
"range": {
"age": {
"gte": 30
}
}
}
}
结果如下。
{
"took" : 43,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [
{
"_index" : "testdynamic",
"_type" : "_doc",
"_id" : "2",
"_score" : 1.0,
"_source" : {
"name" : "Lincoln",
"status" : true,
"birthday" : "2022-10-01T12:00:00.000+0800",
"age" : 35
}
}
]
}
}
2. 将mapping的dynamic设置为false
如果将mapping的dynamic设置为false,则写入的文档就算有新增字段,mapping也不会被更新。如下进行演示。
首先将dynamic设置为false,语句如下。
PUT /testdynamic/_mapping
{
"dynamic": "false"
}
然后添加有新增字段grades的文档,语句如下。
PUT /testdynamic/_doc/3
{
"name": "Lincoln",
"status": true,
"birthday": "2022-10-01T12:00:00.000+0800",
"age": 25,
"grades": 90
}
能够添加成功,但是查看mapping,发现并没有添加grades到mapping中,如下所示。
{
"testdynamic" : {
"mappings" : {
"dynamic" : "true",
"properties" : {
"age" : {
"type" : "long"
},
"birthday" : {
"type" : "date"
},
"name" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"status" : {
"type" : "boolean"
}
}
}
}
}
此时不能以grades字段作为搜索条件,示例语句如下所示。
GET /testdynamic/_search
{
"query": {
"range": {
"grades": {
"gte": 80
}
}
}
}
结果如下。
{
"took" : 0,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 0,
"relation" : "eq"
},
"max_score" : null,
"hits" : [ ]
}
}
3. 将mapping的dynamic设置为strict
如果将mapping的dynamic设置为strict,此时如果写入的文档有新增字段,则写入会失败。如下进行演示。
首先将mapping的dynamic设置为strict,语句如下。
PUT /testdynamic/_mapping
{
"dynamic": "strict"
}
然后添加有新增字段des的文档,语句如下。
PUT /testdynamic/_doc/4
{
"name": "Armstrong",
"status": false,
"birthday": "2022-10-01T18:00:00.000+0800",
"age": 15,
"grades": 50,
"des": "Good people"
}
此时会直接报错,报错如下。
{
"error": {
"root_cause": [
{
"type": "strict_dynamic_mapping_exception",
"reason": "mapping set to strict, dynamic introduction of [grades] within [_doc] is not allowed"
}
],
"type": "strict_dynamic_mapping_exception",
"reason": "mapping set to strict, dynamic introduction of [grades] within [_doc] is not allowed"
},
"status": 400
}
总结
Elasticsearch在进行非字符串的类型自动识别时,会基于如下规则。
| Json数据类型 | Elasticsearch数据类型 |
|---|---|
| 整数 | long |
| 浮点数 | float |
| 布尔值 | boolean |
| 数组 | 取决于第一个非空值的类型 |
| 对象 | object |
| 空 | 忽略该字段 |
进行字符串的类型自动识别时,会基于如下规则。
| 字符串情况 | Elasticsearch数据类型 |
|---|---|
| 字符串满足日期格式 | date |
| 字符串满足数字格式 | long或者float |
| 其它 | text,并添加keyword字段 |
能否修改动态生成的mapping,有如下三种情况。
- 将mapping的dynamic设置为true。插入文档有新增字段时,能插入成功,并且新增字段会添加到mapping中,新增字段能作为搜索条件;
- 将mapping的dynamic设置为false。插入文档有新增字段时,能插入成功,但新增字段不会添加到mapping中,新增字段也不能作为搜索条件;
- 将mapping的dynamic设置为strict。插入文档有新增字段时,插入会直接失败。
大家好,我是半夏之沫 😁😁 一名金融科技领域的JAVA系统研发😊😊
我希望将自己工作和学习中的经验以最朴实,最严谨的方式分享给大家,共同进步👉💓👈
👉👉👉👉👉👉👉👉💓写作不易,期待大家的关注和点赞💓👈👈👈👈👈👈👈👈
👉👉👉👉👉👉👉👉💓关注微信公众号【技术探界】 💓👈👈👈👈👈👈👈👈
开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 22 天,点击查看活动详情