ES 中 mapping 的 true、false、runtime:区别与实践

在 Elasticsearch(ES)的 mapping 配置中,truefalseruntime 是三个容易混淆但至关重要的参数。它们分别控制着字段的动态映射行为、索引状态以及运行时计算逻辑,直接影响 ES 的性能、灵活性和数据规范性。本文将从概念、区别、适用场景和实践案例四个维度,带你彻底搞懂这三个参数。

一、核心概念:参数的本质作用

在 ES 中,这三个参数的作用域和目标不同:

  • true / false :主要用于控制 动态映射(dynamic)字段是否被索引(index) ,决定字段能否被自动添加到 mapping 或参与搜索。

  • runtime :是 ES 7.10+ 引入的 运行时字段 特性,允许在查询时动态生成字段,无需提前定义或索引。

下面我们逐个拆解。

二、动态映射(dynamic)中的 true /false/strict

dynamic 是 mapping 中的顶层配置,用于控制当文档包含 mapping 中未定义的新字段 时,ES 如何处理这些字段。它的可选值包括 truefalsestrict,三者的核心区别在于对新字段的 "容忍度"。

1. dynamic: true(默认值):自动新增字段

行为逻辑:

当文档中出现未定义的新字段时,ES 会自动为其创建映射(根据值推断类型),并将字段添加到 mapping 中。新字段可被搜索、聚合和排序。

适用场景:

  • 快速原型开发(无需提前设计完整 mapping);
  • 字段结构动态变化的场景(如日志数据,不同日志可能包含随机字段)。

示例:

假设我们创建一个 logs 索引,mapping 仅定义 message 字段,且 dynamic: true

json 复制代码
PUT /logs
{
  "mappings": {
    "dynamic": true,  // 默认值,可省略
    "properties": {
      "message": { "type": "text" }
    }
  }
}

写入一条包含新字段 leveltimestamp 的文档:

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" }
    }
  }
}

写入同样包含 leveltimestamp 的文档后,查看 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 会为该字段创建倒排索引,占用磁盘空间。

适用场景:

所有需要参与查询或分析的字段(如 namepricestatus)。

示例:

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 开销

选择建议:

  1. 核心业务数据(如订单):用 dynamic: strict + index: true,保证规范和性能。
  2. 日志、埋点等动态数据:用 dynamic: false,保留原始数据同时避免 mapping 膨胀。
  3. 仅展示的字段(如 URL):用 index: false,节省空间。
  4. 临时分析或动态字段:用 runtime 字段,避免频繁修改 mapping。

六、总结

ES 中的 truefalseruntime 三个参数,分别从动态映射、索引状态和运行时计算三个维度,提供了对字段的精细化控制。理解它们的区别,不仅能避免 "字段无法搜索""mapping 臃肿" 等常见问题,还能根据业务场景平衡 ES 的灵活性和性能。

相关推荐
MarkGosling1 小时前
【开源项目】网络诊断告别命令行!NetSonar:开源多协议网络诊断利器
运维·后端·自动化运维
Codebee1 小时前
OneCode3.0 VFS分布式文件管理API速查手册
后端·架构·开源
_新一1 小时前
Go 调度器(二):一个线程的执行流程
后端
estarlee2 小时前
腾讯云轻量服务器创建镜像免费API接口教程
后端
风流 少年2 小时前
Cursor创建Spring Boot项目
java·spring boot·后端
毕设源码_钟学姐3 小时前
计算机毕业设计springboot宿舍管理信息系统 基于Spring Boot的高校宿舍管理平台设计与实现 Spring Boot框架下的宿舍管理系统开发
spring boot·后端·课程设计
方圆想当图灵3 小时前
ScheduledFutureTask 踩坑实录
后端
全栈凯哥3 小时前
16.Spring Boot 国际化完全指南
java·spring boot·后端
M1A14 小时前
Java集合框架深度解析:LinkedList vs ArrayList 的对决
java·后端
31535669135 小时前
Springboot实现一个接口加密
后端