Elasticsearch 数据建模与映射(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
ipIP 地址-"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

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值