尚品汇-ES(三十一)

news2024/11/13 21:05:29

目录:

(1)封装搜索相关实体对象

(2)搜索接口封装

(3)在service-list-client模块添加远程接口

(1)封装搜索相关实体对象

搜索参数实体:SearchParam

搜索参数实体:SearchParam
package com.atguigu.gmall.model.list;
/**
 * 商品搜索参数
 * 参数说明:
 *      1,商标品牌:trademark=2:华为  
 *              2:为品牌id,搜索字段
 *              华为:品牌名称,页面回显属性
 *      2,平台属性:props=23:4G:运行内存
 *              23:平台属性id,搜索字段
 *              运行内存:平台属性名称,页面回显属性
 *              4G:平台属性值,搜索字段与页面回显属性
 * </p>
 *
 */
@Data
public class SearchParam {

    // ?category3Id=61&trademark=2:华为&props=23:4G:运行内存&order=1:desc
    //category3Id=61
    private Long category1Id;;//三级分类id
    private Long category2Id;
    private Long category3Id;

    //trademark=2:华为
       private String trademark;//品牌id

    private String keyword;//检索的关键字

    // order=1:asc  排序规则   0:asc
    private String order = "";// 1:综合排序/热点  2:价格

    //props=23:4G:运行内存
    private String[] props;//页面提交的数组

    private Integer pageNo = 1;//分页信息
    private Integer pageSize = 12;
}

 搜索结果集实体:SearchResponseVo

搜索结果集实体:SearchResponseVo

package com.atguigu.gmall.model.list;


@Data
public class SearchResponseVo implements Serializable {

    //品牌 此时vo对象中的id字段保留(不用写) name就是“品牌” value: [{id:100,name:华为,logo:xxx},{id:101,name:小米,log:yyy}]
  private List<SearchResponseTmVo> trademarkList;
    //所有商品的顶头显示的筛选属性
    private List<SearchResponseAttrVo> attrsList = new ArrayList<>();

    //检索出来的商品信息
    private List<Goods> goodsList = new ArrayList<>();

  private Long total;//总记录数
    private Integer pageSize;//每页显示的内容
    private Integer pageNo;//当前页面
    private Long totalPages;

}

结果集品牌实体:SearchResponseTmVo

package com.atguigu.gmall.model.list;


@Data
public class SearchResponseTmVo implements Serializable {

    //当前属性值的所有值
    private Long tmId;
    //属性名称
    private String tmName;//网络制式,分类

    //图片url
    private String tmLogoUrl;
}

结果集平台属性实体:SearchResponseAttrVo

package com.atguigu.gmall.model.list;


@Data
public class SearchResponseAttrVo implements Serializable {

   private Long attrId;//1
    //当前属性值的所有值
    private List<String> attrValueList = new ArrayList<>();
    //属性名称
    private String attrName;//网络制式,分类
}

(2)搜索接口封装

SearchService接口

/**
 * 搜索列表
  * @param searchParam
 * @return
 * @throws IOException
 */
SearchResponseVo search(SearchParam searchParam) throws IOException;

接口实现类

api参考文档:

Java REST Client [7.8] | Elastic

Java REST Client [7.8] | Elastic

@Autowired
private RestHighLevelClient restHighLevelClient;
@Override
public SearchResponseVo search(SearchParam searchParam) throws IOException {
    // 构建dsl语句
    SearchRequest searchRequest = this.buildQueryDsl(searchParam);
    SearchResponse response = this.restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
    System.out.println(response);

    SearchResponseVo responseVO = this.parseSearchResult(response);
    responseVO.setPageSize(searchParam.getPageSize());
    responseVO.setPageNo(searchParam.getPageNo());
    long totalPages = (responseVO.getTotal()+searchParam.getPageSize()-1)/searchParam.getPageSize();
    responseVO.setTotalPages(totalPages);
    return responseVO;
}


//封装查询条件
// 制作dsl 语句  
private SearchRequest buildQueryDsl(SearchParam searchParam) {
    // 构建查询器
    SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
    // 构建多条件对象boolQueryBuilder
    BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

    // 判断查询条件是否为空 关键字
    if (!StringUtils.isEmpty(searchParam.getKeyword())){
        // 小米手机  小米and手机
        // MatchQueryBuilder matchQueryBuilder = new MatchQueryBuilder("title",searchParam.getKeyword()).operator(Operator.AND);
        MatchQueryBuilder title = QueryBuilders.matchQuery("title", searchParam.getKeyword()).operator(Operator.AND);
        boolQueryBuilder.must(title);
    }

    // 构建品牌查询
    String trademark = searchParam.getTrademark();
    if (!StringUtils.isEmpty(trademark)){
        // trademark=2:华为
        String[] split = StringUtils.split(trademark, ":");
        if (split != null && split.length == 2) {
             //构建过滤品牌
             TermQueryBuilder tmId=QueryBuilders.termQuery("tmId", split[0]);
            // 根据品牌Id过滤  添加到多条件对象
            boolQueryBuilder.filter(tmId);
        }
    }

    // 构建分类过滤 用户在点击的时候,只能点击一个值,所以此处使用term
    if(null!=searchParam.getCategory1Id()){
        boolQueryBuilder.filter(QueryBuilders.termQuery("category1Id",searchParam.getCategory1Id()));
    }
    // 构建分类过滤
    if(null!=searchParam.getCategory2Id()){
        boolQueryBuilder.filter(QueryBuilders.termQuery("category2Id",searchParam.getCategory2Id()));
    }
    // 构建分类过滤
    if(null!=searchParam.getCategory3Id()){
        boolQueryBuilder.filter(QueryBuilders.termQuery("category3Id",searchParam.getCategory3Id()));
    }


    // 构建平台属性查询
    // 23:4G:运行内存
    String[] props = searchParam.getProps();
    if (props!=null && props.length>0){
        // 循环遍历
        for (String prop : props) {
            // 23:4G:运行内存  平台属性id:平台属性值名称:平台属性名
            String[] split = StringUtils.split(prop, ":");
            if (split!=null && split.length==3){
                // 构建嵌套查询  创建多条件对象
                BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
                // 嵌套查询子查询
                BoolQueryBuilder subBoolQuery = QueryBuilders.boolQuery();
                // 构建子查==询中的过滤条件
                subBoolQuery.must(QueryBuilders.termQuery("attrs.attrId",split[0]));
                subBoolQuery.must(QueryBuilders.termQuery("attrs.attrValue",split[1]));
                // ScoreMode.None ?
                boolQuery.must(QueryBuilders.nestedQuery("attrs",subBoolQuery, ScoreMode.None));
                // 添加到整个过滤对象中,外层对象
                boolQueryBuilder.filter(boolQuery);
            }
        }
    }
    // 执行查询方法
    searchSourceBuilder.query(boolQueryBuilder);



    // 构建分页
    int from = (searchParam.getPageNo()-1)*searchParam.getPageSize();
    searchSourceBuilder.from(from);
    searchSourceBuilder.size(searchParam.getPageSize());

    // 排序  1:hotScore 2:price   1:综合排序/热度  2:价格
    //1:asc
    String order = searchParam.getOrder();
    if (!StringUtils.isEmpty(order)){
        // 判断排序规则
        String[] split = StringUtils.split(order, ":");
        if (split!=null && split.length==2){
            // 排序的字段
            String field = null;
            // 数组中的第一个参数
            switch (split[0]){
                case "1":
                    field="hotScore";
                    break;
                case "2":
                    field="price";
                    break;
            }
            searchSourceBuilder.sort(field,"asc".equals(split[1])? SortOrder.ASC:SortOrder.DESC);
        }else {
            // 没有传值的时候给默认值
            searchSourceBuilder.sort("hotScore",SortOrder.DESC);
        }
    }

    // 构建高亮
        HighlightBuilder highlightBuilder = new HighlightBuilder();
    highlightBuilder.field("title");
    highlightBuilder.postTags("</span>");
    highlightBuilder.preTags("<span style=color:red>");

    searchSourceBuilder.highlighter(highlightBuilder);

    //  设置品牌聚合
    TermsAggregationBuilder termsAggregationBuilder =        AggregationBuilders.terms("tmIdAgg").field("tmId")
        .subAggregation(AggregationBuilders.terms("tmNameAgg").field("tmName"))
        .subAggregation(AggregationBuilders.terms("tmLogoUrlAgg").field("tmLogoUrl"));
    
    searchSourceBuilder.aggregation(termsAggregationBuilder);

    //  设置平台属性聚合
    searchSourceBuilder.aggregation(AggregationBuilders.nested("attrAgg", "attrs")
                    .subAggregation(AggregationBuilders.terms("attrIdAgg").field("attrs.attrId")
                    .subAggregation(AggregationBuilders.terms("attrNameAgg").field("attrs.attrName"))
                    .subAggregation(AggregationBuilders.terms("attrValueAgg").field("attrs.attrValue"))));


    // 结果集过滤
    searchSourceBuilder.fetchSource(new String[]{"id","defaultImg","title","price"},null);

    SearchRequest searchRequest = new SearchRequest("goods");
    //searchRequest.types("_doc");

    //将构建对象添加到请求中
    searchRequest.source(searchSourceBuilder);
    System.out.println("dsl:"+searchSourceBuilder.toString());
    return searchRequest;
}



// 制作返回结果集
private SearchResponseVo parseSearchResult(SearchResponse response) {
    SearchHits hits = response.getHits();
    //声明对象
    SearchResponseVo searchResponseVo = new SearchResponseVo();
    //获取品牌的集合
    Map<String, Aggregation> aggregationMap = response.getAggregations().asMap();
    //ParsedLongTerms ?
    ParsedLongTerms tmIdAgg = (ParsedLongTerms) aggregationMap.get("tmIdAgg");
    List<SearchResponseTmVo> trademarkList = tmIdAgg.getBuckets().stream().map(bucket -> {
        SearchResponseTmVo trademark = new SearchResponseTmVo();
        //获取品牌Id
         trademark.setTmId((Long.parseLong(((Terms.Bucket) bucket).getKeyAsString())));
        //trademark.setTmId(Long.parseLong(bucket.getKeyAsString()));
        //获取品牌名称
        Map<String, Aggregation> tmIdSubMap = ((Terms.Bucket) bucket).getAggregations().asMap();
        ParsedStringTerms tmNameAgg = (ParsedStringTerms) tmIdSubMap.get("tmNameAgg");
        String tmName = tmNameAgg.getBuckets().get(0).getKeyAsString();

        trademark.setTmName(tmName);
ParsedStringTerms tmLogoUrlAgg = (ParsedStringTerms) tmIdSubMap.get("tmLogoUrlAgg");
String tmLogoUrl = tmLogoUrlAgg.getBuckets().get(0).getKeyAsString();
trademark.setTmLogoUrl(tmLogoUrl);

        return trademark;
    }).collect(Collectors.toList());
    searchResponseVo.setTrademarkList(trademarkList);

    //赋值商品列表
    SearchHit[] subHits = hits.getHits();
    List<Goods> goodsList = new ArrayList<>();
    if (subHits!=null && subHits.length>0){
        //循环遍历
        for (SearchHit subHit : subHits) {
            // 将subHit 转换为对象
            Goods goods = JSONObject.parseObject(subHit.getSourceAsString(), Goods.class);

            //获取高亮
            if (subHit.getHighlightFields().get("title")!=null){
                Text title = subHit.getHighlightFields().get("title").getFragments()[0];
                goods.setTitle(title.toString());
            }
            goodsList.add(goods);
        }
    }
    searchResponseVo.setGoodsList(goodsList);

    //获取平台属性数据
    ParsedNested attrAgg = (ParsedNested) aggregationMap.get("attrAgg");
    ParsedLongTerms attrIdAgg = attrAgg.getAggregations().get("attrIdAgg");
    List<? extends Terms.Bucket> buckets = attrIdAgg.getBuckets();
    if (!CollectionUtils.isEmpty(buckets)){
        List<SearchResponseAttrVo> searchResponseAttrVOS = buckets.stream().map(bucket -> {
            //声明平台属性对象
            SearchResponseAttrVo responseAttrVO = new SearchResponseAttrVo();
            //设置平台属性值Id
            responseAttrVO.setAttrId(((Terms.Bucket) bucket).getKeyAsNumber().longValue());
            ParsedStringTerms attrNameAgg = bucket.getAggregations().get("attrNameAgg");
            List<? extends Terms.Bucket> nameBuckets = attrNameAgg.getBuckets();
            responseAttrVO.setAttrName(nameBuckets.get(0).getKeyAsString());
            //设置规格参数列表
            ParsedStringTerms attrValueAgg = ((Terms.Bucket) bucket).getAggregations().get("attrValueAgg");
            List<? extends Terms.Bucket> valueBuckets = attrValueAgg.getBuckets();

            List<String> values = valueBuckets.stream().map(Terms.Bucket::getKeyAsString).collect(Collectors.toList());
            responseAttrVO.setAttrValueList(values);

            return responseAttrVO;

        }).collect(Collectors.toList());
        searchResponseVo.setAttrsList(searchResponseAttrVOS);
    }
    // 获取总记录数
    searchResponseVo.setTotal(hits.getTotalHits().value);

    return searchResponseVo;
}

 

 

控制器ListApiController

/**
 * 搜索商品
 * @param searchParam
 * @return
 * @throws IOException
 */
@PostMapping
public Result list(@RequestBody SearchParam searchParam) throws IOException {
    SearchResponseVo response = searchService.search(searchParam);
    return Result.ok(response);
}

在service-list 模块中配置logstash

首先在service模块中添加依赖

<dependency>

            <groupId>net.logstash.logback</groupId>

            <artifactId>logstash-logback-encoder</artifactId>

            <version>5.1</version>

        </dependency>

其次,将日志配置文件放入到resources目录下!

(3)在service-list-client模块添加远程接口

package com.atguigu.gmall.list.client;
@FeignClient(value = "service-list", fallback = ListDegradeFeignClient.class)
public interface ListFeignClient {

    /**
     * 搜索商品
          * @param listParam
     * @return
     */
    @PostMapping("/api/list")
    Result list(@RequestBody SearchParam listParam);

    /**
     * 上架商品
     * @param skuId
     * @return
     */
    @GetMapping("/api/list/inner/upperGoods/{skuId}")
    Result upperGoods(@PathVariable("skuId") Long skuId);

    /**
     * 下架商品
     * @param skuId
     * @return
     */
    @GetMapping("/api/list/inner/lowerGoods/{skuId}")
    Result lowerGoods(@PathVariable("skuId") Long skuId);

}
package com.atguigu.gmall.list.client.impl;

@Component
public class ListDegradeFeignClient implements ListFeignClient {

    @Override
    public Result list(SearchParam searchParam) {
        return Result.fail();
    }

    @Override
    public Result upperGoods(Long skuId) {
        return null;
    }

    @Override
    public Result lowerGoods(Long skuId) {
        return null;
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2034609.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

haproxy高级功能配置

介绍HAProxy高级配置及实用案例 一.基于cookie会话保持 cookie value:为当前server指定cookie值&#xff0c;实现基于cookie的会话黏性&#xff0c;相对于基于 source 地址hash 调度算法对客户端的粒度更精准&#xff0c;但同时也加大了haproxy负载&#xff0c;目前此模式使用…

Service服务在Android中的使用

目录 一&#xff0c;Service简介 二&#xff0c;Service的两种启动方式 1&#xff0c;非绑定式启动Service 2&#xff0c;绑定式启动Service 三&#xff0c;Service的生命周期 1&#xff0c;非绑定式Service的生命周期 2&#xff0c;绑定式Service的生命周期 四&#xf…

BCArchive加密工具实测分享:为何我觉得它很实用?

前言 你是不是经常有这样的烦恼&#xff1a;重要的文件、私密的照片、敏感的资料&#xff0c;总是担心会不小心泄露出去&#xff1f;哎呀&#xff0c;别担心&#xff0c;别担心&#xff0c;我今天要介绍的这款软件&#xff0c;简直就是守护你数据安全的超级英雄&#xff01; 在…

CVE-2012-2122 mysql/mariaDB身份认证漏洞

简介&#xff1a; 当连接MariaDB/MySQL时&#xff0c;输入的密码会与期望的正确密码比较&#xff0c;不断的尝试登录连接&#xff0c;回导致MySQL认为两个密码是相同的。也就是说只要知道用户名&#xff0c;不断尝试就能够直接登入SQL数据库。 影响范围#所有的Mariadb和mysql版…

【吊打面试官系列-Elasticsearch面试题】Elasticsearch 在部署时,对 Linux 的设置有哪些优化方法?

大家好&#xff0c;我是锋哥。今天分享关于 【Elasticsearch 在部署时&#xff0c;对 Linux 的设置有哪些优化方法&#xff1f;】面试题&#xff0c;希望对大家有帮助&#xff1b; Elasticsearch 在部署时&#xff0c;对 Linux 的设置有哪些优化方法&#xff1f; 1、64 GB 内存…

【STM32】CubeMX + CLion + FreeRTOS移植过程问题记录

文章目录 一、portable 文件选择二、自定义文件添加三、ST-Link v2 烧录问题四、STM32F407工程中程序无法启动调度器 前言   本文依照稚晖君分享的配置CLion用于STM32开发【优雅の嵌入式开发】&#xff0c;尝试配置STM32CubeMX CLion开发环境&#xff0c;并在此基础上移植Fre…

利用Emgucv绘制条形码边框16(C#)

EmguCV环境配置&#xff1a; ​​​​​​Emgu CV4图像处理之环境搭建1(C#)_emgucv 4.7-CSDN博客 本文测试环境&#xff1a; win10 64位 vistual studio 2019 Emgu CV 4.6.0 环境配置准备&#xff1a; 1 新增控制台项目&#xff0c;.net framework为4.7.2 2 把win-x…

minikube 实践练习

前言 我这里就简单跟着官方教程做了下练习 参考文档&#xff1a;https://v1-27.docs.kubernetes.io/zh-cn/docs/tutorials/hello-minikube/ 这里最重要的是&#xff0c;你需要提前配置好你的网络。 这个我教不了&#xff0c;之前发了篇帖子vmware实现科学上网审核不通过&…

ElasticSearch 全文检索相关性 算分

文章目录 相关性相关性Relevance相关性算法TF-IDFBM25 通过Explain查看TF-IDFboosting query 多字段查询 相关性dis_max query最佳字段查询multi_match querybest_fields最佳匹配字段most_fields 多数字段搜索cross_fields跨字段搜索 相关性 相关性Relevance 搜索的相关性算分…

Ubuntu 通过 docker 安装 Nginx 镜像 + 创建并运行 nginx01 容器

一、安装 nginx:精简版镜像 1. 查找有什么类型的 nginx 镜像 yammiemy-pc >/home/yammie $ docker search nginx 2. 下载精简版 nginx 镜像 yammiemy-pc >/opt $ docker pull nginx:alpine alpine: Pulling from library/nginx 46b060cc2620: Already exists 21af147…

【深度学习|目标跟踪】快速入门卡尔曼滤波!

卡尔曼滤波详解 申明一、什么是卡尔曼滤波1.1 卡尔曼滤波的使用场景1.2 卡尔曼滤波的定义 二、卡尔曼滤波公式详解&#xff08;无推导&#xff09;三、卡尔曼滤波的简单应用 申明 本博客参考了b站up主“华南小虎队”的卡尔曼滤波教学视频以及Lauszus Kristian Sloth Lauszus的卡…

联想Thinkpad驱动安装下载(官网的驱动下载)

联想Thinkpad驱动安装官网下载地址&#xff1a; 联想驱动管理_ThinkPad服务网站-联想服务 联想驱动管理 帮助您更快速准确的定位驱动 自动下载安装,安装驱动不求人 软件版本&#xff1a;V2.9.0719.1104 | 大小&#xff1a;5.7M最后更新&#xff1a;2021-07-21支持系统&#…

41.【C语言之外】聊聊Cheat Engine官方教程步骤6的思考

0.看前须知 有一定指针概念的基础 推荐阅读前几篇博文&#xff1a; 19.【C语言】指针&#xff08;重难点&#xff09;&#xff08;A&#xff09; 37.【C语言】指针&#xff08;重难点&#xff09;&#xff08;B&#xff09; 38.【C语言】指针&#xff08;重难点&#xff09…

oracle的exp.exe、imp.exe在哪下载?

需要oracle账号 地址&#xff1a; Instant Client for Microsoft Windows (x64) 64-bit 下载这个工具包

开发一个能打造虚拟带货直播间的工具!

在当今数字化时代&#xff0c;直播带货已成为电商领域的一股强劲力量&#xff0c;其直观、互动性强的特点极大地提升了消费者的购物体验。 然而&#xff0c;随着技术的不断进步&#xff0c;传统直播带货模式正逐步向更加智能化、虚拟化的方向演进&#xff0c;本文将深入探讨如…

智慧景区系统开发功能定制

智慧景区系统开发功能定制是一项综合性服务&#xff0c;它涉及到利用云计算、物联网、AI监控等先进技术&#xff0c;通过互联网和移动互联网&#xff0c;实现景区智慧化管理和服务提升。 以下是智慧景区系统开发中应考虑的关键功能点&#xff1a; 游客服务平台&#xff1a;包…

23款奔驰E350eL升级原厂香氛负离子系统,保持一股高级的香味

相信大家都知道&#xff0c;奔驰自从研发出香氛负离子系统后&#xff0c;一直都受广大奔驰车主的追捧&#xff0c;香氛负离子不仅可以散发出清香淡雅的香气外&#xff0c;还可以对车内的空气进行过滤&#xff0c;使车内的有害气味通过负离子进行过滤&#xff0c;达到车内保持清…

“AI能不能代替某某职业”,到底谁在破防?

前几天&#xff0c;公司在午间分享时谈到一个有趣的辩题&#xff1a;“AI能不能代替产品经理”&#xff0c;不仅双方辩手打了个你来我往&#xff0c;就连下面的吃瓜群众也进入红温状态。 “AI能不能代替xx”已经成为一个普遍的话题&#xff0c;在某乎上随手一刷就是不同的职业…

Linux 利用 ftrace 分析内核调用

目录 一、概述二、ftrace 的使用1、常用信息2、指定 ftrace 跟踪器3、设置要跟踪的函数4、ftrace 的开关5、function 跟踪程序6、function_graph 跟踪程序7、函数过滤器8、跟踪事件 三、trace-cmd 的使用1、常见命令2、常用选项2.1 列出可用的追踪器2.2 跟踪特定进程的函数调用…

如何用剪映自动批量生成左右分屏的视频?

做tiktok中视频计划的朋友&#xff0c;应该都知道一种批量做号的模式&#xff0c;就是找一些热门视频作为左边主机视频&#xff0c;右边则放上一些减压类视频以保存画面的原创度&#xff0c;像下面这种。 这种视频是如何批量用剪映生成的呢&#xff1f; 一、准备好素材 下载好…