Elasticsearch 中 text 和 keyword 有什么区别?怎么选择?
简化版
text 会被分词,适合全文检索;keyword 不分词,按完整值建立索引,适合精确匹配、排序、聚合和去重。需要既能搜索又能聚合时,常用 multi-fields:主字段用 text,子字段 .keyword 用 keyword。
详细版
两者的核心区别是“是否分析文本”:
| 对比项 | text | keyword |
|---|---|---|
| 是否分词 | 会经过 analyzer | 不分词,保留整体值 |
| 典型用途 | 全文搜索、相关性匹配 | 精确过滤、排序、聚合 |
| 查询方式 | match、multi_match | term、terms、排序、terms 聚合 |
| 示例字段 | 标题、正文、评论内容 | 状态、标签、手机号、订单号、枚举值 |
例如:
{
"title": "Java Interview Guide",
"status": "published"
}
title 适合 text,因为用户可能搜 java guide;status 适合 keyword,因为它是一个整体枚举值,不希望被拆开。
常见设计:
"title": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword"
}
}
}
这样 title 用于全文检索,title.keyword 用于排序或聚合。
完整版教学
一、text 字段为什么要分词
全文检索面对的是自然语言。用户输入“Java 集合”,文章标题可能是“深入理解 Java Collection 框架”。如果字段不分词,只按完整字符串匹配,用户很难搜到想要的内容。
text 字段会经过 analyzer,例如:
"Java Interview Guide" -> java, interview, guide
搜索时用户输入也会被分析,然后用 token 去倒排索引里匹配。这样可以支持:
- 部分词命中;
- 大小写归一;
- 同义词扩展;
- 语言相关分词;
- 相关性评分。
二、keyword 字段为什么不分词
有些字段本身就是一个整体值,拆开反而会错。
例如:
order_no = "AIGC-20260719-0001"
status = "PAID"
phone = "13800000000"
这些字段的业务语义是“完整相等”。如果订单号被拆成多个 token,精确查询、聚合统计和排序都会变得不可靠。
所以 keyword 更适合:
term精确查询;terms多值过滤;terms aggregation分组统计;- 排序;
- 去重;
- 枚举字段过滤。
三、为什么 text 字段直接做聚合容易出问题
text 字段面向全文检索,默认通常不会直接用于排序和聚合。因为它保存的是分词后的 token,聚合出来的不是原始完整值,而是词项。
例如标题:
"Java 集合 面试题"
"Java 并发 面试题"
如果按分词后的 token 聚合,可能得到:
java: 2
面试题: 2
集合: 1
并发: 1
这和“按完整标题分组”完全不是一回事。需要按完整标题、品牌、状态等字段聚合时,应该使用 keyword。
四、multi-fields 是最常见答案
很多字符串字段既要全文检索,又要精确聚合。此时可以给同一个字段建立多种索引方式:
PUT /articles
{
"mappings": {
"properties": {
"title": {
"type": "text",
"analyzer": "standard",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
}
}
}
}
查询时:
{
"query": {
"match": {
"title": "Java 集合"
}
},
"sort": [
{ "title.keyword": "asc" }
]
}
title 负责搜索,title.keyword 负责排序。这个设计非常高频,面试里一定要讲出来。
五、选择字段类型的判断口诀
可以按业务问题倒推字段类型:
- 用户会不会输入几个词来搜索?会,用
text。 - 这个字段是不是枚举、编号、标签、状态?是,用
keyword。 - 要不要排序和聚合?通常需要
keyword、数值或日期字段。 - 同一个字符串既要搜索又要统计?用
text + keyword多字段。 - 中文字段要不要更好的分词效果?要考虑中文 analyzer,不只是选
text。
六、常见误区与追问
| 字段 | 更适合类型 | 典型查询 |
|---|---|---|
title | text + keyword 子字段 | match title,必要时 sort title.keyword |
status | keyword | term status |
order_no | keyword | 精确查询、去重 |
content | text | 全文检索、相关性评分 |
"Java Interview Guide"
text -> java, interview, guide
keyword -> "Java Interview Guide"
记忆钩子:用户按“词”搜内容,用
text;系统按“完整值”过滤、排序、聚合,用keyword。
如果 10 万篇文章标题都用 text 直接做 terms 聚合,得到的可能是 java: 30000、面试: 20000 这种 token 统计;如果业务想看“完整标题去重”或按标题排序,就必须走 title.keyword 这类完整值字段。
- 误区:字符串字段都用
text。 状态、编号、枚举、标签、租户 id 这类字段需要完整值语义,通常应使用keyword。 - 误区:
keyword不能搜索。 它可以精确查询、前缀查询、通配查询等,只是不做全文分词和相关性语义。 - 误区:
text字段不能保留完整值。 可以通过 multi-fields 同时建text和.keyword,分别服务搜索与聚合排序。 - 追问:为什么
term查text经常查不到?term不会分析查询词,而text索引里保存的是分析后的 token,大小写、分词结果可能对不上。 - 追问:
ignore_above有什么影响? 超过阈值的字符串不会写入该 keyword 子字段,排序、聚合或精确查询可能查不到这个超长值。 - 追问:中文标题只设
text就够吗? 不一定,全文检索要配置合适中文 analyzer;如果还要排序、聚合或精确匹配,还需要 keyword 子字段。
七、加强记忆
记住“text 看内容,keyword 看整体”。text 解决全文检索,keyword 解决精确过滤、排序和聚合;业务里最常见的是同一个字符串字段建 multi-fields,让搜索和统计各走各的索引方式。