关键词检索不够用了?用 Elasticsearch 做全文搜索

举报
海是岛思念的泪 发表于 2026/09/30 09:51:10 2026/09/30
【摘要】 用 LIKE 做搜索,只能前缀匹配、没法打分、中文更是灾难。用 Elasticsearch 建倒排索引、接中文分词、按相关度返回结果,一篇把搜索从"能用"升级到"好用"。

很多系统的搜索功能,最初都是一句 WHERE title LIKE '%关键词%' 凑合的。数据量小、需求简单时没问题,一旦内容多起来就露怯:只能做子串匹配、大小写和分词一塌糊涂、中文更是基本搜不准,更别提"相关度排序"和"高亮"了。正经的全文搜索,得靠专门的搜索引擎。Elasticsearch(下文简称 ES)是目前最主流的开源选择,它核心是倒排索引——像书末的索引表一样,记录"哪个词出现在哪些文档"。这篇我就用一个文章搜索的例子,把建索引、灌数据、查询、中文分词讲一遍。

image.png

一、为什么 LIKE 顶不住

先看清 LIKE 的天花板,免得为了杀鸡去引 ES 这把刀时心里没数:

维度 LIKE ‘%词%’ Elasticsearch
匹配方式 子串包含 分词后匹配
相关度排序 无,只能按时间 有打分(TF-IDF/BM25)
中文分词 不支持 接 IK 等分词器
高亮 自己拼 内置 highlight
大数据量性能 全表扫描 倒排索引,快

判断标准很简单:只是管理后台里按 ID 或精确字段查,LIKE 够用;只要面向用户的"搜索框",就该上 ES。用户预期的是"搜’手机壳’能出来’适用于 iPhone 的保护壳’",LIKE 给不了这种语义宽松度。

二、把数据灌进索引

先在 ES 里建一个索引,定义字段类型。这里特意给中文内容配 IK 分词器:

PUT /articles
{
  "settings": {
    "analysis": {
      "analyzer": {
        "ik_pinyin": {
          "type": "custom",
          "tokenizer": "ik_max_word"
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "title":    { "type": "text", "analyzer": "ik_max_word" },
      "content":  { "type": "text", "analyzer": "ik_max_word" },
      "author":   { "type": "keyword" },
      "created":  { "type": "date" }
    }
  }
}

text 类型才会被分词、可被全文检索;keyword 是精确值(作者名、状态这类,用于精确过滤,不作全文匹配)。ik_max_word 是 IK 分词器的"最细粒度"模式,能把"中华人民共和国"拆成多个词,召回更全。

灌数据用 _bulk 批量接口,比一条条插快得多:

POST /articles/_bulk
{"index":{"_id":1}}
{"title":"如何使用 Elasticsearch 做搜索","content":"全文检索依赖倒排索引...","author":"阿云","created":"2026-09-01"}
{"index":{"_id":2}}
{"title":"MySQL 索引优化实战","content":"慢查询往往源于缺失的索引...","author":"小李","created":"2026-09-02"}

三、查询怎么写才像搜索引擎

最基础的 match 查询,会对查询词也做分词再匹配,并按相关度打分:

GET /articles/_search
{
  "query": {
    "match": {
      "content": "倒排索引 搜索"
    }
  },
  "highlight": {
    "fields": { "content": {} }
  },
  "size": 10
}

highlight 会让 ES 在返回里标出命中位置,前端用 <em> 一包就是搜索结果里常见的"关键词高亮"。如果想标题命中权重更高,用 multi_match 给字段加权:

GET /articles/_search
{
  "query": {
    "multi_match": {
      "query": "Elasticsearch",
      "fields": ["title^3", "content"]
    }
  }
}

title^3 表示标题字段权重是内容的 3 倍——用户搜到的第一条更可能是标题就包含关键词的,符合直觉。

四、中文分词和性能的几个细节

  1. 分词器要装对。 ES 默认分词器对中文是逐字切,等于没分词。必须装 analysis-ik 插件,否则"全文搜索"会被切成"全/文/搜/索"四个单字,召回乱套。
  2. 索引别无限膨胀。 历史数据可以建索引生命周期(ILM),热数据留 SSD、冷数据滚到对象存储,省成本。
  3. 深翻页用 search_after。 用 from + size 翻到第 10000 条以后会被 ES 拒绝,深度分页改 search_after。
  4. 写入用 bulk、读用 filter。 过滤条件尽量用 filter 而非 query,前者不计算相关度、能走缓存,列表筛选场景快很多。

总结一下

从 LIKE 升级到 Elasticsearch,本质上是把"字符串包含"换成"基于倒排索引的相关度检索"。建索引时想清哪些字段要分词(text)、哪些要精确(keyword),查询时善用 multi_match 加权和高亮,中文务必配好 IK 分词器——这四点做到,一个能打的站内搜索就成了。后面要做"搜索建议(completion suggester)"“拼音搜索”"聚合统计"也都是在这套索引之上加功能。别被"搜索引擎"四个字吓到,它的核心思想,就是这篇开头那张"词→文档"的倒排表。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。