当前位置: 首页 > news >正文

谷粒商城实战笔记-179~183-商城业务-检索服务-SearchRequest和SearchResponse构建

文章目录

  • 一,179-商城业务-检索服务-SearchRequest构建-检索
    • 1,Controller接口
  • 二,180-商城业务-检索服务-SearchRequest构建-排序、分页、高亮&测试
  • 三,181-商城业务-检索服务-SearchRequest构建-聚合
  • 四,182-商城业务-检索服务-SearchResponse分析&封装
  • 五,接口代码
  • 六,183-商城业务-检索服务-验证结果封装正确性

这一节主要是将上一节的DSL语句转换为使用Elasticsearch的Java客户端构建查询。

当从首页跳转到搜索界面,后端会根据搜索条件封装请求,向ES发出检索请求,查询到数据后,封装为之前设计好的数据结构,然后交给Thyleaf编译整合到页面模板中。

一,179-商城业务-检索服务-SearchRequest构建-检索

1,Controller接口

	@GetMapping(value = "/list.html")public String listPage(SearchParam searchParam, Model model) {SearchResult search = mallSearchService.search(searchParam);model.addAttribute("result", search);return "list";}

把查询结果放入Model,是为了Thymeleaf将数据整合到页面模板中。

二,180-商城业务-检索服务-SearchRequest构建-排序、分页、高亮&测试

三,181-商城业务-检索服务-SearchRequest构建-聚合

四,182-商城业务-检索服务-SearchResponse分析&封装

这四节的代码量比较大,难度笔记高,要求对DSL和Elasticsearch的Client API比较熟悉。这部分内容可以借助AI生成,比如将DSL交给ChatGPT,让它生成Java代码,然后在自测的过程中微调。

五,接口代码


@Slf4j
@Service
public class MallSearchServiceImpl implements MallSearchService {@Autowiredprivate RestHighLevelClient esRestClient;@Overridepublic SearchResult search(SearchParam param) {//动态构建出查询需要的DSL语句SearchResult result = null;//1、准备检索请求SearchRequest searchRequest = buildSearchRequest(param);try {//2、执行检索请求SearchResponse response = esRestClient.search(searchRequest, GulimallElasticSearchConfig.COMMON_OPTIONS);//3、分析响应数据,封装成我们需要的格式result = buildSearchResult(response,param);} catch (IOException e) {e.printStackTrace();}return result;}/*** 构建结果数据* 模糊匹配,过滤(按照属性、分类、品牌,价格区间,库存),完成排序、分页、高亮,聚合分析功能* @param response* @return*/private SearchResult buildSearchResult(SearchResponse response,SearchParam param) {SearchResult result = new SearchResult();//1、返回的所有查询到的商品SearchHits hits = response.getHits();List<SkuEsModel> esModels = new ArrayList<>();//遍历所有商品信息if (hits.getHits() != null && hits.getHits().length > 0) {for (SearchHit hit : hits.getHits()) {String sourceAsString = hit.getSourceAsString();SkuEsModel esModel = JSON.parseObject(sourceAsString, SkuEsModel.class);//判断是否按关键字检索,若是就显示高亮,否则不显示if (!StringUtils.isEmpty(param.getKeyword())) {//拿到高亮信息显示标题HighlightField skuTitle = hit.getHighlightFields().get("skuTitle");String skuTitleValue = skuTitle.getFragments()[0].string();esModel.setSkuTitle(skuTitleValue);}esModels.add(esModel);}}result.setProduct(esModels);//2、当前商品涉及到的所有属性信息List<SearchResult.AttrVo> attrVos = new ArrayList<>();//获取属性信息的聚合ParsedNested attrsAgg = response.getAggregations().get("attr_agg");ParsedLongTerms attrIdAgg = attrsAgg.getAggregations().get("attr_id_agg");for (Terms.Bucket bucket : attrIdAgg.getBuckets()) {SearchResult.AttrVo attrVo = new SearchResult.AttrVo();//1、得到属性的idlong attrId = bucket.getKeyAsNumber().longValue();attrVo.setAttrId(attrId);//2、得到属性的名字ParsedStringTerms attrNameAgg = bucket.getAggregations().get("attr_name_agg");String attrName = attrNameAgg.getBuckets().get(0).getKeyAsString();attrVo.setAttrName(attrName);//3、得到属性的所有值ParsedStringTerms attrValueAgg = bucket.getAggregations().get("attr_value_agg");List<String> attrValues = attrValueAgg.getBuckets().stream().map(item -> item.getKeyAsString()).collect(Collectors.toList());attrVo.setAttrValue(attrValues);attrVos.add(attrVo);}result.setAttrs(attrVos);//3、当前商品涉及到的所有品牌信息List<SearchResult.BrandVo> brandVos = new ArrayList<>();//获取到品牌的聚合ParsedLongTerms brandAgg = response.getAggregations().get("brand_agg");for (Terms.Bucket bucket : brandAgg.getBuckets()) {SearchResult.BrandVo brandVo = new SearchResult.BrandVo();//1、得到品牌的idlong brandId = bucket.getKeyAsNumber().longValue();brandVo.setBrandId(brandId);//2、得到品牌的名字ParsedStringTerms brandNameAgg = bucket.getAggregations().get("brand_name_agg");String brandName = brandNameAgg.getBuckets().get(0).getKeyAsString();brandVo.setBrandName(brandName);//3、得到品牌的图片ParsedStringTerms brandImgAgg = bucket.getAggregations().get("brand_img_agg");String brandImg = brandImgAgg.getBuckets().get(0).getKeyAsString();brandVo.setBrandImg(brandImg);brandVos.add(brandVo);}result.setBrands(brandVos);//4、当前商品涉及到的所有分类信息//获取到分类的聚合List<SearchResult.CatalogVo> catalogVos = new ArrayList<>();ParsedLongTerms catalogAgg = response.getAggregations().get("catalog_agg");for (Terms.Bucket bucket : catalogAgg.getBuckets()) {SearchResult.CatalogVo catalogVo = new SearchResult.CatalogVo();//得到分类idString keyAsString = bucket.getKeyAsString();catalogVo.setCatalogId(Long.parseLong(keyAsString));//得到分类名ParsedStringTerms catalogNameAgg = bucket.getAggregations().get("catalog_name_agg");String catalogName = catalogNameAgg.getBuckets().get(0).getKeyAsString();catalogVo.setCatalogName(catalogName);catalogVos.add(catalogVo);}result.setCatalogs(catalogVos);//===============以上可以从聚合信息中获取====================////5、分页信息-页码result.setPageNum(param.getPageNum());//5、1分页信息、总记录数long total = hits.getTotalHits().value;result.setTotal(total);//5、2分页信息-总页码-计算int totalPages = (int)total % EsConstant.PRODUCT_PAGESIZE == 0 ?(int)total / EsConstant.PRODUCT_PAGESIZE : ((int)total / EsConstant.PRODUCT_PAGESIZE + 1);result.setTotalPages(totalPages);List<Integer> pageNavs = new ArrayList<>();for (int i = 1; i <= totalPages; i++) {pageNavs.add(i);}result.setPageNavs(pageNavs);return result;}/*** 准备检索请求* 模糊匹配,过滤(按照属性,分类,品牌,价格区间,库存),排序,分页,高亮,聚合分析* @return*/private SearchRequest buildSearchRequest(SearchParam param) {SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();/*** 模糊匹配,过滤(按照属性,分类,品牌,价格区间,库存)*///1. 构建bool-queryBoolQueryBuilder boolQueryBuilder=new BoolQueryBuilder();//1.1 bool-mustif(!StringUtils.isEmpty(param.getKeyword())){boolQueryBuilder.must(QueryBuilders.matchQuery("skuTitle",param.getKeyword()));}//1.2 bool-fiter//1.2.1 catelogIdif(null != param.getCatalog3Id()){boolQueryBuilder.filter(QueryBuilders.termQuery("catalogId",param.getCatalog3Id()));}//1.2.2 brandIdif(null != param.getBrandId() && param.getBrandId().size() >0){boolQueryBuilder.filter(QueryBuilders.termsQuery("brandId",param.getBrandId()));}//1.2.3 attrsif(param.getAttrs() != null && param.getAttrs().size() > 0){param.getAttrs().forEach(item -> {//attrs=1_5寸:8寸&2_16G:8GBoolQueryBuilder boolQuery = QueryBuilders.boolQuery();//attrs=1_5寸:8寸String[] s = item.split("_");String attrId=s[0];String[] attrValues = s[1].split(":");//这个属性检索用的值boolQuery.must(QueryBuilders.termQuery("attrs.attrId",attrId));boolQuery.must(QueryBuilders.termsQuery("attrs.attrValue",attrValues));NestedQueryBuilder nestedQueryBuilder = QueryBuilders.nestedQuery("attrs",boolQuery, ScoreMode.None);boolQueryBuilder.filter(nestedQueryBuilder);});}//1.2.4 hasStockif(null != param.getHasStock()){boolQueryBuilder.filter(QueryBuilders.termQuery("hasStock",param.getHasStock() == 1));}//1.2.5 skuPriceif(!StringUtils.isEmpty(param.getSkuPrice())){//skuPrice形式为:1_500或_500或500_RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("skuPrice");String[] price = param.getSkuPrice().split("_");if(price.length==2){rangeQueryBuilder.gte(price[0]).lte(price[1]);}else if(price.length == 1){if(param.getSkuPrice().startsWith("_")){rangeQueryBuilder.lte(price[1]);}if(param.getSkuPrice().endsWith("_")){rangeQueryBuilder.gte(price[0]);}}boolQueryBuilder.filter(rangeQueryBuilder);}//封装所有的查询条件searchSourceBuilder.query(boolQueryBuilder);/*** 排序,分页,高亮*///排序//形式为sort=hotScore_asc/descif(!StringUtils.isEmpty(param.getSort())){String sort = param.getSort();String[] sortFileds = sort.split("_");SortOrder sortOrder="asc".equalsIgnoreCase(sortFileds[1])?SortOrder.ASC:SortOrder.DESC;searchSourceBuilder.sort(sortFileds[0],sortOrder);}//分页searchSourceBuilder.from((param.getPageNum()-1)* EsConstant.PRODUCT_PAGESIZE);searchSourceBuilder.size(EsConstant.PRODUCT_PAGESIZE);//高亮if(!StringUtils.isEmpty(param.getKeyword())){HighlightBuilder highlightBuilder = new HighlightBuilder();highlightBuilder.field("skuTitle");highlightBuilder.preTags("<b style='color:red'>");highlightBuilder.postTags("</b>");searchSourceBuilder.highlighter(highlightBuilder);}/*** 聚合分析*///1. 按照品牌进行聚合TermsAggregationBuilder brandAgg = AggregationBuilders.terms("brand_agg");brandAgg.field("brandId").size(50);//1.1 品牌的子聚合-品牌名聚合brandAgg.subAggregation(AggregationBuilders.terms("brand_name_agg").field("brandName").size(1));//1.2 品牌的子聚合-品牌图片聚合brandAgg.subAggregation(AggregationBuilders.terms("brand_img_agg").field("brandImg").size(1));searchSourceBuilder.aggregation(brandAgg);//2. 按照分类信息进行聚合TermsAggregationBuilder catalogAgg = AggregationBuilders.terms("catalog_agg");catalogAgg.field("catalogId").size(20);catalogAgg.subAggregation(AggregationBuilders.terms("catalog_name_agg").field("catalogName").size(1));searchSourceBuilder.aggregation(catalogAgg);//2. 按照属性信息进行聚合NestedAggregationBuilder attrAgg = AggregationBuilders.nested("attr_agg", "attrs");//2.1 按照属性ID进行聚合TermsAggregationBuilder attrIdAgg = AggregationBuilders.terms("attr_id_agg").field("attrs.attrId");attrAgg.subAggregation(attrIdAgg);//2.1.1 在每个属性ID下,按照属性名进行聚合attrIdAgg.subAggregation(AggregationBuilders.terms("attr_name_agg").field("attrs.attrName").size(1));//2.1.1 在每个属性ID下,按照属性值进行聚合attrIdAgg.subAggregation(AggregationBuilders.terms("attr_value_agg").field("attrs.attrValue").size(50));searchSourceBuilder.aggregation(attrAgg);log.debug("构建的DSL语句 {}",searchSourceBuilder.toString());SearchRequest searchRequest = new SearchRequest(new String[]{EsConstant.PRODUCT_INDEX},searchSourceBuilder);return searchRequest;}
}
  1. 依赖注入
  • @Autowired:自动注入RestHighLevelClient,这是Elasticsearch的Java高级REST客户端。
  1. 搜索方法

    • search(SearchParam param):根据传入的搜索参数param执行搜索,并返回SearchResult对象。
  2. 构建搜索请求

    • buildSearchRequest(SearchParam param):动态构建Elasticsearch的搜索请求,包括查询条件、排序、分页、高亮和聚合分析。
  3. 构建搜索结果

    • buildSearchResult(SearchResponse response, SearchParam param):从Elasticsearch的响应中提取数据,并构建SearchResult对象。
  4. 查询构建细节

    • 使用BoolQueryBuilder来构建复合查询,包括必须匹配的条件(must)、过滤条件(filter)等。
    • 对于每个搜索参数,如关键字、分类ID、品牌ID、属性、库存、价格区间等,都有相应的查询构建逻辑。
  5. 高亮显示

    • 如果搜索包含关键字,则使用HighlightBuilder来高亮显示匹配的文本。
  6. 排序和分页

    • 根据参数设置排序字段和顺序。
    • 设置分页的页码和每页大小。
  7. 聚合分析

    • 对品牌、分类和属性进行聚合分析,以便于在搜索结果的侧边栏展示统计信息。

六,183-商城业务-检索服务-验证结果封装正确性

在首页搜索框输入“华为”,点击搜索,跳转到搜索页面,后端会执行ES检索,查看日志,判断接口响应结果是否符合预期。

在这里插入图片描述

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • js中的promise、async/await 用法,详解async、await 语法糖,js中的宏任务和微任务(保姆级教程二)
  • vscode的C/C++环境配置和调试技巧
  • 基于Transformer机制的AI现阶段可能已达峰值
  • xss复现
  • WPF打印控件内容
  • 嵌入式linux系统镜像制作day2
  • 软件工程概述(上)
  • 关注自闭症儿童:走进他们孤独的世界
  • CentOS7安装流程步骤详细教程
  • 数学建模预测类—【多元线性回归】
  • 【ARM】Cortex-A72技术手册(1)
  • c语言---文件
  • SQL每日一练-0816
  • CSS的:current伪类:精准定位当前活动元素
  • Kali Linux网络问题解决与静态IP配置技巧
  • 时间复杂度分析经典问题——最大子序列和
  • java B2B2C 源码多租户电子商城系统-Kafka基本使用介绍
  • leetcode98. Validate Binary Search Tree
  • php面试题 汇集2
  • SpiderData 2019年2月23日 DApp数据排行榜
  • thinkphp5.1 easywechat4 微信第三方开放平台
  • Zsh 开发指南(第十四篇 文件读写)
  • 基于web的全景—— Pannellum小试
  • 区块链分支循环
  • 使用parted解决大于2T的磁盘分区
  • 一个JAVA程序员成长之路分享
  • 怎么将电脑中的声音录制成WAV格式
  • nb
  • Android开发者必备:推荐一款助力开发的开源APP
  • shell使用lftp连接ftp和sftp,并可以指定私钥
  • 从如何停掉 Promise 链说起
  • 如何通过报表单元格右键控制报表跳转到不同链接地址 ...
  • 完善智慧办公建设,小熊U租获京东数千万元A+轮融资 ...
  • 资深实践篇 | 基于Kubernetes 1.61的Kubernetes Scheduler 调度详解 ...
  • ​【原创】基于SSM的酒店预约管理系统(酒店管理系统毕业设计)
  • # 透过事物看本质的能力怎么培养?
  • ### Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLTr
  • #NOIP 2014# day.1 T2 联合权值
  • (PHP)设置修改 Apache 文件根目录 (Document Root)(转帖)
  • (PySpark)RDD实验实战——取最大数出现的次数
  • (zz)子曾经曰过:先有司,赦小过,举贤才
  • (附源码)springboot车辆管理系统 毕业设计 031034
  • (附源码)springboot美食分享系统 毕业设计 612231
  • (附源码)ssm教师工作量核算统计系统 毕业设计 162307
  • (七)Knockout 创建自定义绑定
  • (未解决)jmeter报错之“请在微信客户端打开链接”
  • (五十)第 7 章 图(有向图的十字链表存储)
  • (一)spring cloud微服务分布式云架构 - Spring Cloud简介
  • (转)IOS中获取各种文件的目录路径的方法
  • ***php进行支付宝开发中return_url和notify_url的区别分析
  • ***微信公众号支付+微信H5支付+微信扫码支付+小程序支付+APP微信支付解决方案总结...
  • ./configure,make,make install的作用
  • .form文件_SSM框架文件上传篇
  • .net core 调用c dll_用C++生成一个简单的DLL文件VS2008
  • .NET NPOI导出Excel详解