电商项目——商城业务-检索服务——第六章——中篇

电商项目——全文检索-ElasticSearch——第一章——中篇
电商项目——商城业务-商品上架——第二章——中篇
电商项目——商城业务-首页——第三章——中篇
电商项目——性能压测——第四章——中篇
电商项目——缓存——第五章——中篇
电商项目——商城业务-检索服务——第六章——中篇
电商项目——商城业务-异步——第七章——中篇
电商项目——商品详情——第八章——中篇
电商项目——认证服务——第九章——中篇
电商项目——购物车——第十章——中篇
电商项目——消息队列——第十一章——中篇
电商项目——订单服务——第十二章——中篇
电商项目——分布式事务——第十三章——中篇

1:搭建页面环境

我们接下来就搭建整个商城的检索功能,同样的按照微服务自治的功能,我们的检索功能就放在mall-search下
在这里插入图片描述
在这里插入图片描述
index.html要引入依赖和标头,并且进行替换(变成linux的nginx中的文件路径/html/)

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-thymeleaf</artifactId>
		</dependency>
<html lang="en" xmlns:th="http://www.thymeleaf.org">

在这里插入图片描述
在这里插入图片描述
将所有静态资源放在linux中的/mydata/nginx/html/static/search下,实现动静分离
在这里插入图片描述
我们要实现通过访问search.mall.com然后跳转到nginx,在到网关,最后回显到检索页面
第一步:配置域名网关映射
在这里插入图片描述
第二步:进行nginx的配置,配置mall.conf

在这里插入图片描述

第三步:进行网关配置,,前提:mall-serach要配置在nacos服务中心里面

       - id: mall_host_route
        uri: lb://mall-search
        predicates:
          - Host=search.mall.com   

在这里插入图片描述
在这里插入图片描述

2:调整页面跳转

前面搭建好了页面检索环境,现在我们就来梳理一下检索逻辑
在这之前,我们要配置dev-tools的依赖和配置关闭缓存

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
		</dependency>
spring:
  thymeleaf:
    cache: false

在这里插入图片描述
接下来我们要完成商城首页(zlj.mall.com)跳转到检索页面的跳转(search.mall.com)
第一个:打通点击三级分类下数据跳转到检索页面
第二个:点击搜素内容可以跳转到检索页面
接下来一一介绍
在这里插入图片描述
1:打通点击三级分类下数据跳转到检索页面

在这里插入图片描述
mall-search
controller
SearchController

@Controller
public class SearchController {
   

    @GetMapping("/list.html")
    public String listPage(){
   

        return "list";
    }
}

2:点击搜素内容可以跳转到检索页面
在这里插入图片描述
search()下的方法

      window.location.href="http://search.mall.com/list.html?keyword="+keyword;

如上我们就完成了调整页面跳转

3:检索查询参数模型分析抽取

前面我们无论是选择分类,还是进行检索关键字,都打通了到search.mall.com/list.html的检索系统(mall-search),接下来,我们就分析一下检索系统检索这些商品都需要哪些检索条件。。我们是由mall-search中的controller下的SearchController类下的如下方法 @GetMapping("/list.html") public String listPage()来完成的,它要做的事情就是它要接收所有的检索条件,然后进行处理,最后进行返回;我们要写一个SearchParam类来接受所有的检索条件,还要写一个接口来进行处理,最后返回给页面list
mall-search
vo
SearchParam
如上操作流程,转化成如下代码演示

@Controller
public class SearchController {
   

    @Autowired
    MallService mallService;
    @GetMapping("/list.html")
    public String listPage(SearchParam searchParam){
   

       Object result= mallService.search(param);
        return "list";
    }

}

我们现在就要分析,封装页面所有可呢传递过来的查询条件,查询条件有哪些???并把他们写入SearchParam类中
商品检索条件的三个入口,我们第三个入口要传递的参数是最难判断的
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
如下就是我们分析的有可呢会从前端传递到后端的检索条件,最终我们也希望我们的MallSearchService中的方法可以去es中通过这些检索条件,来找到我们想要的查询结果

/**
 * 封装页面所有可呢传递过来的查询条件
 * 自动将页面提交过来的所有请求查询参数封装成指定的对象SearchParam 
 * @author Mr.zhneg
 * @create 2020-11-04-22:49
 */
@Data
public class SearchParam {
   

    private String keyword;//页面传递过来的全文匹配关键字
    private Long catalog3Id;//三级分类id

    /**
     *  sort=saleCount_asc/desc
     *  sort=skuPrice_asc/desc
     *  sort=hotScore_asc/desc
     */
    private String sort;//排序条件

    /**
     * 好多的过滤条件
     * hasStock(是否有货)  ,skuPrice价格区间,brandId,catalog3Id,attrs
     * hasStock=0/1
     * skuPrice =1_500/_500/500_
     * brandId=1
     *
     */
    private Integer hasStock;//是否有货
    private String skuPrice;//价格区间查询
    private List<Long> brandId;//按照品牌进行查询,可以多选
    private List<String> attrs;//按照属性进行筛选
    private Integer pageNum;//页码
}

4:检索返回结果模型分析抽取

前面我们通过分析页面,将所有可呢提交的查询参数封装成了SearchParam 对象,我们调用方法把前端提交过来的参数,查询出对应的结果然后通过封装返回给页面
在这里插入图片描述

在这里插入图片描述
mall-search
vo
SearchResult

@Data
public class SearchResult{
   

    //查询到的所有商品信息
    private List<SkuEsModel> products;

    /**
     * 以下是分页信息
     */
    private Integer pageNum;//当前页码
    private Long total;//总记录数
    private Integer totalPage;//总页码

    private List<BrandVo> brands;//当前查询到的结果,所有涉及到的品牌
    private List<CatalogVo> catalogs;//当前查询到的结果,所有涉及到的分类
    private List<AttrVo> attrs;//当前查询到的结果,所有涉及到的属性
    /**
     *=====以上是返回给页面的所有信息
     */
    @Data
    public static class BrandVo{
   
        private Long brandId;
        private String brandName;
        private String brandImg;
    }
    @Data
    public static class CatalogVo{
   
        private Long catalogId;
        private String catalogName;
    }

    @Data
    public static class AttrVo{
   
        private Long attrId;
        private String attrName;
        private String attrValue;
    }
}

SearchController 大致框架已经搭建完成,下章节,我们就讲如何去es中查询

public class SearchController {

    @Autowired
    MallSearchService mallService;

    /**
     * 自动将页面提交过来的所有请求查询参数封装成指定的对象
     * @param searchParam
     * @return
     */
    @GetMapping("/list.html")
    public String listPage(SearchParam searchParam, Model model){

        //1:根据传递来的页面的查询参数,去es中检索商品
       SearchResult result= mallService.search(searchParam);
       model.addAttribute("result",result);

        return "list";
    }

}

5:检索DSL测试-查询部分

mall-search

  • 前面我们抽取了两种数据模型,第一个是我们可呢从页面传递过来的请求参数,我们封装成SearchParam,还有一个就是我们将页面的返回结果抽取成SearchResult,我们contoller(SearchController)接受到请求就应该去调用业务逻辑里面的检索功能进行检索;而这些功能非常复杂,我们现在就要使用kibana来测试如何检索商品,为了以后可以在search(MallSearchService)方法中更好的实现业务代码
    在这里插入图片描述
    我在码云中的项目里面已经保存了,我测试检索DSL-查询部分地址如下,都在mall-search中有一个.json文件结尾的
    zlj分布式代码
    更难的在后面,
    在这里插入图片描述

每次查询一个东西以后,下一次我们要查询的东西是动态变化的,它是根据我们已查到的东西聚合分析出来的(我们查到的东西的属性,值有哪些),我们下节就完成检索DSL测试-聚合部分
https://www.elastic.co/guide/index.html

6:检索DSL测试-聚合部分

在这里插入图片描述

我在码云中的项目里面已经保存了,我测试检索DSL-聚合部分地址如下,都在mall-search中有一个.json文件结尾的
zlj分布式代码
https://www.elastic.co/guide/index.html

7:SearchRequest构建-检索

动态的构建出查询所需要的dsl语句
https://www.elastic.co/guide/index.html
mall-search
MallSearchServiceImpl

@Service("MallSearchService")
@Slf4j
public class MallSearchServiceImpl implements MallSearchService {
   

    @Autowired
    private RestHighLevelClient client;
    @Override
    public SearchResult search(SearchParam param) throws IOException {
   
        //1:动态构建出查询需要的DSL语句
        SearchResult result=null;

        //1:准备检索请求
        SearchRequest searchRequest=new SearchRequest();
        searchRequest= buildSearchRequest(param);
        try {
   
            //2:执行检索请求
            SearchResponse response = client.search(searchRequest, MallESConfig.COMMON_OPTIONS);

            //3:分析响应数据封装成我们需要的格式
           result= buildSearchResult(response);
        }catch (IOException e){
   
            e.printStackTrace();
        }

        return null;
    }

    /**
     * 构建结果数据
     * @param response
     * @return
     */
    private SearchResult buildSearchResult(SearchResponse response) {
   

        return null;
    }

    /**
     * 准备检索请求
     * 模糊匹配。过滤(按照属性,分类,品牌,架构区间,库存),排序,分页,高亮,聚合分析
     */
    private SearchRequest buildSearchRequest(SearchParam param){
   

        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();//构建DSL语句

        /**
         *   查询:模糊匹配。过滤(按照属性,三级分类,品牌,价格区间,库存),排序,分页,高亮,聚合分析
         */

        //1:构建bool -query
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        //1.1  must ——模糊匹配
        if (!StringUtils.isEmpty(param.getKeyword())){
   
            boolQuery.must(QueryBuilders.matchQuery("skuTitle",param.getKeyword()));
        }
        //1.2 bool -filiter——按照三级分类id查询
        if (param.getCatalog3Id()!=null){
   
            boolQuery.filter(QueryBuilders.termsQuery("catalogId",param.getCatalog3Id()));

        }
        //1.2 bool -filiter——按照品牌id查询
        if (param.getBrandId()!=null&&param.getBrandId().size()>0){
   
            boolQuery.filter(QueryBuilders.termsQuery("brandId",param.getBrandId()));
        }
        //1.2 bool -filiter——按照属性查询
        if (param.getAttrs()!=null &&param.getAttrs().size()>0){
   

            //不断遍历循环
            //attrs=1_5寸:8寸&attrs=2_16G:8G
            for (String attrStr:param.getAttrs()){
   
                BoolQueryBuilder nestedboolQuery = QueryBuilders.boolQuery();

                //attrs=1_5寸:8寸
                String[] s = attrStr.split("_");
                String attrId=s[0];//检索属性id
                String[] attrValues=s[1].split(":");//这个属性的检索用的值
                nestedboolQuery.must(QueryBuilders.termsQuery("attrs.attrId",attrId));
                nestedboolQuery.must(QueryBuilders.termsQuery("attrs.attrValue",attrValues));
               //每一个都必须生成一个nested查询
                NestedQueryBuilder nestedQuery = QueryBuilders.nestedQuery("attrs", nestedboolQuery, ScoreMode.None);
                boolQuery.filter(nestedQuery);

            }


            }

        //1.2 bool -filiter——按照库存查询
        boolQuery.filter(QueryBuilders.termsQuery("hasStock",param.getHasStock()==1));

        //1.2 bool -filiter——按照价格区间查询
        if(!StringUtils.isEmpty(param.getSkuPrice())){
   
            //1_500/_500/500_
            RangeQueryBuilder rangeQuery = QueryBuilders.rangeQuery("skuPrice");

            String[] s = param.getSkuPrice().split("_");
            if (s.length==2){
   
                //区间
                //大于前边的小于后边的
                rangeQuery.gte(s[0]).lte(s[1]);

            }else if (s.length==1){
   
                if (param.getSkuPrice().startsWith("_")){
   
                    rangeQuery.lte(s[0]);
                }
                if (param.getSkuPrice().endsWith("_")){
   
                    rangeQuery.gte(s[0]);
                }
            }
        }
        //把以前的所有条件都拿来进行封装
        sourceBuilder.query(boolQuery);
        /**
         * 排序,分页,高亮,
         */

        /**
         * 聚合分析
         */
        SearchRequest searchRequest = 
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值