尚品汇-ES(三十一)

目录:

(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;
    }
}

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

喵俺第一专栏

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值