在 Elasticsearch 8.13.4 的世界里,有一个让无数开发者头秃的“死结”:我想要像百度一样的全文搜索(分词),又想要像数据库一样的精确匹配(Keyword),这两者真的能共存吗?

如果你还在试图用一个字段走天下,或者在 text 类型上强行做聚合,那你正在给未来的系统埋雷。在 8.13.4 这个对 Mapping 规范极其严苛的版本中,答案是肯定的——但前提是你必须掌握核心武器:多字段(Multi-fields)策略

今天,我们就剥开理论的外衣,直接上手实战,教你如何用一套配置,让同一个字段既能“如水般流动”支持模糊搜索,又能“如磐石般坚定”支持精准过滤与聚合。

一、 核心心法:拒绝“既要又要”的单字段幻想

首先要打破一个幻想:textkeyword 是水火不容的两种索引逻辑。

  • Text:被分词器切碎,用于全文检索,支持高亮、相关性评分(_score),但绝对不能用于排序或聚合(会引发内存爆炸或报错)。
  • Keyword:原封不动,用于精确匹配(Term Query)、范围查询、聚合分析(Aggs)和排序。

成年人不做选择,我们全都要。 在 ES 8.13.4 中,利用 fields 关键字,我们可以为主字段穿上“分词的战衣”用于搜索,同时保留一个“原生的内核”用于精准打击。

黄金配置模板

这是生产环境的标准范式,请直接复制并背诵:

PUT /product_index
{
  "mappings": {
    "properties": {
      "product_name": {
        "type": "text",
        "analyzer": "ik_max_word", 
        "fields": {
          "raw": { 
            "type": "keyword",
            "ignore_above": 256
          }
        }
      }
    }
  }
}

解析这把“双刃剑”

  1. 主字段 (product_name):类型为 text,使用 ik_max_word 分词器。当你搜索“新鲜番茄”时,它会被切分为 ["新鲜", "番茄"],去倒排索引里进行模糊匹配。这是搜索的灵魂。
  2. 子字段 (product_name.raw):类型为 keyword,不分词,整体作为一个 Token 存入磁盘。当你需要精确匹配(Term Query)、按名称排序(Sort)或分类统计(Aggs)时,它就是定海神针。

二、 进阶:给分词器装上“同义词大脑”

在 8.13.4 版本,仅仅分词是不够的。用户搜“番茄”,文档里写的是“西红柿”或“圣女果”,如果搜不到,体验就是零分。我们需要结合 IK 分词 + 同义词过滤器

1. 部署同义词库
在 ES 配置目录 config/ 下创建 ik_synonyms 文件夹,新建 my_synonyms.txt

番茄, 西红柿, 圣女果
土豆, 马铃薯, 洋芋
计算机, 电脑, PC

2. 定义智能分析器
在索引 Settings 中,自定义一个结合了 IK 和同义词的分析器。这里有一个极致的优化技巧:索引用细粒度(ik_max_word),搜索用粗粒度(ik_smart,兼顾召回率和精度。

PUT /advanced_product_index
{
  "settings": {
    "analysis": {
      "filter": {
        "my_synonym_filter": {
          "type": "synonym",
          "synonyms_path": "ik_synonyms/my_synonyms.txt"
        }
      },
      "analyzer": {
        "ik_index_analyzer": {
          "tokenizer": "ik_max_word",
          "filter": ["lowercase", "my_synonym_filter"]
        },
        "ik_search_analyzer": {
          "tokenizer": "ik_smart",
          "filter": ["lowercase", "my_synonym_filter"]
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "title": {
        "type": "text",
        "analyzer": "ik_index_analyzer",
        "search_analyzer": "ik_search_analyzer",
        "fields": {
          "keyword": {
            "type": "keyword"
          }
        }
      }
    }
  }
}

三、 实战:Bool Query 的“左右互搏”

有了上面的 Mapping,你就可以在查询时上演“精准制导”的战术了。

场景:搜索“土豆”,但只想要状态为“上架”且名称精确包含“马铃薯”的商品。

GET /product_index/_search
{
  "query": {
    "bool": {
      "must": [
        { "match": { "product_name": "土豆" }} 
      ],
      "filter": [
        { "term": { "product_name.raw": "马铃薯" }}, 
        { "term": { "status": "published" }}
      ]
    }
  }
}

战术解析

  • must (分词侧):使用主字段 product_name,IK 分词器将“土豆”匹配文档,即使文档里写的是“马铃薯”,同义词过滤器也会将其扩展命中。这里计算相关性评分。
  • filter (精准侧):使用子字段 product_name.raw,不分词,直接全量匹配“马铃薯”这个 Token。关键点filter 不计算评分,且会被 ES 缓存,速度比 must 快几个数量级!

四、 避坑指南:8.13.4 的“红线”

  1. 严禁对 Text 字段做聚合:如果你对 product_name(text 类型)直接做 terms 聚合,ES 会报错或返回不准确的结果,因为它在内存里对碎片化的词条进行聚合,这是性能杀手。务必使用 .keyword 后缀。
  2. Mapping 即终局:在 8.13.4 中,字段类型一旦写入几乎不可修改。改类型意味着新建索引 -> Reindex -> 切换别名。宁可花一小时设计 Mapping,不要花一周迁移数据。
  3. 动态同义词的革命:别再死守着修改 txt 文件重启集群的笨办法了。8.13.4 支持 Synonyms API,可以通过 RESTful 接口动态更新同义词集,无需闭索引,新规则秒级生效。
  4. 范围查询的禁区:千万不要对 text 字段使用 range 查询(如价格区间、时间范围)。范围查询是结构化数据的专利,必须用 keyword、数值或日期类型。

结语

在 Elasticsearch 8.13.4 中,实现分词与精确搜索的共存,不是“我全都要”的贪婪,而是对倒排索引原理的深刻洞察。fields 多字段策略就是那把解开死结的钥匙。

别再犹豫了,立刻去检查你的 Mapping!给你的字段装上这对“双翼”:一个负责在文本的海洋里冲浪(Text),一个负责在数据的岩石上锚定(Keyword)。只有这样,你才能在毫秒之间,既捕捉到风中的呢喃,又扼住命运的咽喉。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐