ES 支持哪些数据类型,和 MySQL 之间的映射关系是怎么样的?
结论先行:ES 的字段类型分五族——字符串(text/keyword)、数值(long/integer/short/byte/double/float/half_float/scaled_float)、日期(date/date_nanos)、布尔与二进制、以及空间/对象/嵌套等特殊类型。与 MySQL 的映射不是一一对应:
varchar要按“是否分词”拆成 text 或 keyword,decimal只能用 scaled_float 或字符串近似,json对应 object/nested。
一、类型对照表
| MySQL | ES 类型 | 说明 |
|---|---|---|
varchar(全文检索) | text | 分词,不能直接聚合排序 |
varchar(精确值/枚举) | keyword | 不分词,可聚合、可排序 |
char | keyword | 定长精确匹配 |
tinyint | byte | 范围 -128~127 |
smallint | short | 范围 ±3.2 万 |
int | integer | 范围 ±21 亿 |
bigint | long | 64 位整数 |
float | float | 单精度,有精度损失 |
double | double | 双精度,仍非精确十进制 |
decimal | scaled_float / keyword | 无原生 decimal,见后文 |
datetime | date | 支持毫秒,date_nanos 支持纳秒 |
tinyint(1) / bit | boolean | true/false |
json | object / nested | 数组内对象需 nested 才能独立查询 |
blob | binary | 仅存储,不可检索 |
| 经纬度 | geo_point | 距离查询、地理聚合 |
二、text 与 keyword 的本质区别
| 维度 | text | keyword |
|---|---|---|
| 是否分词 | 是(standard/ik 等) | 否,整串入库 |
| 能否聚合 | 不能(除非 fielddata) | 能 |
| 能否排序 | 不能 | 能 |
| 典型查询 | match | term、terms |
| 典型字段 | 标题、正文 | 状态、城市、ID、标签 |
一个字段同时要全文检索与聚合时,用 fields 多类型:
PUT /article
{
"mappings": {
"properties": {
"title": {
"type": "text",
"analyzer": "ik_max_word",
"fields": {
"raw": { "type": "keyword", "ignore_above": 256 }
}
}
}
}
}
title 走分词检索,title.raw 走精确聚合。
三、decimal 的三种替代
PUT /order
{
"mappings": {
"properties": {
"amount_scaled": { "type": "scaled_float", "scaling_factor": 100 },
"amount_str": { "type": "keyword" },
"amount_double": { "type": "double" }
}
}
}
| 方案 | 精度 | 可聚合 | 适用 |
|---|---|---|---|
scaled_float | 定点,按因子缩放为 long | 是 | 金额、单价(两位小数) |
keyword 存字符串 | 完全精确 | 否(只能精确匹配) | 展示、对账 |
double | IEEE754 浮点误差 | 是 | 统计近似值,不能用于账务 |
四、动态映射的坑
PUT /log/_doc/1
{ "traceId": "123456789012345678", "latency": 12 }
traceId 若被动态映射成 long,前导零与超长 ID 会失真;latency 若先写入字符串,后续数值查询会失败。生产上应关闭动态映射或使用模板:
PUT /_index_template/log_tpl
{
"index_patterns": ["log-*"],
"template": {
"mappings": {
"dynamic": "strict",
"properties": {
"traceId": { "type": "keyword" },
"latency": { "type": "integer" }
}
}
}
}
常见追问
- 追问:nested 和 object 有什么区别?object 会把子字段打平,数组内对象的关联关系丢失;nested 为每个子对象建独立文档并维护关联,能用
nested查询,但写入与查询成本更高。 - 追问:为什么 text 不能聚合?聚合需要正排(doc → value),text 分词后没有稳定的“整串值”;开启
fielddata可以强行聚合,但会把数据加载进堆,极易 OOM。 - 追问:date 存时区吗?ES 内部统一存 UTC 毫秒时间戳,展示时按
format与时区转换,写入时要带时区或 ISO8601 偏移量。
小结
- 字符串按“是否分词”拆成 text 与 keyword,这是最常见的映射决策。
- 数值类型按取值范围选,越窄越省空间。
- decimal 用
scaled_float或字符串,double不能用于金额。 - 生产索引建议
dynamic: strict加模板,避免动态映射埋雷。