springboot+springcloud + elasticsearch (电商平台搜索功能)_按照价格区间查询条件 前端传参-程序员宅基地

技术标签: 知识总结  java  

搜索关键字查询
0.1 构建查询条件
1). 需求

在这里插入图片描述
2). 接口定义
public interface SearchService {
//按照查询条件进行数据查询
Map search(Map<String,String> searchMap);
}

方法形参 Map : 关键字 , 品牌 , 规格 , 价格 , 排序, 分页参数 ;
返回值为 Map : 分页结果 , 结果列表 , 品牌 , 规格 … ;
3). 接口实现-条件封装
技术 : SpringDataElasticSearch ; ------> 并未使用原生API : RestHighLevelClient
1). 封装请求条件
NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();// 多条件查询使用 , 通过该boolQuery组装多个条件

//根据关键字搜索
if (StringUtils.isNotEmpty(searchMap.get(“keywords”))){
boolQuery.must(QueryBuilders.matchQuery(“name”,searchMap.get(“keywords”)).operator(Operator.AND));//必须满足
}
//… boolQuery组装多个条件

nativeSearchQueryBuilder.withQuery(boolQuery);

2). 执行请求
AggregatedPage resultInfo = elasticsearchTemplate.queryForPage(nativeSearchQueryBuilder.build(), SkuInfo.class, new SearchResultMapper() {
@Override
public AggregatedPage mapResults(SearchResponse searchResponse, Class aClass, Pageable pageable) {
//查询结果操作
List list = new ArrayList<>();

    //获取查询命中结果数据
    SearchHits hits = searchResponse.getHits();
    if (hits != null){
        //有查询结果
        for (SearchHit hit : hits) {
            //SearchHit转换为skuinfo
            SkuInfo skuInfo = JSON.parseObject(hit.getSourceAsString(), SkuInfo.class);
            list.add((T) skuInfo);
        }
    }
    return new AggregatedPageImpl<T>(list,pageable,hits.getTotalHits(),searchResponse.getAggregations());
}

});

//总记录数
resultMap.put(“total”,resultInfo.getTotalElements());
//总页数
resultMap.put(“totalPages”,resultInfo.getTotalPages());
//数据集合
resultMap.put(“rows”,resultInfo.getContent());

在这里插入图片描述
可以参考ElasticSearch的原始操作请求Rest接口, 理解 :
请求链接 : POST http://192.168.192.152:9200/skuinfo/docs/_search
请求参数 :
{“query”:{
“bool”:{
“must”:[
{“match”:{“name”:“手机”}}
]
}
},
“from”:0,
“size”:2
}

0.2 Controller
@RestController
@RequestMapping("/search")
public class SearchController {

@Autowired
private SearchService searchService;

@GetMapping //?key=value&key=value
public Map search(@RequestParam Map<String,String> searchMap){
    Map searchResult = searchService.search(searchMap);
    return searchResult;
}

}

1.搜索 - 条件筛选
1.1 介绍
在这里插入图片描述

1.2 品牌过滤查询
//按照品牌进行过滤查询
// 1.4 根据品牌进行过滤查询
// 如果请求参数中包含brand 品牌 且数据信息不为空
if (StringUtils.isNotEmpty(searchMap.get(“brand”))){
// 使用boolQuery进行过滤 因为是进行过滤查询,所以不进行分词,直接精确匹配
// 第一个参数为需要进行过滤查询的域 第二个字段为需要匹配的值
boolQuery.filter(QueryBuilders.termQuery(“brandName”,searchMap.get(“brand”)));
}

matchQuery : 会对查询的关键字进行分词 , 然后再进行匹配 ;
termQuery : 不会对关键字进行分词, 精准匹配 ;
1.3 品牌聚合查询
1). 品牌列表数据来源
在这里插入图片描述

2). 在数据库中应该如何实现
SELECT brand_name AS brandName FROM tb_sku WHERE NAME LIKE ‘%手机%’ GROUP BY brand_name;

在这里插入图片描述
3). ES中的实现方式
A. 设置分组条件 (根据那个域进行分组)
// 1.5.1 对于品牌进行聚合查询,关键字搜索不同时,所对应的品牌也不相同,所以对应品牌进行聚合查询
// 第一个参数为给分组查询起的别名。 第二个参数为需要对那个域进行分组查询
String skuBrand = “skuBrand”;
nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms(skuBrand).field(“brandName”));

B. 解析分组结果
// 1.5.2获取resultInfo的品牌分组数据,进行封装
StringTerms brandTerms = (StringTerms) resultInfo.getAggregation(skuBrand);
// 1.5.3使用stream流将brandTerms中的数据取出,并转换为list。封装在mapResult中
List brandList = brandTerms.getBuckets().stream().map(bucket -> bucket.getKeyAsString()).collect(Collectors.toList());
resultMap.put(“brandList”,brandList);

1.4 规格过滤查询
1). 参数传递
在这里插入图片描述

2). 代码实现
// 1.6 对于规格信息进行过滤查询
// 1.6.1在前台发送数据的时候因为规格的数据也跟随着品牌的变化,而不相同,所以约定规格数据发送的时候为spec_开头
// 1.6.2遍历所有接收到的请求参数
for (String key : searchMap.keySet()) {
// 1.6.3如果key的开头为"spec_"则证明是传递的规格参数 例如spec_尺寸
if (key.startsWith(“spec_”)){
// 1.6.4获取到所对应的值
String value = searchMap.get(key);
//1.6.5 对指定的域进行过滤
boolQuery.filter(QueryBuilders.termQuery((“specMap.” + key.substring(5) + “.keyword”),value));
}
}

URL编解码:
浏览器在请求后端接口时, 会对url中的中文 , 特殊符号 , 进行URL编码;
服务端获取到数据之后, 会自动对url进行解码 ;

  • -----------> 2B%
    1.5 规格分组聚合
    A. 设置分组条件

// 1.6.6 对于规格进行聚合查询,关键字搜索不同,所对应的规格也不同,
String skuSpec = “skuSpec”;
nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms(skuSpec).field(“spec.keywords”));

B. 解析分组结果
// 1.6.7 获取resultInfo的规格分组数据,进行封装
StringTerms specTerms = (StringTerms) resultInfo.getAggregation(skuSpec);
// 1.6.8 使用 stream流将specTerms中的数据取出,并转换为list,封装在mapResult中
List specList = specTerms.getBuckets().stream().map(bucket -> bucket.getKeyAsString()).collect(Collectors.toList());
resultMap.put(“specList”,specList);

1.6 价格区间过滤查询
1). 前端参数传递

在这里插入图片描述
price : 0-500 , 500-1000 , 3000
2). 代码实现
// 1.7对于价格进行过滤查询
// 价格传递过来的关键字为 0-500 或者3000+ 这样的。所以进行对字符串进行切割
if (StringUtils.isNotEmpty(searchMap.get(“price”))) {
String[] prices = searchMap.get(“price”).split("-");
// 1.7.1如果prices的长度为2 则证明里面封装了一个范围, 否则为大于该价格
if (prices.length == 2) {
// 1.7.2 定义价格区间为小于 prices[1]
boolQuery.filter(QueryBuilders.rangeQuery(“price”).lte(prices[1]));
}
// 1.7.3定义价格区间大于prices[0]
boolQuery.filter(QueryBuilders.rangeQuery(“price”).gte(prices[0]));
}

2.搜索 - 分页
// 1.8对应页面进行分页设置
// 1.8.1定义当前页的页码
String pageNum = searchMap.get(“pageNum”);
// 1.8.2定义每页显示的页码
String pageSize = searchMap.get(“pageSize”);
// 1.8.3 如果客户端每页传递分页的条件,则自定义一个
if (StringUtils.isEmpty(searchMap.get(“pageNum”))) {
pageNum = “1”;
}
if (StringUtils.isEmpty(searchMap.get(“pageSize”))) {
pageSize = “50”;
}
// 1.8.4 进行分页查询的设置
// 第一个参数为当前页:索引从0开始
// 第二个参数为每页显示的数据数,
nativeSearchQueryBuilder.withPageable(PageRequest.of(Integer.parseInt(pageNum) - 1,Integer.parseInt(pageSize)));

注意: 查询的页面时从0开始的 ;
3.搜索 - 排序
1). 前端传递参数

在这里插入图片描述
sortField : price
sortRule : 升序ASC / 降序DESC
2). 代码实现
// 1.当前域 2.当前的排序操作(升序ASC,降序DESC)
// 1.9 对于价格栏进行排序
// 1.9.1如果分组字段sortFiled 以及分组的条件sortRule 不为空,则进行排序
if (StringUtils.isNotEmpty(searchMap.get(“sortField”))&&StringUtils.isNotEmpty(searchMap.get(“sortRule”))){
if (“ASC”.equals(searchMap.get(“sortRule”))){
//升序
// 第一个参数为需要进行排序的字段,第二个参数为排序的规则
nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort((searchMap.get(“sortField”))).order(SortOrder.ASC));
}else{
//降序
nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort((searchMap.get(“sortField”))).order(SortOrder.DESC));
}
}

4.搜索 - 高亮展示
4.1 高亮原理
手机
手机
手机
手机
高亮三要素 : 前缀 , 后缀 , 高亮域
4.2 高亮代码实现
1). 设置高亮参数
// 1.10 对关键字进行高亮查询
// 1.10.1设置高亮域
HighlightBuilder.Field filed = new HighlightBuilder.Field(“name”)
// 1.10.2这是高亮样式的前缀
.preTags("")
// 1.10.3这是高亮样式的后缀
.postTags("
");
nativeSearchQueryBuilder.withHighlightFields(filed);

2). 解析高亮结果
// 1.10.4解析高亮结果
Map<String, HighlightField> highlightFields = hit.getHighlightFields();
// 1.10.5非空校验,进行替换原来的内容
if (null != highlightFields && highlightFields.size() > 0) {
skuInfo.setName(highlightFields.get(“name”).getFragments()[0].toString());
}

在这里插入图片描述

6.1 搜索接口开发

在这里插入图片描述
API :

在这里插入图片描述

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_44993313/article/details/104402113

智能推荐

SSH服务器拒绝了密码。请再试一次 问题解决_ssh拒绝了密码,请再试一次-程序员宅基地

文章浏览阅读1.1k次。SSH服务器拒绝了密码。请再试一次1.问题 SSH服务器拒绝了密码。请再试一次2.查看配置vim /etc/ssh/sshd_config找到Authentication# Authentication:#LoginGraceTime 2m#PermitRootLogin yes#StrictModes yes把配置改成# Authentication:LoginGraceTime 2mPermitRootLogin yesStrictModes yes重启s_ssh拒绝了密码,请再试一次

黑马IOS基础课程的学习笔记 C语言基础_黑马朴乾-程序员宅基地

文章浏览阅读576次。昨天弄了一天虚拟机是装上了 不过 这速度 装Xcode也死活装不上。。无爱了。。在MAC系统中的终端操作指令cc -c文件名.c // 要有空格编译成功会生成一个.o的目标文件链接 指令 CC 文件名.o 要有空格 貌似能多个文件一起链接的样子。 其实就是把我们的.o目标文件跟系统自带的库函数合并在一起,生成一个可_黑马朴乾

创建ICC2/ICC所需要的tech file(.tf)_icc 没有.tf文件怎么办-程序员宅基地

文章浏览阅读3.7k次,点赞2次,收藏7次。最近摸索了一下ICC2创建tech file的过程。首先,我手上有什么?没错,我什么都没有,只有stdcell的Layout.1. 通过icfb dump出tech.lef文件。这个过程中,需要选择一个technology library, 而technolgy library可以选择项目中的tech lib。一般在创建tech lib的时候,会关联virtuoso的Tech file.因此,选择这个library,就相当于关联了一个tech file (virtuoso版本的)。然后export l_icc 没有.tf文件怎么办

react Native 执行 run-android报错Failed to launch emulator. Reason: Emulator exited before boot._error failed to launch emulator. reason: emulator -程序员宅基地

文章浏览阅读1.3w次。react Native 执行 run-android 错误,报错如图报错信息:未能启动模拟器。原因:模拟器在启动前退出。原因:x86镜像的模拟器启动不了,因为HAMX没有安装。Android SDK已经集成了HAMX这个软件,我们需要做的就是找到他,然后安装就可以了。文件路径:存放于你的SDK下面的D:\Program Files\Android\AndroidSDK\(自己指定的SD..._error failed to launch emulator. reason: emulator exited before boot..

ROS moveit 机械臂笛卡尔空间运动_omputecartesianpath-程序员宅基地

文章浏览阅读5.7k次,点赞12次,收藏89次。机械臂moveit编程(python)机械臂在笛卡尔空间的运动只能走点到点的直线运动,通过将位姿点加入waypoints中,机械臂会一次按照waypoints中的唯一依次沿直线运动到下一个点。程序流程:1.初始化需要控制的规划组;2.设置运动约束(可选);3.设置终端link;4.设置坐标系;5.建立一个waypoints空列表,将所需要到达的位姿加入waypoints列表;6.用..._omputecartesianpath

基于开源技术,构建ONVIF录播服务器_录播服务器技术创新-程序员宅基地

文章浏览阅读1.4k次,点赞3次,收藏3次。引子: ONVIF协议是监控领域的国际标准,现在基本所有的大厂IPC摄像头都支持此协议。如果想开发一套录播系统,支持IPC摄像头的集中录制,点播回放,以及实时监控流调度,提供的点播协议需要支持rtsp和HLS,可以利用的开源技术有哪些呢?本文提供的基本解决方案如下IPC 1------&gt;IPC 2 ------&gt; 基于onvif + live555 + ffmpeg 的Re..._录播服务器技术创新

随便推点

【HRBUST - 1996】数学等式 (HASH 或 二分)_现在给出三个数字a,b和c,你可以在保证a+b不变的情况下对两数进行调整,设调整以后-程序员宅基地

文章浏览阅读360次。题干:又到了数学题的时刻了,给出三个数组A,B,C,然后再给出一个数X,现在我想知道是否能找到三个数满足等式A[i]+B[j]+C[k]=X,你能帮助我么??Input本题有多组数据,每组数据第一行输入三个数n,m,h,分别表示数组A,B,C内的的元素个数(0<n,m,h<=500)接下来三行分别输入数组A,B,C的元素接下来输入一个数Q,表示Q次询问(1&l..._现在给出三个数字a,b和c,你可以在保证a+b不变的情况下对两数进行调整,设调整以后

数据可视化基本套路总结-程序员宅基地

文章浏览阅读2k次,点赞3次,收藏13次。真依然很拉风,简书《数据可视化》专栏维护者,里面有很多优秀的文章,本文便是其中一篇。文章总结了多种数据可视化图形,并简要介绍了各种图形的作用,能为科研工作者在数据可视化阶段提供新的思路,..._计算机设计大赛经验分享,数据可视化

鸿蒙智联生态产品《接入智慧生活App开发指导》(官方更新版)_万和热水器如何加入鸿蒙智联-程序员宅基地

文章浏览阅读1.3k次。在HarmonyOS Connect生态产品应用开发过程中,很多开发者对于如何接入智慧生活App还存在一些疑问,如:如何选择合适的开发方式、如何进行H5开发与调测等。为了更好地帮助开发者,官方文档特意整理出“接入智慧生活App”专题。跟紧小编的步伐,赶紧来看看本次文档更新内容~文档中心-接入智慧生活App的开发指导:文档中心智慧生活App作为华为全场景智慧体验的重要入口,可以实现华为自研设备与生态伙伴设备的统一管理。图1 智慧生活App伙伴可以通过开发H5..._万和热水器如何加入鸿蒙智联

Typescript error :Property mozRequestFullScreen' does not exist on type 'HTMLElement'_属性“mozrequestfullscreen”在类型“htmlelement”上不存在。你是否指的-程序员宅基地

文章浏览阅读1.2k次。当我一开始在做全屏功能的时候,遇到了以下这个问题:Typescript error :Property mozRequestFullScreen' does not exist on type 'HTMLElement'.其他类似问题:property ‘xxx’ does not exist on type ‘yyy’解决:声明用let de : any;..._属性“mozrequestfullscreen”在类型“htmlelement”上不存在。你是否指的是“req

URAL 1684. Jack's Last Word KMP_ural kmp-程序员宅基地

文章浏览阅读1k次。题目来源:URAL 1684. Jack's Last Word题意:输入a b 把b分成若干段 每一段都是a的前缀思路:b为主串 然后用a匹配b 记录到b的i位置最大匹配的长度 然后分割 分割的时候要从后往前如果a = abac b = abab 那么如果从前往后 首先覆盖了aba 然后b就不能覆盖了 从后往前就可以了 首先覆盖ab 下一次还是ab因为已经记录了到i位置的最大匹配_ural kmp

【课题总结】OpenCV 抠图项目实战(4)固定阈值抠图_opencv 扣图-程序员宅基地

文章浏览阅读4.6k次,点赞3次,收藏34次。第三章 阈值抠图阈值处理方法直观简单,是一种基本的图像分割方法。根据图像的整体或部分信息适当选择阈值,像素值高于阈值时设为1/255,低于阈值时设为0,以此将图像中感兴趣的区域筛选出来生成掩模,再与原图像合成即可得到抠图图像。由于待处理图像的灰度级数与其灰度直方图是不确定的,对于不同的图像、不同的目标前景,需要选取适当的阈值处理方法进行图像分割。本章采用固定阈值、自适应阈值与色彩范围三种方法进行图像抠图处理。_opencv 扣图