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

一、为什么 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 倍——用户搜到的第一条更可能是标题就包含关键词的,符合直觉。
四、中文分词和性能的几个细节
- 分词器要装对。 ES 默认分词器对中文是逐字切,等于没分词。必须装
analysis-ik插件,否则"全文搜索"会被切成"全/文/搜/索"四个单字,召回乱套。 - 索引别无限膨胀。 历史数据可以建索引生命周期(ILM),热数据留 SSD、冷数据滚到对象存储,省成本。
- 深翻页用 search_after。 用
from + size翻到第 10000 条以后会被 ES 拒绝,深度分页改search_after。 - 写入用 bulk、读用 filter。 过滤条件尽量用
filter而非query,前者不计算相关度、能走缓存,列表筛选场景快很多。
总结一下
从 LIKE 升级到 Elasticsearch,本质上是把"字符串包含"换成"基于倒排索引的相关度检索"。建索引时想清哪些字段要分词(text)、哪些要精确(keyword),查询时善用 multi_match 加权和高亮,中文务必配好 IK 分词器——这四点做到,一个能打的站内搜索就成了。后面要做"搜索建议(completion suggester)"“拼音搜索”"聚合统计"也都是在这套索引之上加功能。别被"搜索引擎"四个字吓到,它的核心思想,就是这篇开头那张"词→文档"的倒排表。
- 点赞
- 收藏
- 关注作者
评论(0)