← 返回题目列表

Elasticsearch 中 text 和 keyword 有什么区别?怎么选择?

高频 简单 第 2 / 30 题 更新于 2026/07/28
Elasticsearchtextkeyword字段类型

简化版

text 会被分词,适合全文检索;keyword 不分词,按完整值建立索引,适合精确匹配、排序、聚合和去重。需要既能搜索又能聚合时,常用 multi-fields:主字段用 text,子字段 .keywordkeyword

详细版

两者的核心区别是“是否分析文本”:

对比项textkeyword
是否分词会经过 analyzer不分词,保留整体值
典型用途全文搜索、相关性匹配精确过滤、排序、聚合
查询方式matchmulti_matchtermterms、排序、terms 聚合
示例字段标题、正文、评论内容状态、标签、手机号、订单号、枚举值

例如:

{
  "title": "Java Interview Guide",
  "status": "published"
}

title 适合 text,因为用户可能搜 java guidestatus 适合 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

六、常见误区与追问

字段更适合类型典型查询
titletext + keyword 子字段match title,必要时 sort title.keyword
statuskeywordterm status
order_nokeyword精确查询、去重
contenttext全文检索、相关性评分
"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,分别服务搜索与聚合排序。
  • 追问:为什么 termtext 经常查不到? term 不会分析查询词,而 text 索引里保存的是分析后的 token,大小写、分词结果可能对不上。
  • 追问:ignore_above 有什么影响? 超过阈值的字符串不会写入该 keyword 子字段,排序、聚合或精确查询可能查不到这个超长值。
  • 追问:中文标题只设 text 就够吗? 不一定,全文检索要配置合适中文 analyzer;如果还要排序、聚合或精确匹配,还需要 keyword 子字段。

七、加强记忆

记住“text 看内容,keyword 看整体”。text 解决全文检索,keyword 解决精确过滤、排序和聚合;业务里最常见的是同一个字符串字段建 multi-fields,让搜索和统计各走各的索引方式。