分布式搜索引擎:Elasticsearch 从入门到实战
微服务架构中,数据存储的选择越来越多样化。MySQL 擅长事务和关系查询,Redis 擅长缓存,但在全文搜索这个场景下,它们都不太够用。
假如你的电商平台有上千万件商品,用户想搜“冬季保暖男鞋”。用 MySQL 的LIKE '%男鞋%'会怎么样?索引失效、全表扫描、响应时间几秒起步。更别说处理同义词、拼音搜索、相关性排序这些高级需求了。
这就是 Elasticsearch(简称 ES)要解决的典型问题。它是一个分布式搜索引擎,基于 Apache Lucene 构建,擅长海量数据的快速检索和分析。Kibana 是它的可视化仪表盘,可以查看数据、编写查询、监控集群状态。
Elasticsearch 的普及度和 SpringBoot 一样高,两者经常成对出现。这篇文章讲清楚 ES 的核心概念、典型应用场景、数据同步方案,以及 SpringBoot 如何与此集成。
一、核心概念:用“图书馆”来理解
ES 里有很多术语,但可以用图书馆来类比。
索引相当于数据库中的 Database。在图书馆里,它就是整个图书分类体系——小说区、科技区、历史区。
文档相当于数据库中的 Row。图书馆里的每一本书,都有书名、作者、出版日期、内容简介。
字段相当于数据库中的 Column。书的标题、作者、ISBN 号就是字段。
映射相当于数据库中的 Schema,定义了每个字段是什么类型。
倒排索引是搜索引擎的核心技术。传统数据库是按文档找词(这篇文档里有“冬天”这个词吗),倒排索引是按词找文档(“冬天”这个词出现在哪些文档里)。正因如此,ES 的搜索速度远超 MySQL 的模糊查询。
举个例子:有三篇文章,文章A有“冬天”,文章B有“冬天”和“保暖”,文章C有“运动”。搜索“保暖”时,ES 直接去倒排索引里查“保暖”这个词出现在哪里,瞬间定位到文章B。
集群是一组运行着 ES 的服务器,共同存储数据、处理请求,对外像一个整体。
节点是集群中的一个服务器。每个节点有自己的名字,可以是主节点、数据节点、协调节点。
二、分片与副本:分布式的基础
ES 能处理海量数据,靠的是分片机制。
主分片:把一个索引拆成多份,每一份就是一个主分片。创建索引时指定主分片数量,一旦确定就不能改。每个主分片可以分布在不同的节点上,查询时会并行搜索所有分片,速度比单分片快得多 -2。
一般来说,一个分片存储 10-50GB 是比较理想的规模。超过这个范围,分片太大查询会变慢;分片太多,每个分片都要消耗内存和文件句柄,管理开销也会增大 -2。
副本分片是主分片的完整拷贝,主要起两个作用:一是高可用,主分片所在的节点宕机了,副本可以顶上;二是提升查询性能,读请求可以负载均衡到主分片和副本分片上并行执行 -2。
副本数可以在线动态调整。需要注意的是,副本和主分片不能放在同一个节点上——如果它们在同一台机器上,机器坏了数据照样丢 -2。
举个例子:一个索引有 3 个主分片、每个主分片有 1 个副本,总共需要 6 个分片。如果集群有 3 个节点,ES 会自动把分片均匀分布,保证每个节点上既有主分片也有副本分片。
三、典型应用场景
3.1 全文搜索
这是 ES 最核心的用途。电商搜索、内容检索、日志搜索都属于这一类。用户输入关键词,ES 可以做到拼音搜索、拼写纠错、同义词匹配、按相关度排序 -8。
3.2 日志分析
配合 Logstash 和 Kibana(即 ELK 技术栈),ES 可以收集、存储、分析海量日志。几十个微服务的日志统一汇聚到一个地方,需要查问题时,一条 Trace ID 就能把所有相关日志串起来。
3.3 数据聚合分析
ES 支持类似 SQL 的GROUP BY和统计函数,可以按时间、按类别做聚合,生成报表和图表。
四、MySQL 与 ES 的数据同步方案
这是实践中非常常见的问题。业务数据在 MySQL 里,搜索需求在 ES 里,两个系统之间的数据怎么保持同步?
4.1 同步双写
业务代码在写 MySQL 的同时,也写 ES。
优点是实时性高,缺点是代码侵入性强,还要处理分布式事务——MySQL 写成功了但 ES 写失败了怎么办?整体上不太推荐。
4.2 异步 MQ
写 MySQL 成功后,发一条消息到 MQ,消费者拿到消息后再写 ES。
优点是解耦,消息重试机制也能保证最终一致性。缺点是要在业务代码里加发消息的逻辑,代码仍然有侵入。
4.3 Canal 方案(推荐)
Canal 是阿里巴巴开源的产品,它的作用是伪装成 MySQL 的从库,读取 MySQL 的 binlog 日志,再把数据变更解析出来 -7。
这个方案最大的好处是零侵入:业务代码只需要写 MySQL,完全不需要知道 ES 的存在。Canal 拿到 binlog 后,可以直连 ES 写入,也可以通过 MQ 中转再写入 -3。
缺点是需要多维护一个组件,Canal 本身需要高可用设计。目前 Canal 1.1.5 版本支持 ES 7.x,1.1.7 支持 8.x,版本要配套 -3。
五、中文分词与搜索优化
英文有天然的空格分词,中文没有,这是中文搜索最大的难点。
5.1 IK 分词器
IK 是目前最流行的中文分词插件。它有两种分词模式:ik_max_word尽可能多地把文本拆成更细的词,适合对召回率要求高的场景;ik_smart做最粗粒度的拆分,适合对性能要求高的场景 -8。
例如“冬天保暖男鞋”,ik_max_word会分成“冬天”、“保暖”、“男鞋”、“鞋”;ik_smart可能只分成“冬天”、“保暖”、“男鞋”。
5.2 拼音分词器
拼音分词器把汉字转成拼音,支持用户输入拼音缩写也能搜到结果。典型的例子是输入“bj”搜出“北京”的相关内容 -8。
5.3 自定义词典
某些专业术语或品牌名可能不在默认词典里,需要在分词时被识别为一个完整的词。IK 支持配置自定义词典,把特定词汇加进去即可。
六、SpringBoot 集成 ES
6.1 版本兼容性
SpringBoot 和 ES 的版本必须匹配。SpringBoot 2.x 系列对应 ES 7.x,ES 8.x 需要 SpringBoot 3.x 配合。用错版本会出现各种诡异的兼容问题,建议先查官方兼容性列表再动手 -1-5。
6.2 添加依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-elasticsearch</artifactId> </dependency>这个 Starter 和 JPA 的用法非常相似,都是继承一个 Repository 接口,写法几乎一样 -9。
6.3 配置连接
spring: elasticsearch: uris: http://localhost:9200 username: # 如果开启了安全认证 password:6.4 实体定义
@Document(indexName = "products") public class Product { @Id private String id; private String name; private String description; private Double price; }6.5 Repository 操作
继承ElasticsearchRepository,就获得了基础的 CRUD 能力。自定义查询只要遵循命名规范,比如findByNameContaining就能实现全文搜索 -9。
核心要点:如果服务注册中心用的是 Nacos,ES 的地址完全可以托管到 Nacos 配置中心,做到不同环境自动切换,无需硬编码。
七、总结
Elasticsearch 是分布式搜索引擎的事实标准。
它基于倒排索引,搜索速度远超 MySQL 模糊查询
分片机制让它可以横向扩展、处理海量数据
中文搜索需要配合 IK 分词器才能发挥威力
与 MySQL 的数据同步推荐使用 Canal 方案,业务代码零侵入
SpringBoot 通过 Spring Data Elasticsearch 集成,写法与 JPA 非常相似
一句话总结:ES 负责“找得快”,MySQL 负责“存得准”,各司其职。用好 ES 的关键,一是根据数据量合理规划分片,二是设计好数据同步链路保证最终一致性。
