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

智能推荐

快速导入十亿数据到hugegraph图数据库_hugegraph导数据后没有图-程序员宅基地

在前面学习了《快速入门hugegraph图数据库》和《hugegraph图数据库概念详解》之后,大家一定想导入一定规模的真实数据到hugegraph练练手,本文就以Stanford的公开数据为例,教大家如何快速导入10亿+的数据到hugegraph图数据库。1. 环境准备导入数据到hugegraph之前需要准备好一些必要环境,包括:安装服务hugegraph-server和下载导入工具huge..._hugegraph导数据后没有图

ModBus-RTU详解_mbsartu-程序员宅基地

Modbus 一个工业上常用的通讯协议、一种通讯约定。Modbus协议包括RTU、ASCII、TCP。其中MODBUS-RTU最常用,比较简单,在单片机上很容易实现。虽然RTU比较简单,但是看协议资料、手册说得太专业了,起初很多内容都很难理解。 所谓的协议是什么?就是互相之间的约定嘛,如果不让别人知道那就是暗号。现在就来定义一个新的最简单协议。例如,协议: “A” --“LED灭” ..._mbsartu

测试用例注意事项-程序员宅基地

1、正确性测试:输入实际数据以验证系统是满足需求说明书的要求;2、非法类型测试: 输入非法数据,程序应能给出提示文案3、接口测试:测试各个模块相互间的协调和通信情况,数据输入输出的一致性和正确性。4、数据库测试:依据数据库设计规范对软件系统的数据库结构、数据表及其之间的数据调用关系进行测试。5、边界值分析法:边界情况(等于、小于和大于等价类边界值),2.6.1在测试过程中主要输..._测试用例注意事项

python 读grid 数据_如何将TextGrid文件的变量读入Python?-程序员宅基地

余弦语言语料库的转录如下:File type = "ooTextFile"Object class = "TextGrid"xmin = 0xmax = 3931.56874994773tiers? size = 8item []:item [1]:class = "IntervalTier"name = "Phrases"xmin = 0xmax = 3931.56874994773interv..._textgrid文本读取python

vue引用公用的头部和尾部文件。-程序员宅基地

我创建了一个header.vue和fotter.vue,用来做于网站的头部和尾部,每个页面都需要引用这两个,我以组件的方式,来引用这样只需要添加注册的组件就可以了。第一步、在components文件夹下新建header.vue,footer.vue两个组件第二步、修改index.js,也就是程序入口:引入两个头尾组件第三步、修改App.vue也就是页面入口:引入两个头尾组件..._vue.js 制作公共的头尾

当写烂代码的人离职之后....-程序员宅基地

今天看到一篇关于代码的规范之文章,在此分享给大家, 原文地址 **当写烂代码的人离职之后….** 2016-03-08 java那些事 本文作者:蛋疼的AXB 来源:程序人生 写烂代码很容易 一坨翔但居然能用 刚入程序员这行的时候经常听到一个观点:你要把精力放在ABCD(需求文档/功能设计/架构设计/理解原理)上,写代码只是把想法翻译成编程语言而已,是一个没什么技术含量的事

随便推点

Linux服务器的进程查看命令详解_ps -ef|grep命令 linux 怎么查看进程是否启动-程序员宅基地

Linux 服务器正常启动后,提供服务时会调用程序,占用进程。这时候我们如何查看系统中有哪些进程在被调用呢?我们可以通过以下命令来查看。一、ps 命令ps 命令是最基本同时也是非常强大的进程查看命令。使用该命令可以确定有哪些进程正在运行和它所运行的状态、进程是否结束、进程有没有僵死、哪些进程占用了过多的资源等。总之大部分信息都是可以通过执行该命令得到的。ps 命令最常用来监控后台进程的工作情况,因为后台进程是不和屏幕、键盘这些标准输入/输出设备进行通信的,所以如果需要检测后台情况,就需要使用 ps 命令_ps -ef|grep命令 linux 怎么查看进程是否启动

软件开发六阶段和十个经典模型_系统开发的6个阶段-程序员宅基地

软件开发六阶段软件开发十模型_系统开发的6个阶段

09_Up and Running with TensorFlow_Anaconda3-4.2.0_No module named joblib_KeyError 0_Normal Equation_joblib keyerror: 0-程序员宅基地

TensorFlow is a powerful open source software library for numerical computation, particularly wellsuited and fine-tuned for large-scale Machine Learning. Its basic principle is simple: you first define inPython a graph of computations to perform (fo..._joblib keyerror: 0

图文字浅谈--计算机网络常遇的面试问题(计网面经)-程序员宅基地

学习计算机网络准备面试的同时做了一些笔记,分享出来希望能够帮助大家快速掌握计算机网络常遇到的问题。笔记主要选自《图解HTTP》与《图解TCP/IP》以及网络面经,由于本人也是处于学习阶段,同时笔记是Word转MD上传,格式与知识点有误处望请指正。计算机网络一、协议层次以及服务类型OSI七层模型开放式通信系统互联参考模型 每一层实现各自的功能和协议,并完成相邻层的接口通信 某一层的服务就是该层以及其下各层的一种能力1.应用层通过应用程序间的交互来完成特定的网络应用。 协议定义了应用进._计网面经

Hive数据仓库建模_hive数据建模-程序员宅基地

1、基于Hive数据仓库建模数据仓库的发展大致经历了这样的三个过程:报表——>集市——>仓库简单报表阶段:这个阶段,系统的主要目标是解决一些日常的工作中业务人员需要的报表,以及生成一些简单的能够帮助领导进行决策所需要的汇总数据。这个阶段的大部分表现形式为数据库和前端报表工具。数据集市阶段:这个阶段,主要是根据某个业务部门的需要,进行一定的数据的采集,整理,按照业务人员的需要,进行多维报表的展现,能够提供对特定业务指导的数据,并且能够提供特定的领导决策数据。数据仓库阶段:这个阶_hive数据建模

树莓派3B+ 启用LCD显示屏_适合树莓派3b+独立显示器怎么设置-程序员宅基地

对于新手来说,如果没有显示屏显示树莓派运行状态,会让他们满头雾水,不知道怎么操作。所以,就来学学怎么启用小型的LCD显示屏吧!_适合树莓派3b+独立显示器怎么设置