> 技术文档 > Elasticsearch 数据建模与映射(Mapping)详解_建模中的mapping

Elasticsearch 数据建模与映射(Mapping)详解_建模中的mapping

在 Elasticsearch 中,数据建模与映射(Mapping) 是决定搜索性能、存储效率和功能支持的核心环节。合理的映射设计能让搜索更精准、聚合更高效、存储更节省。

本文将全面详解 Elasticsearch 的 数据建模原则、字段类型、动态映射、自定义分析器、嵌套结构、最佳实践 等关键内容。


一、什么是映射(Mapping)?

映射(Mapping) 是 Elasticsearch 中对索引结构的定义,类似于关系型数据库中的 Schema。它描述了:

  • 每个字段的名称和数据类型;
  • 是否分词(用于全文搜索);
  • 是否索引(可被搜索);
  • 如何处理日期、数字、对象等复杂类型。

✅ 每个索引都有一个 mapping,定义其文档结构。


二、映射的核心组成

一个完整的 mapping 包含:

{ \"mappings\": { \"properties\": { ... }, // 字段定义 \"dynamic\": true,  // 动态映射策略 \"date_detection\": true, // 是否自动检测日期 \"numeric_detection\": false, // 是否自动检测数字 \"_source\": { \"enabled\": true }, // 是否存储原始 JSON \"routing\": { \"required\": false } }}

三、字段类型详解(Field Types)

Elasticsearch 支持丰富的字段类型,选择合适的类型至关重要。

1. 常用字段类型

类型 用途 是否分词 示例 text 全文搜索(会分词) ✅ \"这是一段中文文本\" keyword 精确匹配、聚合、排序 ❌ \"status:active\" date 日期类型 - \"2024-06-01T10:00:00Z\" long, integer, short, byte 整数 - 100, -5 double, float 浮点数 - 3.14 boolean 布尔值 - true, false ip IP 地址 - \"192.168.1.1\" geo_point 地理位置坐标 - {\"lat\": 39.9, \"lon\": 116.4} object 嵌套 JSON 对象 - {\"name\": \"张三\", \"age\": 30} nested 独立索引的嵌套对象 - 数组中的对象列表 binary 二进制数据(Base64) - 图片缩略图 flattened 将复杂 JSON 作为 keyword 处理 ❌ 动态标签

2. text vs keyword:最重要的选择

场景 推荐类型 搜索商品标题 text 聚合品牌、分类 keyword 排序价格、时间 keyword 或数值类型 精确匹配订单号 keyword

最佳实践:对同一字段使用 多字段(multi-fields)

\"title\": { \"type\": \"text\", \"analyzer\": \"ik_max_word\", \"fields\": { \"keyword\": { \"type\": \"keyword\" } }}
  • 搜索用 title
  • 聚合/排序用 title.keyword

四、动态映射(Dynamic Mapping)

1. 什么是动态映射?

当插入一个新字段时,Elasticsearch 自动推断其类型并添加到 mapping 中。

PUT /my-index/_doc/1{ \"user\": \"张三\", → 推断为 text + keyword \"age\": 30, → 推断为 long \"created\": \"2024-06-01\" → 推断为 date}

2. 动态策略(dynamic

设置 说明 true(默认) 自动添加新字段 false 忽略新字段,不报错 strict 拒绝未知字段,抛出异常

✅ 生产环境建议设为 strict,防止字段污染。

PUT /my-index{ \"mappings\": { \"dynamic\": \"strict\", \"properties\": { ... } }}

五、自定义分析器(Analyzer)

用于控制 text 字段的分词方式,直接影响搜索结果。

1. 分析器组成

  • Character Filters:预处理(如 HTML 标签过滤)
  • Tokenizer:分词器(如空格、中文分词)
  • Token Filters:后处理(小写、停用词)

2. 示例:中文分词配置

PUT /news{ \"settings\": { \"analysis\": { \"analyzer\": { \"my_ik_analyzer\": { \"type\": \"custom\", \"tokenizer\": \"ik_max_word\", \"filter\": [\"lowercase\"] } } } }, \"mappings\": { \"properties\": { \"content\": { \"type\": \"text\", \"analyzer\": \"my_ik_analyzer\" } } }}

3. 常见中文分词插件

  • ik:最常用,支持自定义词典
  • jieba:Python 社区流行
  • smartcn:官方提供,功能有限

六、复杂结构建模

1. object 类型(扁平化对象)

{ \"address\": { \"city\": \"北京\", \"district\": \"朝阳区\" }}

映射:

\"address\": { \"properties\": { \"city\": { \"type\": \"keyword\" }, \"district\": { \"type\": \"keyword\" } }}

⚠️ 内部字段是扁平化的:address.cityaddress.district 是独立字段。


2. nested 类型(独立索引的对象)

适用于数组中的对象,需保持内部关系。

示例:用户评论
{ \"comments\": [ { \"user\": \"A\", \"content\": \"好\", \"likes\": 10 }, { \"user\": \"B\", \"content\": \"差\", \"likes\": 1 } ]}

错误方式(object):

\"comments\": { \"properties\": { ... }}

→ 会匹配 \"user:A AND content:差\"(跨文档匹配)

正确方式(nested):

\"comments\": { \"type\": \"nested\", \"properties\": { \"user\": { \"type\": \"keyword\" }, \"content\": { \"type\": \"text\" }, \"likes\": { \"type\": \"integer\" } }}

查询:

\"query\": { \"nested\": { \"path\": \"comments\", \"query\": { \"bool\": { \"must\": [ { \"match\": { \"comments.user\": \"A\" } }, { \"match\": { \"comments.content\": \"好\" } } ] } } }}

3. join 类型(父子文档)

用于一对多关系(如文章与评论),但性能较低。

\"relation\": { \"type\": \"join\", \"relations\": { \"post\": \"comment\" }}

⚠️ 7.x 后推荐用 nested 或应用层关联。


七、高级映射设置

1. _source 控制

  • 是否存储原始 JSON,默认 true
  • 设为 false 可节省空间,但无法:
    • 获取原始文档
    • 使用 update API
    • 高亮、脚本字段
\"_source\": { \"enabled\": false }

2. doc_valuesfielddata

  • doc_values: true(默认):列式存储,用于排序、聚合(推荐开启)
  • fielddata:用于 text 字段聚合,消耗大,不推荐
\"tags\": { \"type\": \"text\", \"fielddata\": true // 仅在必须时启用}

3. index 设置

控制字段是否可被搜索:

\"internal_id\": { \"type\": \"keyword\", \"index\": false // 不参与搜索,仅存储}

八、数据建模最佳实践 ✅

场景 建议 文本搜索 使用 text + 中文分词器(如 ik) 聚合/排序 使用 keyword 或数值类型 多字段 使用 fields 定义 text + keyword 动态字段 生产环境设为 strict 嵌套对象 使用 nested 保持关系 日期 使用 date 类型,格式统一 大字段 index: false 节省空间 冗余设计 适当反规范化提升查询性能

九、反规范化 vs 正规范化

策略 说明 适用场景 反规范化(Denormalization) 将关联数据冗余存储 查询频繁、写少 正规范化(Normalization) 拆分为多个索引,通过 join 查询 数据一致性要求高

✅ Elasticsearch 推荐 适度反规范化,以提升查询性能。


十、总结:映射设计 checklist

项目 是否完成 使用 text 用于全文搜索 ✅ 使用 keyword 用于聚合排序 ✅ 中文字段配置 IK 分词器 ✅ 关键字段启用 doc_values ✅ 嵌套对象使用 nested ✅ 生产环境 dynamic: strict_source 根据需求启用 ✅ 避免 fielddata on text