news 2026/3/27 20:07:50

搜索慢了?SpringBoot+Elasticsearch让查询快100倍!

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
搜索慢了?SpringBoot+Elasticsearch让查询快100倍!

《搜索慢了?SpringBoot+Elasticsearch让查询快100倍!》

我是小坏,今天咱们聊搜索。用户搜个东西,转圈圈等半天,这体验可不行。数据库like查询是方便,但数据多了能把你卡死。今天教你用Elasticsearch(后面就叫ES),让搜索快到飞起。

零基础全栈开发Java微服务版本实战-后端-前端-运维-实战企业级三个实战项目
资源获取:关注公众号: 小坏说Java ,获取本文所有示例代码、配置模板及导出工具。

一、数据库搜索的痛

零基础全栈开发Java微服务版本实战-后端-前端-运维-实战企业级三个实战项目
资源获取:关注公众号: 小坏说Java ,获取本文所有示例代码、配置模板及导出工具。

场景:1000万商品,搜索"华为手机"

SELECT*FROMproductsWHEREnameLIKE'%华为%'ORdescriptionLIKE'%华为%';

问题

  • 全表扫描,不走索引
  • 返回慢,用户等3秒
  • 不能分词(“华为手机"搜不到"华为P40手机”)
  • 不能按相关度排序
  • 不支持拼音搜索

用ES能解决啥

  • 毫秒级返回
  • 自动分词
  • 支持拼音、同义词
  • 智能排序
  • 聚合统计

二、ES快速上手

零基础全栈开发Java微服务版本实战-后端-前端-运维-实战企业级三个实战项目
资源获取:关注公众号: 小坏说Java ,获取本文所有示例代码、配置模板及导出工具。

2.1 先明白几个词

  1. 索引:相当于数据库
  2. 文档:相当于一行数据
  3. 字段:相当于列
  4. 分词:把句子拆成词,比如"华为手机"拆成"华为"和"手机"

2.2 3步集成

第一步:加依赖

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-elasticsearch</artifactId></dependency>

第二步:写配置

spring:elasticsearch:uris:http://localhost:9200username:elasticpassword:123456

第三步:定义商品实体

@Document(indexName="product")@DatapublicclassProduct{@IdprivateLongid;@Field(type=FieldType.Text,analyzer="ik_max_word")privateStringname;// 商品名,用ik分词@Field(type=FieldType.Text,analyzer="ik_max_word")privateStringdescription;// 描述@Field(type=FieldType.Double)privateDoubleprice;@Field(type=FieldType.Keyword)privateStringcategory;// 分类,不分词@Field(type=FieldType.Integer)privateIntegersales;// 销量}

三、数据同步:4种方案选哪个?

零基础全栈开发Java微服务版本实战-后端-前端-运维-实战企业级三个实战项目
资源获取:关注公众号: 小坏说Java ,获取本文所有示例代码、配置模板及导出工具。

3.1 双写(简单直接)

@ServicepublicclassProductService{publicvoidaddProduct(Productproduct){// 1. 写数据库productRepository.save(product);// 2. 写ESelasticsearchRepository.save(product);}}

优点:实时性强
缺点:可能不一致,影响性能

3.2 定时同步(稳定可靠)

@ComponentpublicclassSyncTask{@Scheduled(fixedDelay=300000)// 5分钟一次publicvoidsyncProducts(){// 查最近5分钟修改的商品List<Product>products=productRepository.findRecentUpdated();elasticsearchRepository.saveAll(products);}}

优点:解耦,稳定
缺点:有延迟

3.3 消息队列(推荐)

商品更新发消息,消费者同步到ES。解耦,实时,但复杂。

3.4 监听binlog(高级玩法)

监听数据库变化自动同步。实时,对业务无侵入,但技术门槛高。

建议:中小项目用双写或定时同步,大项目用消息队列。

四、搜索实战

零基础全栈开发Java微服务版本实战-后端-前端-运维-实战企业级三个实战项目
资源获取:关注公众号: 小坏说Java ,获取本文所有示例代码、配置模板及导出工具。

4.1 基础搜索

@ServicepublicclassProductSearchService{publicPage<Product>search(Stringkeyword,intpage,intsize){// 构建查询NativeSearchQueryquery=newNativeSearchQueryBuilder().withQuery(QueryBuilders.multiMatchQuery(keyword,"name","description")).withPageable(PageRequest.of(page,size)).build();returnelasticsearchRestTemplate.search(query,Product.class);}}

4.2 多字段搜索+高亮

publicSearchResultsearchProducts(Stringkeyword,intpage,intsize){// 1. 多字段匹配MultiMatchQueryBuilderquery=QueryBuilders.multiMatchQuery(keyword).field("name",3.0f)// name权重3倍.field("description",1.0f);// 2. 高亮显示HighlightBuilderhighlightBuilder=newHighlightBuilder().field("name").preTags("<em>").postTags("</em>");NativeSearchQuerysearchQuery=newNativeSearchQueryBuilder().withQuery(query).withHighlightBuilder(highlightBuilder).withPageable(PageRequest.of(page,size)).build();// 执行搜索SearchHits<Product>searchHits=elasticsearchRestTemplate.search(searchQuery,Product.class);// 封装结果returnconvertToResult(searchHits);}

4.3 拼音搜索

步骤

  1. 安装拼音分词插件
  2. 字段用拼音分词器
  3. 搜索时同时匹配中文和拼音
// 搜索时同时查中文和拼音String[]fields={"name","name.pinyin","description","description.pinyin"};MultiMatchQueryBuilderquery=QueryBuilders.multiMatchQuery(keyword,fields);

4.4 同义词搜索

场景:搜"笔记本"也能找到"笔记本电脑"

// 同义词配置"filter":{"my_synonym":{"type":"synonym","synonyms":["笔记本,笔记本电脑","手机,移动电话"]}}

五、排序和筛选

零基础全栈开发Java微服务版本实战-后端-前端-运维-实战企业级三个实战项目
资源获取:关注公众号: 小坏说Java ,获取本文所有示例代码、配置模板及导出工具。

5.1 智能排序

// 按相关度、销量、价格综合排序NativeSearchQueryquery=newNativeSearchQueryBuilder().withSort(SortBuilders.scoreSort())// 相关度.withSort(SortBuilders.fieldSort("sales").order(SortOrder.DESC))// 销量.withSort(SortBuilders.fieldSort("price").order(SortOrder.ASC))// 价格.build();

5.2 条件筛选

// 价格区间RangeQueryBuilderpriceFilter=QueryBuilders.rangeQuery("price").gte(minPrice).lte(maxPrice);// 分类筛选TermQueryBuildercategoryFilter=QueryBuilders.termQuery("category",category);// 组合查询BoolQueryBuilderboolQuery=QueryBuilders.boolQuery().must(QueryBuilders.multiMatchQuery(keyword,"name","description")).filter(priceFilter).filter(categoryFilter);

六、聚合分析

场景:搜索结果的分类统计,用于生成筛选条件

publicMap<String,Long>getCategoryStats(Stringkeyword){// 按分类聚合TermsAggregationBuilderaggregation=AggregationBuilders.terms("by_category").field("category").size(10);NativeSearchQueryquery=newNativeSearchQueryBuilder().withQuery(QueryBuilders.multiMatchQuery(keyword,"name","description")).addAggregation(aggregation).build();SearchHits<Product>searchHits=elasticsearchRestTemplate.search(query,Product.class);// 解析聚合结果Termsterms=searchHits.getAggregations().get("by_category");Map<String,Long>result=newHashMap<>();for(Terms.Bucketbucket:terms.getBuckets()){result.put(bucket.getKeyAsString(),bucket.getDocCount());}returnresult;}

七、性能优化

零基础全栈开发Java微服务版本实战-后端-前端-运维-实战企业级三个实战项目
资源获取:关注公众号: 小坏说Java ,获取本文所有示例代码、配置模板及导出工具。

7.1 索引优化

@Document(indexName="product",createIndex=true,shards=3,// 分片数replicas=1)// 副本数publicclassProduct{// 字段优化@Field(type=FieldType.Keyword)privateStringsku;// 精确查找用keyword@Field(type=FieldType.Integer,index=false)privateIntegerstock;// 不索引库存,只用于显示}

7.2 查询优化

// 避免深度分页SearchAfterBuildersearchAfter=newSearchAfterBuilder();searchAfter.setSortValues(newObject[]{lastScore,lastId});// 使用filter替代query(不计算分数,可缓存)BoolQueryBuilderboolQuery=QueryBuilders.boolQuery().must(QueryBuilders.matchQuery("name",keyword)).filter(QueryBuilders.termQuery("status",1));// 状态过滤用filter

7.3 缓存优化

@ServicepublicclassProductSearchService{@Cacheable(value="search",key="#keyword + ':' + #page")publicPage<Product>search(Stringkeyword,intpage,intsize){// 热门搜索结果缓存returndoSearch(keyword,page,size);}}

八、监控告警

零基础全栈开发Java微服务版本实战-后端-前端-运维-实战企业级三个实战项目
资源获取:关注公众号: 小坏说Java ,获取本文所有示例代码、配置模板及导出工具。

8.1 健康检查

# application.ymlmanagement:endpoints:web:exposure:include:health,metricselasticsearch:health:enabled:true

8.2 关键指标监控

  • 查询响应时间
  • 索引速度
  • 节点负载
  • 磁盘使用率

8.3 告警规则

@ComponentpublicclassESMetricsMonitor{@Scheduled(fixedRate=60000)publicvoidcheckHealth(){// 检查集群状态ClusterHealthhealth=elasticsearchRestTemplate.cluster().health();if(health.getStatus()==ClusterHealthStatus.RED){// 发送告警alertService.send("ES集群异常,状态:"+health.getStatus());}// 检查查询延迟doubleavgQueryTime=getAverageQueryTime();if(avgQueryTime>1000){// 超过1秒alertService.send("ES查询延迟过高:"+avgQueryTime+"ms");}}}

九、实战:电商搜索完整流程

零基础全栈开发Java微服务版本实战-后端-前端-运维-实战企业级三个实战项目
资源获取:关注公众号: 小坏说Java ,获取本文所有示例代码、配置模板及导出工具。

9.1 搜索建议

publicList<String>getSuggestions(Stringprefix){CompletionSuggestionBuildersuggestion=SuggestBuilders.completionSuggestion("suggest").prefix(prefix).size(5);SuggestBuildersuggestBuilder=newSuggestBuilder().addSuggestion("product_suggest",suggestion);SearchRequestrequest=newSearchRequest("product").source(newSearchSourceBuilder().suggest(suggestBuilder));// 执行搜索建议SearchResponseresponse=elasticsearchRestTemplate.suggest(request,RequestOptions.DEFAULT);// 解析结果returnparseSuggestions(response);}

9.2 搜索结果封装

@DatapublicclassSearchResult{privateList<ProductVO>products;// 商品列表privateList<CategoryAgg>categories;// 分类统计privateList<BrandAgg>brands;// 品牌统计privatePriceRangepriceRange;// 价格区间privatelongtotal;// 总条数privateinttotalPage;// 总页数privateList<String>suggestions;// 搜索建议}// 搜索接口@GetMapping("/search")publicSearchResultsearch(@RequestParamStringkeyword,@RequestParam(defaultValue="0")intpage,@RequestParam(defaultValue="20")intsize,@RequestParam(required=false)Stringcategory,@RequestParam(required=false)DoubleminPrice,@RequestParam(required=false)DoublemaxPrice){returnproductSearchService.search(keyword,page,size,category,minPrice,maxPrice);}

十、今日要点

零基础全栈开发Java微服务版本实战-后端-前端-运维-实战企业级三个实战项目
资源获取:关注公众号: 小坏说Java ,获取本文所有示例代码、配置模板及导出工具。

  1. ES比数据库like快得多,支持分词、拼音、同义词
  2. 数据同步4种方案:双写简单,定时稳定,消息队列推荐
  3. 搜索要智能:多字段、高亮、拼音、同义词
  4. 排序和筛选是电商搜索的刚需
  5. 聚合分析用于生成筛选条件
  6. 性能优化:索引设计、查询优化、缓存
  7. 监控告警不能少,出问题早知道

十一、避坑指南

零基础全栈开发Java微服务版本实战-后端-前端-运维-实战企业级三个实战项目
资源获取:关注公众号: 小坏说Java ,获取本文所有示例代码、配置模板及导出工具。

坑1:分词器选错

// ❌ 错误:用默认分词器分中文@Field(type=FieldType.Text)// 默认分词器处理不好中文// ✅ 正确:用ik分词器@Field(type=FieldType.Text,analyzer="ik_max_word")

坑2:字段类型用错

// ❌ 错误:分类用Text,搜索时会分词@Field(type=FieldType.Text)privateStringcategory;// ✅ 正确:分类用Keyword,精确匹配@Field(type=FieldType.Keyword)privateStringcategory;

坑3:分页太深

// ❌ 错误:深度分页性能差from:10000,size:20// 性能差// ✅ 正确:用search_aftersearch_after:[lastScore,lastId]

十二、思考题

场景:你要做一个商品搜索,要求:

  1. 支持中文、拼音、同义词
  2. 结果按综合排序(相关度+销量+价格)
  3. 左侧有分类、品牌、价格筛选
  4. 搜索框有智能提示
  5. 热门搜索词推荐

问题

  1. 你会如何设计ES索引?
  2. 如何实现拼音和同义词搜索?
  3. 如何优化搜索性能?

评论区聊聊你的方案,明儿咱们讲MyBatis-Plus。


明天预告:《SpringBoot+MyBatis-Plus:开发效率提升10倍》

今日福利:关注后回复"ES搜索",获取电商搜索完整源码和ik分词器配置。


CSDN运营小贴士:

💡互动

  1. 你的项目搜索用的是什么方案?
  2. 遇到过哪些搜索性能问题?
  3. 留言提问,明天文章解答

👥进群
零基础全栈开发Java微服务版本实战-后端-前端-运维-实战企业级三个实战项目
资源获取:关注公众号: 小坏说Java ,获取本文所有示例代码、配置模板及导出工具。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/21 2:26:30

BertViz深度解析:揭开Transformer注意力机制的神秘面纱

BertViz深度解析&#xff1a;揭开Transformer注意力机制的神秘面纱 【免费下载链接】bertviz BertViz: Visualize Attention in NLP Models (BERT, GPT2, BART, etc.) 项目地址: https://gitcode.com/gh_mirrors/be/bertviz 在自然语言处理领域&#xff0c;Transformer…

作者头像 李华
网站建设 2026/3/21 14:20:39

3步搞定跨平台加密:crypto-js新手避坑指南

3步搞定跨平台加密&#xff1a;crypto-js新手避坑指南 【免费下载链接】crypto-js 项目地址: https://gitcode.com/gh_mirrors/cry/crypto-js 还在为加密代码在Node.js和浏览器中表现不一致而烦恼吗&#xff1f;crypto-js作为一款功能强大的JavaScript加密标准库&#…

作者头像 李华
网站建设 2026/3/26 21:35:15

7个关键OpenCode环境变量设置:新手快速上手指南

7个关键OpenCode环境变量设置&#xff1a;新手快速上手指南 【免费下载链接】opencode 一个专为终端打造的开源AI编程助手&#xff0c;模型灵活可选&#xff0c;可远程驱动。 项目地址: https://gitcode.com/GitHub_Trending/openc/opencode 还在为复杂的AI编程助手配置…

作者头像 李华
网站建设 2026/3/23 2:39:24

Material-UI实战指南:3个技巧让React开发效率翻倍

Material-UI实战指南&#xff1a;3个技巧让React开发效率翻倍 【免费下载链接】material-ui mui/material-ui: 是一个基于 React 的 UI 组件库&#xff0c;它没有使用数据库。适合用于 React 应用程序的开发&#xff0c;特别是对于需要使用 React 组件库的场景。特点是 React 组…

作者头像 李华