mobile wallpaper 1mobile wallpaper 2mobile wallpaper 3mobile wallpaper 4
1325 words
3 minutes
Elasticsearch 从 0 到 1(二):索引、Mapping 和分词器
2025-07-03

Elasticsearch 从 0 到 1(二):索引、Mapping 和分词器#

上一篇讲了 ES 是什么,以及为什么它适合搜索场景:

Elasticsearch 从 0 到 1(一):ES 是什么,为什么需要它

这一篇开始真正建索引。

ES 入门最容易踩的坑就是:数据先随便写进去,Mapping 让 ES 自动推断,等后面要搜索、排序、聚合时才发现字段类型不对。

所以建 ES 索引前,最好先想清楚:

哪些字段要全文搜索?
哪些字段要精确过滤?
哪些字段要排序?
哪些字段要聚合?
哪些字段只是展示?

创建一个简单索引#

最简单的创建索引:

PUT /products

这样 ES 会创建一个名为 products 的索引。

但真实项目不建议只这样创建,因为 Mapping 会交给 ES 动态推断。

更推荐显式指定字段:

PUT /products
{
"mappings": {
"properties": {
"productId": { "type": "long" },
"title": { "type": "text" },
"brand": { "type": "keyword" },
"category": { "type": "keyword" },
"price": { "type": "integer" },
"sales": { "type": "integer" },
"createdAt": { "type": "date" }
}
}
}

这就明确告诉 ES 每个字段该怎么处理。

Mapping 是什么#

Mapping 就是字段定义。

它决定:

  • 字段是什么类型;
  • 是否分词;
  • 是否能搜索;
  • 是否能排序;
  • 是否能聚合;
  • 用哪个分词器。

可以把 Mapping 类比成 MySQL 的表结构,但不要完全等同。

MySQL 建表关注的是数据约束和关系结构,ES Mapping 更关注搜索方式。

常见字段类型#

常用字段类型可以先记这些:

类型适合字段
text商品标题、文章内容、描述
keyword品牌、分类、状态、标签、编码
integer / long数量、ID、销量
double / scaled_float价格、评分
date创建时间、更新时间
boolean是否上架、是否删除
object普通对象
nested需要独立匹配的对象数组

初学时最重要的是区分 textkeyword

text 和 keyword 的区别#

text 会分词,适合全文搜索。

比如:

{
"title": "无线蓝牙耳机"
}

如果 titletext,它会被分词,用户搜索“蓝牙”“耳机”都有机会搜到。

keyword 不分词,适合精确匹配、排序、聚合。

比如:

{
"brand": "SoundGo"
}

品牌通常不需要拆成词,用户筛选品牌时要精确匹配。

一个常见设计:

{
"title": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
}
}

这样 title 本身可以全文搜索,title.keyword 可以用于精确匹配或排序。

什么是分词器#

分词器负责把文本拆成词。

比如:

无线蓝牙耳机

如果没有合适的中文分词器,拆分结果可能不符合搜索预期。

英文天然有空格,分词相对容易;中文没有天然空格,所以通常需要中文分词器。

常见中文分词方案包括:

  • IK 分词器;
  • smartcn;
  • 自定义词典;
  • 拼音分词器。

具体用哪个要看业务。商品搜索里经常需要自定义词典,比如品牌名、型号、行业词。

analyzer 和 search_analyzer#

字段可以指定两个分词器:

{
"title": {
"type": "text",
"analyzer": "ik_max_word",
"search_analyzer": "ik_smart"
}
}

analyzer 是写入文档时用的分词器。
search_analyzer 是用户搜索时用的分词器。

常见策略是:

  • 建索引时切得细一点,尽量多召回;
  • 搜索时切得稳一点,减少噪音。

这不是绝对规则,但商品搜索里很常见。

商品索引 Mapping 示例#

一个商品搜索索引可以这样设计:

PUT /products
{
"settings": {
"number_of_shards": 3,
"number_of_replicas": 1
},
"mappings": {
"properties": {
"productId": { "type": "long" },
"title": {
"type": "text",
"analyzer": "ik_max_word",
"search_analyzer": "ik_smart",
"fields": {
"keyword": { "type": "keyword", "ignore_above": 256 }
}
},
"brand": { "type": "keyword" },
"category": { "type": "keyword" },
"price": { "type": "integer" },
"sales": { "type": "integer" },
"stock": { "type": "integer" },
"status": { "type": "keyword" },
"createdAt": { "type": "date" }
}
}
}

说明:

  • titletext,支持全文搜索;
  • brandcategorystatuskeyword,支持精确筛选;
  • pricesales 用数值类型,支持范围查询和排序;
  • createdAtdate,支持时间范围查询;
  • title.keyword 可以用于精确匹配或排序。

写入一条商品文档#

PUT /products/_doc/1001
{
"productId": 1001,
"title": "无线蓝牙耳机",
"brand": "SoundGo",
"category": "数码耳机",
"price": 199,
"sales": 3000,
"stock": 80,
"status": "ON_SALE",
"createdAt": "2026-07-02T10:00:00"
}

这里 _doc/10011001 是文档 ID。

如果 MySQL 里商品 ID 是 1001,ES 里也用同一个 ID,会方便后续更新和删除。

Mapping 能不能改#

Mapping 不是完全不能改,但有些字段类型一旦确定就不能随便改。

比如一个字段已经是 keyword,后面想改成 text,通常不能直接改。

更稳的方式是:

  1. 创建新索引;
  2. 使用新 Mapping;
  3. 重新导入数据;
  4. 通过别名切换读写。

所以 ES 建索引前要先设计好字段,不要完全依赖动态 Mapping。

常见 Mapping 坑#

几个常见坑:

  • 商品标题建成 keyword,结果不能正常全文搜索;
  • 品牌建成 text,聚合结果被分词拆乱;
  • 价格建成字符串,范围查询和排序出问题;
  • 时间字段格式不统一,写入失败;
  • 让 ES 自动推断字段,后面发现类型不符合业务;
  • 对象数组用了 object,但实际需要 nested

前期 Mapping 设计多花一点时间,后面会少很多返工。

这一篇先记住什么#

  • Mapping 决定字段怎么存、怎么搜;
  • text 会分词,适合全文搜索;
  • keyword 不分词,适合过滤、排序、聚合;
  • 中文搜索通常需要合适的中文分词器;
  • 商品搜索要提前设计好字段类型;
  • Mapping 不要完全依赖自动推断;
  • 字段类型设计错了,后面通常要重建索引。

下一篇开始写查询 DSL:

Elasticsearch 从 0 到 1(三):DSL 查询入门

参考#

Share

If this article helped you, please share it with others!

Elasticsearch 从 0 到 1(二):索引、Mapping 和分词器
https://mizuki.mysqil.com/posts/elasticsearch-02-index-mapping-analyzer/
Author
梦幻晨风
Published at
2025-07-03
License
CC BY-NC-SA 4.0

Some information may be outdated

Table of Contents