Elasticsearch(ES)映射(Mapping)
作者介绍:简历上没有一个精通的运维工程师。请点击上方的蓝色《运维小路》关注我,下面的思维导图也是预计更新的内容和当前进度(不定时更新)。

中间件,我给它的定义就是为了实现某系业务功能依赖的软件,包括如下部分:
Web服务器
代理服务器
ZooKeeper
Kafka
RabbitMQ
Hadoop HDFS
Elasticsearch ES (本章节)
其实在我们前面的章节里面已经涉及到这个映射(Mapping)概念,今天我们来详细介绍下他。想象一下关系型数据库(如 MySQL,虽然我还未讲解他,下个章节就会涉及到数据库)。在创建表之前,你需要定义表结构:表名、列名、每列的数据类型(VARCHAR, INT, DATE等)、是否允许 NULL、默认值、索引等。Elasticsearch 的 Mapping 扮演着完全相同的角色!
我们前面在ES的读写操作里面已经向里面插入过一些数据,但是我们并没有单独定义这个Mapping,当 Elasticsearch 索引未手动创建 Mapping 时,首次写入数据会触发 自动生成 Mapping(Dynamic Mapping)
1.写入数据,不指定Mapping
这个等效于MySQL里面的创建表结构,并插入一条数据。
# 向不存在的索引写入数据(自动创建索引)
curl -X POST "http://192.168.31.173:9200/auto_index/_doc" -H 'Content-Type: application/json' -d'
{"name": "Alice","age": 30,"active": true,"join_date": "2023-05-15"
}
2.查看对应的Mapping
[root@localhost ~]# curl -X GET "http://192.168.31.172:9200/auto_index/_mapping?pretty"
{"auto_index" : {"mappings" : {"properties" : {"active" : {"type" : "boolean" #布尔型},"age" : {"type" : "long" #长整型},"join_date" : {"type" : "date" #日期格式 },"name" : {"type" : "text", #文本类型"fields" : {"keyword" : {"type" : "keyword", "ignore_above" : 256}}}}}}
}
3.写入数据前先创建Mapping
这个操作实际上就等效于MySQL里面的创建表结构。
[root@localhost ~]# curl -X PUT "http://192.168.31.173:9200/simple_index" -H 'Content-Type: application/json' -d'
{"mappings": {"properties": {"name": {"type": "text","fields": {"keyword": {"type": "keyword"}}},"age": {"type": "integer"},"created_at": {"type": "date","format": "yyyy-MM-dd"},"is_active": {"type": "boolean"},"ip_address": {"type": "keyword" }}}
}
'
{"acknowledged":true,"shards_acknowledged":true,"index":"simple_index"}[root@localhost ~]#
其实无论我们提前创建Mapping还是插入数据自动生成,都会涉及到一个问题,那就是我后面插入的数据如果和前面的标准Mapping下不一致会出现什么情况。这个情况如果是在M有SQL里面则会插入失败,因为MySQL会严格查询数据结构,如果对不上则会插入失败,而这个问题在ES里面则会分为下面几种情况。
1.减少字段
// Mapping 定义
"properties": {"name": {"type": "text"},"age": {"type": "integer"}
}// 插入数据(缺失 age 字段)
{"name": "张三"
}
结果:文档成功写入,age 字段值为 null。
2.增加字段
// 已有 Mapping
"properties": {"name": {"type": "text"}}// 插入数据(新增 email 字段)
{"name": "李四","email": "lisi@example.com" // 新字段
}
结果:文档成功写入,Mapping 自动扩展。
3.变更字段
// 已有 Mapping
"properties": {"age": {"type": "integer"}}// 尝试插入冲突数据
{"age": "twenty five" // 字符串 vs integer
}{"error": {"type": "mapper_parsing_exception","reason": "failed to parse field [age] of type [integer]"}
}
上面提到的3种情况,是基于ES默认的配置情况下,实际生产环境我们提前创建Mapping,并严格控制ES的行为,比如不允许增加字段。在ES里面Mapping一旦创建成功,不允许修改(自动扩展不算)。所以我们需要在创建Mapping的时候指定不允许增加字段。
curl -X PUT "http://192.168.31.172:9200/new_auto_index" -H 'Content-Type: application/json' -d'
{"mappings": {"dynamic": "strict", # 修改为严格模式"properties": {"active": {"type": "boolean"},"age": {"type": "integer" # 从 long 改为 integer},"join_date": {"type": "date","format": "yyyy-MM-dd" # 指定日期格式},"name": {"type": "keyword" # 从 text 改为 keyword}}}
}'
可以和前面未指定对比下参数有什么区别。
