你是小阿巴,刚入职的后端程序员。

这天,产品经理给你安排任务:阿巴阿巴,咱们网站要加一个文章搜索功能。

你心想:简单,直接写一句 SQL 查询数据库就搞定了~

SELECT * FROM article WHERE title LIKE '%关键词%'

结果上线没几天,就收到了大量用户的投诉!

  • 怎么什么搜索结果都没有啊?

  • 搜索结果乱七八糟,我想找的那篇内容竟然排在最后面?

  • 搜索一次竟然要等好几秒才出结果?什么破系统!

你汗流浃背了:明明 SQL 写对了啊,难道是 MySQL 数据库不行?

打开网易新闻 查看精彩图片

这时,号称 "后端之狗" 的鱼皮路过。他瞄了一眼你的代码,嘲笑道:肯定要用 Elasticsearch 来做搜索功能啊!

你一脸懵:Elasticsearch?那是啥?

 第一阶段:认识 Elasticsearch
打开网易新闻 查看精彩图片
第一阶段:认识 Elasticsearch

鱼皮Elasticsearch 简称 ES,是一个专门为搜索而生的分布式数据库,也叫 搜索引擎数据库

它能存储和管理大量文本数据,提供快速、准确、灵活的全文检索功能。你刚才用 LIKE 查询搞不定的那些问题,用 ES 都能轻松解决。

你挠了挠头:真有这么神?

鱼皮:当然。打个比方,MySQL 就像图书馆的书架,书按照分类整整齐齐地摆放着,你想找某本书得自己一排一排去翻;而 ES 就像图书馆的电子检索系统,你输入关键词,它立刻就能告诉你书在哪儿,还会把最相关内容的排在最前面。

打开网易新闻 查看精彩图片

像全文搜索、日志分析、数据统计这些需要搜索能力的场景,ES 都能轻松搞定。

打开网易新闻 查看精彩图片

你眼前一亮:听起来有点儿夯啊,那我赶紧装一个试试。

第二阶段:实战应用 安装 Elasticsearch

机智如你,直接打开 ES 官网 下载了安装包:

打开网易新闻 查看精彩图片

并且成功安装运行:

打开网易新闻 查看精彩图片

你:安装好之后,我怎么操作它呢?

鱼皮:ES 本身提供了 RESTful API,默认在 9200 端口提供服务,你可以用 curl 命令或者 Postman 等接口测试工具直接发 HTTP 请求来操作它。

打开网易新闻 查看精彩图片

不过对新手来说,更推荐先安装一个官方的可视化工具 Kibana

有了它,你可以直观地查看分析数据、对数据进行操作。

打开网易新闻 查看精彩图片

只需要到官网下载安装包并运行,启动之后访问本机的 5601 端口,就能打开 Kibana 的管理界面了。在开发工具控制台里,你可以直接输入查询语句,能够立刻看到结果,非常方便。

 基本操作
打开网易新闻 查看精彩图片
基本操作

下面我来带你实操一波 ES 的基本操作。

1)首先是 创建索引。ES 的 索引(Index) 相当于 MySQL 里的表,是存放数据的容器。

打开网易新闻 查看精彩图片

创建索引的时候,还要定义 Mapping(映射),类似 MySQL 的表结构,用来规定每个字段的类型、是否需要分词、使用什么分词器等等。

打开网易新闻 查看精彩图片

在 Kibana 开发工具中输入这段代码:

PUT /article
{
"mappings": {
"properties": {
"title": { "type": "text", "analyzer": "standard" },
"content": { "type": "text" },
"tags": { "type": "keyword" },
"viewCount": { "type": "long" },
"isPublished": { "type": "boolean" },
"createTime": { "type": "date" }
}
}
}

这段代码创建了一个叫 article 的索引。其中 text 类型表示需要分词的文本字段,适合做全文检索;keyword 类型不会分词,适合存标签、状态这种需要精确匹配的内容。其他的类型就比较好理解了,long 存数字,boolean 存 true 或者 false,date 存日期。设计索引的时候要根据业务需求合理选择字段类型。

2)然后是 插入文档文档(Document) 相当于 MySQL 里的一行数据。ES 的文档是用 JSON 格式存储的,不需要像 MySQL 那样提前定义好所有字段,而是随时可以加新字段,非常灵活。

POST /article/_doc/1
{
"title": "鱼皮的 Elasticsearch 入门教程",
"content": "鱼皮带你学习 ES",
"cover": "封面图地址",
"tags": ["ES", "搜索"],
"viewCount": 1000,
"isPublished": true,
"createTime": "2025-01-30"
}
打开网易新闻 查看精彩图片

3)有了数据之后,就可以体验 ES 最核心的能力 搜索文档。比如在 article 索引中搜索标题包含 "鱼皮教程" 的文章:

GET /article/_search
{
"query": {
"match": { "title": "鱼皮教程" }
}
}

你执行完这条查询,惊喜地发现:搜 "鱼皮教程" 居然能匹配到 "鱼皮的 ES 入门教程" 这篇文章!

打开网易新闻 查看精彩图片

鱼皮点点头:虽然标题里并没有 "鱼皮教程" 这 4 个连着的字,但因为 ES 会自动分词,把 "鱼皮" 和 "教程" 拆开分别匹配,所以就搜到了。

打开网易新闻 查看精彩图片

你感叹道:哇,这才是搜索该有的样子啊!

查询语法 DSL

鱼皮:没错,ES 的搜索能力非常灵活强大。刚才你写的那些操作语句,其实用的就是 ES 的 DSL(Domain Specific Language 领域特定语言)。就像学数据库要学 SQL 一样,学 ES 就得学 DSL。不管是创建索引、插入文档,还是搜索查询,都是用这套 JSON 格式的语法来描述的。

打开网易新闻 查看精彩图片

其中最常用的就是查询语法,常见的查询类型有这么几种:

  • match 是全文检索,会对搜索词分词之后再匹配

  • term 是精确匹配,不分词,适合查 id、状态这种

  • bool 可以组合多个条件,用 must (必须满足)、 should (最好满足)、 must_not (必须不满足)来灵活控制

  • range 用来做范围查询,比如查某个时间段内的数据。

打开网易新闻 查看精彩图片

你不需要背这些语法,用到的时候问 AI 或者查文档就行,多写几次就熟了。

用代码操作 ES

你皱了皱眉:感觉写这些 JSON 格式的 DSL 还是有点麻烦啊,我用 Java 代码操作 ES 的时候,总不会也要手动拼这堆 JSON 吧?

鱼皮:当然不用!ES 官方提供了各种语言的客户端。比如你用 Java 语言,对应的是 Java API Client,支持链式调用和类型安全。

打开网易新闻 查看精彩图片

对于 Spring 项目来说,更推荐用 Spring Data Elasticsearch,它可以让你像用 MyBatis-Plus 操作 MySQL 一样操作 ES。只需要定义一个实体类,加上 @Document 注解指定要操作的索引,再写个 Repository 接口继承依赖包内置的 ES 操作接口。

@Document(indexName = "article")
public class Article {
@Id
private Long id;
private String title;
private String content;
}


public interface ArticleRepository extends ElasticsearchRepository {
// 根据标题搜索
List
findByTitle(String title);
}

框架会根据方法名自动生成查询逻辑,基本的增删改查方法就自动实现了。

// 使用示例
// 插入文档
articleRepository.save(article);
// 根据 id 查询
articleRepository.findById(1L);
// 根据标题搜索
articleRepository.findByTitle("鱼皮");
// 删除文档
articleRepository.deleteById(1L);

你感叹道:这才是人写的代码啊!优雅,真是优雅~ 我这就给 Java 代码整上 ES!

鱼皮:要注意,ES 版本更新很快,你用的客户端版本要跟安装的 ES 服务保持一致,不然会出各种奇奇怪怪的 Bug。

 第三阶段:实用特性
打开网易新闻 查看精彩图片
第三阶段:实用特性

学会了基本操作之后,你兴冲冲地把 MySQL 数据库里的文章数据全部导入到了 ES,然后把网站的搜索功能改成从 ES 查询。上线后效果立竿见影,搜索又快又准,用户好评如潮。

打开网易新闻 查看精彩图片

你非常开心:阿巴,俺可真厉害!

打开网易新闻 查看精彩图片

鱼皮:不错不错,你已经掌握了 ES 的基本操作,算是学会 80% 了。不过 ES 还有很多值得学习的实用特性,进一步优化你的搜索功能。

倒排索引

鱼皮:先来考考你,你知道为什么 ES 能搜得又快又准么?

你挠挠头:阿巴阿巴……

鱼皮笑道:关键在于它使用了 倒排索引 来存储数据,这是 ES 最核心的特性。

举个例子,假设咱们要存 3 篇博客文档,用 MySQL 数据库的话,存储结构是这样的:

文档 id

文档内容

1

感谢关注鱼皮

2

鱼皮是一名程序员

3

感谢关注编程导航

这种结构下,如果用户搜 “鱼皮程序员”,MySQL 会傻乎乎地把它当成一整个词去匹配,结果可能啥也搜不到。

打开网易新闻 查看精彩图片

而 ES 的做法不一样。它会先把文档内容按照单词进行切分,这个过程叫 分词。然后再构建 单词到文档 id 的映射关系,也就是 倒排索引

打开网易新闻 查看精彩图片

有了上述的倒排索引,当用户搜索 “鱼皮程序员” 时,搜索引擎数据库会先对搜索词进行分词,得到 “鱼皮” 和 “程序员”,然后根据这两个词汇就能找到文档 id 1、2 了。不用再一行一行遍历表内所有的数据,实现了更灵活、快速的 模糊搜索

打开网易新闻 查看精彩图片

你两眼放光:原来如此,牛啊牛啊!

但是 ES 怎么知道一句话该拆成哪些词呢?

分词器

鱼皮:好问题,这就要靠 分词器 了,它负责把一段文本拆成一个个词。

ES 内置了标准分词器,它基于 Unicode 文本分割算法设计,会按空格和标点符号等来切分文本。但这个规则只适合英文,对中文基本是一个字一个字地拆,效果很差。

打开网易新闻 查看精彩图片

所以如果你要做中文搜索,必须安装 IK 分词器。它是专门为中文设计的,能够智能识别中文词汇的边界,把句子正确地拆分成有意义的词语。

IK 提供了两种分词模式:

  • ik_smart 是智能分词,尽量把词分得少一点,比如 "好学生" 就只会拆成 "好学生" 一个词

  • ik_max_word 是最大化分词,能拆的都拆,"好学生" 会被拆成 "好学生"、"好学"、"学生" 三个词。

打开网易新闻 查看精彩图片

一般建议索引的时候用 ik_max_word 尽可能多分词,搜索的时候用 ik_smart 提高精确度。

此外,IK 还支持自定义词典。比如你想让 “程序员鱼皮” 作为一个完整的词不被拆开,加到词典里就行了。

 高亮显示
打开网易新闻 查看精彩图片
高亮显示

你好奇道:既然 ES 能分词,那能不能在搜索结果中把命中的关键词标红啊?

打开网易新闻 查看精彩图片

鱼皮:当然可以,ES 支持 高亮显示 功能。只需要在查询里加个 highlight 参数,指定要高亮的字段就行:

GET /article/_search
{
"query": {
"match": { "title": "鱼皮教程" }
},
"highlight": {
"fields": { "title": {} }
}
}

返回结果里,命中的关键词会自动被 标签包起来,前端拿到之后加个颜色样式就搞定了。

打开网易新闻 查看精彩图片

你两眼放光:这也太方便了吧!

打开网易新闻 查看精彩图片

不过还有个问题,现在虽然能够搜索到内容了,但怎么把最相关的结果排到前面呢?

相关性评分

鱼皮:好问题。ES 会给每个搜索结果计算一个分数,放到 _score 字段中,分数高的排在前面。

打开网易新闻 查看精彩图片

你好奇道:这个分数是怎么算的呢?

鱼皮:ES 默认用的是 BM25 算法,主要考虑三个因素:

  • 词频 ,关键词在文档里出现的次数越多,分数越高。这很好理解,一篇文章里反复提到 "鱼皮",说明它很可能就是在讲鱼皮相关的内容。

  • 文档长度 ,同样出现一次关键词,在短文档里占的比例更大,所以短文档的分数会更高一点。

  • 稀有度 ,如果一个词在所有文档里都很常见,比如 "的"、"是",那它对搜索结果的区分度就不大。反过来,如果一个词很少见,只在少数文档里出现,那命中这个词的文档就更有价值,分数也更高。

打开网易新闻 查看精彩图片
聚合分析

鱼皮:除了搜索,ES 还有个很实用的功能叫 聚合分析,有点像 MySQL 的 GROUP BY 分组查询。

比如你想统计每个标签下有多少篇文章,写个聚合查询就行:

GET /article/_search
{
"size": 0,
"aggs": {
"tag_count": {
"terms": { "field": "tags" }
}
}
}
打开网易新闻 查看精彩图片

除了分组统计数量,ES 的聚合还能做求和、求平均值、找最大最小值、甚至多层嵌套聚合,能够满足开发各类数据报表的需求。

 第四阶段:生产环境实践
打开网易新闻 查看精彩图片
第四阶段:生产环境实践

用了一段时间 ES 后,你开始有点儿飘了。

没事儿就对着新来的实习生阿坤吹牛皮:ES 我闭着眼睛都能写!什么分词、高亮、聚合,我都玩得贼溜儿~

打开网易新闻 查看精彩图片

结果没多久,老板黑着脸找到你:有用户投诉,说明明改了自己文章的标题,但是搜索出来还是旧的,怎么回事?

打开网易新闻 查看精彩图片

你排查后发现:原来是 ES 里的数据和 MySQL 数据库里的不一样!当初俺只是把数据一次性导入 ES,后来文章在数据库里更新了,但 ES 里还是旧数据。

你有些头大:唉,ES 和 MySQL 是两套独立的系统,数据不会自动同步啊,咋办啊?

打开网易新闻 查看精彩图片

这时,旁边的阿坤突然鸡叫起来:我来!

数据同步方案

阿坤一边打篮球一边说:MySQL 和 ES 的数据同步,一般有这么几种方案。

1)定时任务

每隔几分钟扫一遍数据库,把最近更新的数据同步到 ES。优点是实现简单,缺点是有一定延迟。适合数据更新不频繁、对实时性要求不高的场景。

打开网易新闻 查看精彩图片

2)双写

每次把数据写入 MySQL 的时候顺便也写一份到 ES。优点是能做到实时同步,缺点是会影响写入性能,而且如果 ES 写失败了还得处理数据不一致的问题。适合数据写入量不大的场景。

打开网易新闻 查看精彩图片

3)用 Logstash

它是 ES 官方提供的数据收集工具,可以配置从 MySQL 定时拉取数据同步到 ES。优点是不用写代码,全靠配置驱动,缺点是需要额外部署组件,灵活性也有限。

打开网易新闻 查看精彩图片

4)用 Canal 监听数据库

Canal 是阿里开源的一个工具,它会伪装成 MySQL 的从库,实时监听数据库的变更日志。数据库一有改动,Canal 立刻就能感知到,然后同步到 ES。优点是能做到实时同步,缺点是部署和运维相对麻烦一点。

打开网易新闻 查看精彩图片

像咱们这个文章系统,更新又不频繁,用户也能接受几分钟的延迟,用定时任务就完全够了。如果以后做电商那种对实时性要求高的系统,再考虑上 Canal。

集群部署

鱼皮走过来拍了拍阿坤的肩膀:不错不错,我再考考你们,如果 ES 服务器挂了怎么办?

你支支吾吾:重…… 重启?

打开网易新闻 查看精彩图片

鱼皮摇头:用户等得起吗?

阿坤:生产环境肯定不能只部署一台 ES 啊,得搭建 集群

ES 集群中有几种角色的节点。主节点 负责管理集群的状态,比如哪些节点在线、索引的元数据等等。数据节点 负责存储实际的数据,处理读写请求。一般生产环境至少部署 3 个节点,保证高可用。

打开网易新闻 查看精彩图片

鱼皮追问:那如果数据量特别大,一个节点存不下怎么办?

你眼前一亮,终于等到自己会的问题了,抢答道:删除数据!

阿坤用看流浪狗的眼神看了你一眼,回答道:这就要说到 分片 了。分片就是把一个索引的数据拆成多份,分别存到不同的节点上。这样单个节点存不下的海量数据,也能通过多节点分担。而且多个节点可以并行处理查询请求,性能也更好。

打开网易新闻 查看精彩图片

你有些不服气:那万一某个节点挂了,上面的数据不就丢了?

阿坤:所以还需要 副本。副本就是分片的备份。每个分片可以配置若干个副本,存在其他节点上。万一某个节点挂了,副本可以顶上,这样数据就不会丢失,服务也不会中断。

 其他生产实践
打开网易新闻 查看精彩图片
其他生产实践

鱼皮拍了拍阿坤的肩膀:小伙子年轻有为啊!

这些都是 ES 在生产环境必须考虑的问题,此外还要学习:

  • 深度分页问题:ES 默认只允许查询前 10000 条数据,再往后翻就会报错。这是为了保护集群性能。如果确实需要给用户深度翻页,推荐使用更高效的 search_after。如果需要导出全量数据,可以结合 Point-in-Time API 使用。

  • 性能调优技巧:合理设计 Mapping,该用 keyword 的别用 text;查询的时候多用 filter 少用 query,因为 filter 会缓存结果;还有控制返回字段的数量,别动不动就查全部字段。

  • ELK 日志方案:ES 最经典的应用场景之一就是做日志系统。ELK 是三个组件的缩写,E 是 Elasticsearch 负责存储和搜索日志,L 是 Logstash 负责收集和处理日志,K 是 Kibana 负责可视化展示。大厂排查线上问题,基本都靠这一套。

打开网易新闻 查看精彩图片

你羞愧地抬不起头:我以为自己已经掌握了 ES,原来只是学了个皮毛……

鱼皮:小阿巴,你还要好好跟阿坤学习啊。

 第五阶段:深入原理
打开网易新闻 查看精彩图片
第五阶段:深入原理

被连环拷问后,你主动找到阿坤:坤哥,我想深入学习 ES 的底层原理,你是怎么学的?

阿坤有些惊讶:咦?你不背八股文的么?去 面试刷题网站 - 面试鸭 刷刷题就好了呀!

打开网易新闻 查看精彩图片

你震惊了:现在的实习生,竟然恐怖如斯!

鱼皮笑了笑:阿坤你别逗他了。其实可以带着问题去学习,比如 ES 为什么这么快

你抢答道:因为倒排索引!

鱼皮:没错,但这只是一方面。ES 底层是基于 Lucene 搜索引擎库的,它的倒排索引结构经过了高度优化。另外 ES 会把常用的数据缓存在内存里,查询时优先从内存读取,速度自然快。再加上 ES 是分布式的,可以把数据分片存储到多个节点,并行处理查询请求,几方面加起来,性能就上去了。

打开网易新闻 查看精彩图片

再比如数据是怎么写入的、查询请求是怎么执行的?

从这些问题出发,去阅读相关的文章,或者像阿坤说的刷一刷 ES 高频面试题,就能快速学会很多核心知识点。

打开网易新闻 查看精彩图片

如果想系统学习,推荐看 ES 官方文档,因为 ES 的更新太快了,很多书籍可能已经跟不上节奏了。

 结尾
打开网易新闻 查看精彩图片
结尾

若干年后,你已经成为了公司的 ES 搜索专家。不仅能熟练使用 ES 解决各种搜索问题,搭个集群架构也是手拿把掐的。

你也像鱼皮当时一样,耐心地给新人分享学习 ES 的经验,让他们谨记一句话:ES 是实战型技术,一定要多动手实践!

打开网易新闻 查看精彩图片

再次遇到鱼皮是在一条昏暗的小巷,此时的他年过 35,灰头土脸。你什么都没说,只是给他点了个赞,投了 2 个币。

打开网易新闻 查看精彩图片

不打扰,是你的温柔~

一些对大家有用的资源:
100+ 编程学习路线 / 实战项目 / 求职指导
100+ 简历模板
300+ 企业面试题库 mianshiya.com
500+ AI 资源大全
1 对 1 模拟面试
动画学算法教程