基于本文回答

播面 播面

文图音视,全方位拆解八股文
0
评论

Elasticsearch 中Text 类型和 Keyword 类型有什么区别?

知识点图片

在 Elasticsearch 中,TextKeyword 是处理字符串(String)数据的两种主要类型。它们的核心区别在于是否进行分词(Analysis)以及底层存储结构的不同,这也决定了它们各自适用的场景。

以下是详细的对比分析:

1. 核心区别总结表

特性 Text 类型 Keyword 类型
分词 (Analysis) 会分词 (Analyzed)。会被解析器拆分成独立的词项 (tokens)。 不分词 (Not Analyzed)。作为一个整体存储。
主要用途 全文检索 (Full-text search)。如搜索文章内容、产品描述。 精确匹配、过滤、排序、聚合。如 ID、状态码、标签、邮箱。
查询方式 通常使用 match 查询。支持模糊匹配、相关性打分。 通常使用 term 查询。必须完全一致(包括大小写)。
排序与聚合 不支持 (默认禁用 Fielddata,因为消耗大量堆内存)。 支持 (使用 Doc Values,性能高)。
存储结构 倒排索引 (Inverted Index)。 倒排索引 + 列式存储 (Doc Values)。
大小写敏感 通常不敏感 (标准分析器会将词转为小写)。 敏感 (原样存储)。

2. 详细原理解析

Text 类型 (全文检索)

  • 处理过程:当数据存入 Text 字段时,ES 会使用分析器(Analyzer)对字符串进行处理。
    • 例如:输入 "Apple Store"
    • 标准分析器处理后:生成两个词项 ["apple", "store"](转小写、去标点、拆分)。
  • 搜索:当你搜索 "Apple" 时,ES 会去倒排索引中查找 apple,能找到文档。
  • 缺点:因为原文本被拆散了,所以无法直接用来做排序(Sorting)或聚合(Aggregation)。如果强行开启 fielddata 来支持排序,会占用极高的内存,容易导致 OOM(内存溢出)。

Keyword 类型 (结构化数据)

  • 处理过程:数据存入 Keyword 字段时,ES 不做任何修改,原样存储。
    • 例如:输入 "Apple Store"
    • 存储结果:"Apple Store" 这一整个字符串。
  • 搜索
    • 搜索 "Apple Store" -> 匹配
    • 搜索 "Apple" -> 不匹配
    • 搜索 "apple store" (小写) -> 不匹配 (除非原数据就是小写)。
  • 优势Keyword 类型默认开启 Doc Values(一种列式存储结构,存在磁盘上),这使得它在排序、聚合(如统计每个品牌的销量)和脚本计算时速度非常快且内存友好。

3. 代码示例

假设我们有一个博客文章的索引:

Mapping 定义:

json
PUT /blog_posts
{
  "mappings": {
    "properties": {
      "title": {
        "type": "text"          // 标题:用于全文搜索
      },
      "status": {
        "type": "keyword"       // 状态:用于精确过滤(如 "published", "draft")
      }
    }
  }
}

插入数据:

json
POST /blog_posts/_doc/1
{
  "title": "Elasticsearch is fast",
  "status": "PUBLISHED"
}

场景 A:搜索 Title (Text)

json
// 使用 match 查询,不区分大小写,分词匹配
GET /blog_posts/_search
{
  "query": {
    "match": {
      "title": "Elasticsearch" 
    }
  }
}
// 结果:命中文档。因为 "Elasticsearch" 被分词并匹配到了索引中的 "elasticsearch"。

场景 B:搜索 Status (Keyword)

json
// 错误示范:大小写不匹配
GET /blog_posts/_search
{
  "query": {
    "term": {
      "status": "published" 
    }
  }
}
// 结果:未命中。因为 Keyword 存储的是 "PUBLISHED",而你搜的是 "published"。

// 正确示范
GET /blog_posts/_search
{
  "query": {
    "term": {
      "status": "PUBLISHED"
    }
  }
}
// 结果:命中。

4. 最佳实践:多字段 (Multi-fields)

在实际开发中,我们经常遇到既需要全文检索,又需要排序/聚合的字段(例如:文章标题、人名)。

此时,可以使用 ES 的 Multi-fields 功能,将同一个字段映射为两种类型。

Mapping 定义:

json
PUT /products
{
  "mappings": {
    "properties": {
      "product_name": {
        "type": "text",            // 主字段:用于搜索
        "fields": {
          "raw": {                 // 子字段:命名为 raw (也可以叫 keyword)
            "type": "keyword"      // 类型为 keyword,用于排序和聚合
          }
        }
      }
    }
  }
}

如何使用:

  1. 搜索时:使用 product_name
    json
    "match": { "product_name": "iPhone" }
  2. 排序/聚合时:使用 product_name.raw
    json
    "sort": [
      { "product_name.raw": { "order": "asc" } }
    ]

总结

  • Text:也就是“文章”,用来内容的。
  • Keyword:也就是“标签/ID”,用来筛选、排序、统计的。
  • 两者都要:使用 fields 开启多字段映射。
00:00
00:00