Elasticsearch中的静态 Mapping 和动态 Mapping 有什么区别?
在 Elasticsearch (ES) 中,Mapping (映射) 类似于关系型数据库(如 MySQL)中的 Schema(表结构定义)。它定义了索引中的文档包含哪些字段,以及这些字段的数据类型(如 text, keyword, integer, date 等)和索引方式。
Elasticsearch 支持两种 Mapping 方式:动态 Mapping (Dynamic Mapping) 和 静态 Mapping (Explicit/Static Mapping)。
以下是两者的详细区别和对比:
1. 动态 Mapping (Dynamic Mapping)
定义:
当你向一个不存在的索引写入文档,或者向已有索引写入包含新字段的文档时,Elasticsearch 会自动根据 JSON 数据的内容推断字段类型,并自动创建 Mapping。ES 号称 "Schemaless"(无模式)主要就是基于这个特性。
工作机制:
ES 依靠内置的规则来猜测数据类型:
- JSON
true/falseboolean - JSON 整数
long - JSON 浮点数
float - JSON 字符串
text(带keyword子字段) 或date(如果符合日期格式)
优点:
- 上手快: 不需要预先定义结构,直接写入数据即可,非常适合开发初期或原型验证。
- 灵活性高: 能够自动适应字段的变化(新增字段)。
缺点:
- 类型推断可能不准确: 例如,你希望存储为
integer的 ID 字段(如 "123")可能被推断为text,或者日期格式推断错误。 - 资源浪费: 默认字符串会被映射为
text和keyword双重字段,这会占用更多磁盘空间和内存。 - Mapping Explosion (映射爆炸): 如果数据中有大量不确定的动态字段,会导致 Mapping 过大,影响集群性能。
2. 静态 Mapping (Explicit Mapping / 显式映射)
定义:
开发者在创建索引时,手动定义好字段的名称、数据类型、分词器(Analyzer)等属性。这相当于在 SQL 中执行 CREATE TABLE 语句。
工作机制:
你需要通过 API 显式地告诉 ES:“title 字段是 text 类型,使用 ik_max_word 分词器;age 字段是 integer 类型”。
优点:
- 精准控制: 可以精确指定字段类型(如使用
byte代替long节省空间),指定分词器,配置null_value等。 - 性能优化: 避免了不必要的字段索引(例如只存不搜的字段设为
index: false),节省存储和 CPU。 - 数据质量保障: 防止脏数据污染。如果定义了
age是数字,写入 "abc" 会报错(取决于配置),从而保证数据类型一致性。
缺点:
- 前期工作量大: 需要预先了解数据结构并编写 Mapping JSON。
- 灵活性较差: 字段定义后,通常不能修改已有字段的类型(因为这会使已索引的数据失效),只能通过 Reindex(重建索引)来解决。
3. 核心区别对比表
| 特性 | 动态 Mapping (Dynamic) | 静态 Mapping (Explicit) |
|---|---|---|
| 创建方式 | 自动推断,随数据写入自动创建 | 手动通过 API 预先定义 |
| 灵活性 | 高,自动处理新字段 | 低,需严格遵守预定义结构 |
| 准确性 | 基于猜测,可能出错 | 100% 准确,由开发者掌控 |
| 存储空间 | 通常较大(默认冗余索引) | 较小(可优化) |
| 适用场景 | 开发测试、日志类数据、字段不确定的场景 | 生产环境、核心业务数据、搜索调优场景 |
| 维护成本 | 低(前期),高(后期可能需清理) | 高(前期),低(后期稳定) |
4. 进阶:如何结合使用?(最佳实践)
在生产环境中,通常不会非黑即白地只选一种,而是结合使用。
A. 控制动态行为 (dynamic 参数)
你可以在静态 Mapping 中设置 dynamic 参数来控制如何处理未定义的新字段:
dynamic: true(默认):允许自动新增字段(动态 Mapping 行为)。dynamic: false:新字段会被忽略(不被索引,无法搜索,但会出现在_source中)。dynamic: 'strict':遇到新字段直接报错,拒绝写入。这是最严格的模式,适合核心业务表。
B. 动态模板 (Dynamic Templates)
这是一种“半自动”的方式。你可以定义规则,告诉 ES:“如果遇到以 is_ 开头的字段,就自动映射为 boolean” 或者 “如果遇到字符串类型,统一映射为 keyword”。
示例:
PUT my_index
{
"mappings": {
"dynamic_templates": [
{
"strings_as_keywords": {
"match_mapping_type": "string",
"mapping": {
"type": "keyword"
}
}
}
],
"properties": {
"title": { "type": "text" }, // 静态定义
"age": { "type": "integer" } // 静态定义
}
}
}
总结
- 想省事、不确定数据结构 用 动态 Mapping。
- 要性能、要精准搜索、生产环境 必须用 静态 Mapping。
- 高手做法 静态 Mapping 定义核心字段 +
dynamic: strict防止脏数据 + Dynamic Templates 处理特定规则的动态字段。