在 Elasticsearch(ES)的 mapping 配置中,true
、false
、runtime
是三个容易混淆但至关重要的参数。它们分别控制着字段的动态映射行为、索引状态以及运行时计算逻辑,直接影响 ES 的性能、灵活性和数据规范性。本文将从概念、区别、适用场景和实践案例四个维度,带你彻底搞懂这三个参数。
一、核心概念:参数的本质作用
在 ES 中,这三个参数的作用域和目标不同:
-
true
/false
:主要用于控制 动态映射(dynamic) 或 字段是否被索引(index) ,决定字段能否被自动添加到 mapping 或参与搜索。 -
runtime
:是 ES 7.10+ 引入的 运行时字段 特性,允许在查询时动态生成字段,无需提前定义或索引。
下面我们逐个拆解。
二、动态映射(dynamic)中的 true /false/strict
dynamic
是 mapping 中的顶层配置,用于控制当文档包含 mapping 中未定义的新字段 时,ES 如何处理这些字段。它的可选值包括 true
、false
、strict
,三者的核心区别在于对新字段的 "容忍度"。
1. dynamic: true(默认值):自动新增字段
行为逻辑:
当文档中出现未定义的新字段时,ES 会自动为其创建映射(根据值推断类型),并将字段添加到 mapping 中。新字段可被搜索、聚合和排序。
适用场景:
- 快速原型开发(无需提前设计完整 mapping);
- 字段结构动态变化的场景(如日志数据,不同日志可能包含随机字段)。
示例:
假设我们创建一个 logs
索引,mapping 仅定义 message
字段,且 dynamic: true
:
json
PUT /logs
{
"mappings": {
"dynamic": true, // 默认值,可省略
"properties": {
"message": { "type": "text" }
}
}
}
写入一条包含新字段 level
和 timestamp
的文档:
json
POST /logs/_doc/1
{
"message": "system error",
"level": "error", // 新字段
"timestamp": "2024-07-01T12:00:00" // 新字段
}
此时查看 mapping,会发现 ES 已自动添加 level
(推断为 keyword
)和 timestamp
(推断为 date
):
json
GET /logs/_mapping
{
"logs": {
"mappings": {
"dynamic": "true",
"properties": {
"message": { "type": "text" },
"level": { "type": "keyword" }, // 自动新增
"timestamp": { "type": "date" } // 自动新增
}
}
}
}
优缺点:
- 优点:灵活性极高,无需提前定义字段,适合快速迭代。
- 缺点:字段可能失控(如恶意写入大量无效字段),导致 mapping 臃肿,拖慢搜索和索引性能。
2. dynamic: false:忽略新字段
行为逻辑:
文档中的新字段会被 保留在 _source
中(原始文档可查看),但不会被添加到 mapping,也不会被索引(无法搜索、聚合)。
适用场景:
- 希望保留原始数据(
_source
完整),但不希望新字段影响 mapping 结构; - 字段偶尔变化,但核心字段固定(如用户行为日志中的临时参数)。
示例:
基于上面的 logs
索引,修改 dynamic: false
:
json
PUT /logs
{
"mappings": {
"dynamic": false,
"properties": {
"message": { "type": "text" }
}
}
}
写入同样包含 level
和 timestamp
的文档后,查看 mapping 会发现新字段未被添加:
json
GET /logs/_mapping
{
"logs": {
"mappings": {
"dynamic": "false",
"properties": {
"message": { "type": "text" } // 仅原始字段
}
}
}
}
但 _source
中仍包含新字段(可查看但不可搜索):
json
GET /logs/_doc/1
{
"_source": {
"message": "system error",
"level": "error",
"timestamp": "2024-07-01T12:00:00"
}
}
优缺点:
- 优点:避免 mapping 膨胀,保护核心字段的索引效率。
- 缺点:新字段无法搜索,可能导致业务逻辑错误(如误写字段名却查不到数据)。
3. dynamic: strict:严格拒绝新字段
行为逻辑:
文档中若包含未定义的新字段,ES 会直接 拒绝索引请求 并抛出异常,强制要求所有字段必须提前在 mapping 中定义。
适用场景:
- 字段结构固定的核心业务数据(如订单、用户信息);
- 需严格控制数据规范性的场景(如金融、医疗数据)。
示例:
将 logs
索引的 dynamic
设为 strict
:
json
PUT /logs
{
"mappings": {
"dynamic": "strict",
"properties": {
"message": { "type": "text" }
}
}
}
再次写入含 level
的文档时,ES 会抛出异常:
json
{
"error": {
"root_cause": [
{
"type": "strict_dynamic_mapping_exception",
"reason": "mapping set to strict, dynamic introduction of [level] within [_doc] is not allowed"
}
]
},
"status": 400
}
此时必须先手动添加 level
字段到 mapping,才能成功写入:
json
PUT /logs/_mapping
{
"properties": {
"level": { "type": "keyword" }
}
}
优缺点:
- 优点:数据规范性极强,杜绝无效字段,保护集群性能。
- 缺点:灵活性低,新字段需手动更新 mapping,增加开发成本。
三、index: true /false:控制字段是否被索引
与 dynamic
不同,index
是 单个字段的配置,用于控制已定义的字段是否被索引(与新字段无关)。
1. index: true(默认值)
行为逻辑:
字段会被索引,可用于搜索、聚合、排序。ES 会为该字段创建倒排索引,占用磁盘空间。
适用场景:
所有需要参与查询或分析的字段(如 name
、price
、status
)。
示例:
json
PUT /users
{
"mappings": {
"properties": {
"username": {
"type": "text",
"index": true // 可搜索
}
}
}
}
2. index: false
行为逻辑:
字段 不被索引 ,仅保存在 _source
中(可查看原始值),但无法用于搜索、聚合或排序。
适用场景:
- 仅需展示但无需搜索的字段(如用户头像 URL、原始 JSON 字符串);
- 敏感字段(如身份证号,仅需存储无需检索)。
示例:
json
PUT /users
{
"mappings": {
"properties": {
"avatar_url": {
"type": "keyword",
"index": false // 不可搜索,仅存储
}
}
}
}
此时查询 avatar_url
会返回空结果:
json
GET /users/_search
{
"query": {
"match": { "avatar_url": "https://example.com/avatar.jpg" }
}
}
四、runtime 字段:动态计算的临时字段
runtime
字段是 ES 7.10+ 引入的特性,允许在查询时动态生成字段,无需提前定义或索引,字段值仅在查询时计算,不占用磁盘空间。
核心特点:
- 不写入 mapping,不占用索引空间;
- 计算逻辑可动态修改(无需重建索引);
- 支持通过脚本(Painless)基于已有字段生成新值。
适用场景:
- 临时分析(如动态转换时间格式);
- 低频使用的字段(无需长期索引);
- 字段逻辑频繁变化(避免重建索引)。
示例:动态生成日期格式化字段
假设文档中存储的是毫秒级时间戳 timestamp
,我们希望在查询时动态生成 date_str
字段(格式为 yyyy-MM-dd
),无需提前定义:
json
GET /logs/_search
{
"runtime_mappings": {
"date_str": { // 运行时字段名
"type": "keyword",
"script": {
"source": "emit(doc['timestamp'].value.toString('yyyy-MM-dd'))"
}
}
},
"query": {
"match_all": {}
},
"fields": ["date_str", "timestamp"] // 返回运行时字段
}
查询结果中会新增 date_str
字段:
json
{
"hits": {
"hits": [
{
"_source": { "timestamp": 1688208000000 },
"fields": {
"timestamp": [1688208000000],
"date_str": ["2024-07-01"] // 动态生成
}
}
]
}
}
优缺点:
- 优点:灵活度极高,不占用磁盘空间,适合动态分析。
- 缺点:每次查询都需计算,增加 CPU 开销,不适合高频查询字段。
五、参数对比与选择建议
参数 | 作用域 | 核心行为 | 适用场景 | 性能影响 |
---|---|---|---|---|
dynamic: true | 新字段动态映射 | 自动新增字段到 mapping 并索引 | 快速开发、日志等动态数据 | 可能导致 mapping 臃肿 |
dynamic: false | 新字段动态映射 | 忽略新字段,仅保存在 _source |
需保留原始数据但控制 mapping 结构 | 无额外开销 |
dynamic: strict | 新字段动态映射 | 拒绝含新字段的文档 | 核心业务数据、强规范场景 | 无额外开销 |
index: true | 单个字段 | 字段被索引,可搜索 | 需查询 / 分析的字段 | 占用磁盘空间 |
index: false | 单个字段 | 字段不被索引,仅存储 | 仅展示的字段 | 节省磁盘空间 |
runtime | 查询时动态生成字段 | 临时计算,不存储 | 动态分析、低频字段 | 增加查询时 CPU 开销 |
选择建议:
- 核心业务数据(如订单):用
dynamic: strict
+index: true
,保证规范和性能。 - 日志、埋点等动态数据:用
dynamic: false
,保留原始数据同时避免 mapping 膨胀。 - 仅展示的字段(如 URL):用
index: false
,节省空间。 - 临时分析或动态字段:用
runtime
字段,避免频繁修改 mapping。
六、总结
ES 中的 true
、false
、runtime
三个参数,分别从动态映射、索引状态和运行时计算三个维度,提供了对字段的精细化控制。理解它们的区别,不仅能避免 "字段无法搜索""mapping 臃肿" 等常见问题,还能根据业务场景平衡 ES 的灵活性和性能。