文章目录
- 动态映射
- 动态映射的弊端
- 静态映射
- 实战:映射创建后还可以更新吗
动态映射
动态映射的核心是在自动检测字段类型后添加新字段
哪些字段类型支持动态检测呢?
答:boolean类型、float类型、long类型、Object类型、Array类型、date类型、字符串类型。除此之外的类型是不支持动态检测匹配的,会适配为text类型
动态映射的弊端
1)字段匹配不准确,如将date类型匹配为keyword类型。
###字段匹配不正确
DELETE my_index_0505
PUT my_index_0505/_doc/1
{
"create_date": "2020-12-26 12:00:00"
}
GET my_index_0505/_mapping
获取映射发现,create_date是text和keyword组合类型,不是我们期望的date类型。
那么如何解决呢?方案如下(需要提前设置匹配规则)。
####提前设置匹配规则
DELETE my_index_0505
PUT my_index_0505
{
"mappings": {
"dynamic_date_formats": ["yyyy-MM-dd HH:mm:ss"]
}
}
PUT my_index_0505/_doc/1
{
"create date": "2020-12-26 12:00:00"
}
GET my_index_0505/_mapping
2)字段匹配不精准,可能不是用户期望的。
举例:用户期望text类型支持ik中文分词,但默认的是standard标准分词器。对此当然也有解决方案,可借助动态模板实现。
3)占据多余的存储空间。
举例:string类型匹配为text和keyword两种类型,但实际用户极有可能只期望排序和聚合的keyword类型,或者只需要存储text类型,如网页正文内容只需要全文检索,不需要排序和聚合操作。
4)映射可能错误泛滥。
不小心写错查询语句,由于使用了PUT操作,导致映射变得非常混乱。
静态映射
我们在数据建模前,需要明确文档中各个字段的类型。如何严格禁止动态添加字段或者忽略动态添加字段呢?这些都是静态映射要解决的问题。
对于该场景,可以将dynamic参数设置为false(表示忽略新字段),或者将dynamic参数设置为strict(表示如果遇到未知字段,则引发异常)。
例如,在"dynamic":false
后,cont字段可以写入,但不能被检索。
###创建索引,指定dynamic为false
PUT my_index_0506
{
"mappings": {
"dynamic": false,
"properties": {
"user": {
"properties": {
"name": {
"type": "text"
},
"social_networks": {
"dynamic": true,
"properties": {
}
}
}
}
}
}
}
####数据可以写入成功
PUT my_index_0506/_doc/1
{
"cont": "Each document has metadata associated"
}
###检索不能找回数据,核心原因在于cont是未映射字段
POST my_index_0506/_search
{
"profile": true,
"query": {
"match": {
"cont": "document"
}
}
}
### 可以返回结果
GET my_index_0506/_doc/1
####mapping中并没有 cont
GET my_index_0506/_mapping
代码中"profile":true辅助我们看到底层的检索逻辑,而不能召回数据的核心原因在于cont是未映射的字段。
POST my_index_0506/_doc
{
"user.social_networks.test": "Each document has metadata associated"
}
GET my_index_0506/_doc/CsS4cY8BA63nf2PurWKA
POST my_index_0506/_search
{
"profile": true,
"query": {
"match": {
"user.social_networks.test": "document"
}
}
}
对于social_networks对象设置为"dynamic": true
,可以动态映射字段类型
GET my_index_0506/_mapping
如果"dynamic":"strict"
,那么写入映射中未定义的字段会怎么样呢?
###创建索引,指定dynamic为false
PUT my_index_0507
{
"mappings": {
"dynamic": "strict",
"properties": {
"user": {
"properties": {
"name": {
"type": "text"
},
"social_networks": {
"dynamic": true,
"properties": {
}
}
}
}
}
}
}
####数据写入失败
PUT my_index_0507/_doc/1
{
"cont": "Each document has metadata associated"
}
实战:映射创建后还可以更新吗
官方文档强调已经定义的字段在大多数情况下不能更新,除非通过reindex操作来更新映射。
但以下3种情况例外。
❑Object对象可以添加新的属性。
❑在已经存在的字段里面可以添加fields,以构成一个字段多种类型。
❑ignore_above是可以更新的。
###创建索引,验证映射更新
PUT my_index_0508
{
"mappings": {
"properties": {
"name": {
"properties": {
"first": {
"type": "text"
}
}
},
"user_id": {
"type": "keyword"
}
}
}
}
### 映射可以更新成功
PUT my_index_0508/_mapping
{
"mappings": {
"properties": {
"name": {
"properties": {
"first": {
"type": "text",
"fields": {
"field": {
"type": "keyword"
}
}
},
"last":{
"type" : "text"
}
}
},
"user_id": {
"type": "keyword"
}
}
}
}
在以上实战中,对应第一种情况,Object对象可以添加新的属性,添加了last字段。对应第二种情况,first添加了keyword类型,以组合构造fields。对应第三种情况,user_id添加了ignore_above。