黑马SpringBoot+Elasticsearch作业2实战:商品搜索与竞价排名功能实现

Elasticsearch的基本语法我们已经学完,足以应对大多数搜索业务需求了。接下来大家就可以基于学习的知识实现商品搜索的业务了。在昨天的作业中要求大家拆分一个独立的微服务:search-service,在这个微服务中实现搜索数据的导入、商品数据库数据与elasticsearch索引库数据的同步。接下来的搜索功能也要在search-service服务中实现。

拆分成单独的服务search-service在上一个作业已经实现了

这次作业主要是过滤条件聚合和竞价排序

工具直接用swagger调试就行,记得在网关的时候把/Search/**路径放行,不用登录校验这样就方便很多。

1.过滤条件聚合

这张图片就是发过来的参数,首先分析一个每个参数在文档中设置的类型,整体流程就是,先根据条件查询,再排序,最后分页取出

1.1 条件查询

json 复制代码
"mappings" : {
      "properties" : {
        "brand" : {
          "type" : "keyword"
        },
        "category" : {
          "type" : "keyword"
        },
        "commentCount" : {
          "type" : "integer",
          "index" : false
        },
        "id" : {
          "type" : "keyword"
        },
        "image" : {
          "type" : "keyword",
          "index" : false
        },
        "isAD" : {
          "type" : "boolean"
        },
        "name" : {
          "type" : "text",
          "analyzer" : "ik_max_word"
        },
        "price" : {
          "type" : "integer"
        },
        "sold" : {
          "type" : "integer"
        },
        "stock" : {
          "type" : "integer"
        },
        "updateTime" : {
          "type" : "date"
        }
      }

因此可以得出:

text ------》 matchQuery

keyword ------》 termQuery

price ------》 rangeQuery

注意:在添加条件之前,记得先进行判空

1.2 排序

整体思路,前端有个参数传过来是------sortBy,表示按照什么排序,我这里设置了默认值为price

java 复制代码
      if (query.getIsAsc()){
                if (query.getSortBy() == null){
                    query.setSortBy("price");
                }
                request.source().sort(query.getSortBy(), SortOrder.ASC);
            }

1.3 分页

分页是根据前端传过来的pageSize,pageNo决定的

java 复制代码
 request.source().query(bool)
                    .from((query.getPageNo() - 1) * query.getPageSize())
                    .size(query.getPageSize());

1.4 完整代码

java 复制代码
@Override
    public Page<ItemDOC> queryItemByES(ItemPageQuery query) {

        client = new RestHighLevelClient(
                RestClient.builder(new HttpHost("127.0.0.1", 9200, "http")));


        SearchRequest request = new SearchRequest("item");
        BoolQueryBuilder bool = new BoolQueryBuilder();

        if (query.getKey() != null) {
            bool.filter(QueryBuilders.matchQuery("name", query.getKey()));
        }

        if (query.getCategory() != null) {
            bool.filter(termQuery("category", query.getCategory()));
        }

        if (query.getBrand() != null){
            bool.filter(termQuery("brand", query.getBrand()));
        }



        if (query.getMinPrice() != null || query.getMaxPrice() != null) {
            RangeQueryBuilder rangeQuery = QueryBuilders.rangeQuery("price");

            if (query.getMinPrice() != null) {
                rangeQuery.gte(query.getMinPrice()); // 大于等于最小价格
            }

            if (query.getMaxPrice() != null) {
                rangeQuery.lte(query.getMaxPrice()); // 小于等于最大价格
            }

            bool.filter(rangeQuery);
        }

	//TODO 设置竞价排名

        Page<ItemDOC> page = new Page<>();
        try {
            if (query.getIsAsc()){
                if (query.getSortBy() == null){
                    query.setSortBy("price");
                }
                request.source().sort(query.getSortBy(), SortOrder.ASC);
            }
            request.source().query(bool)
                    .from((query.getPageNo() - 1) * query.getPageSize())
                    .size(query.getPageSize());

            SearchResponse response = client.search(request, RequestOptions.DEFAULT);
            List<ItemDOC> itemDOCS = handleResponse(response);

            SearchHits searchHits = response.getHits();
            long total = searchHits.getTotalHits().value;

            page.setCurrent(query.getPageNo());
            page.setSize(query.getPageSize());
            page.setTotal(total);
            page.setRecords(itemDOCS);
            client.close();
        }catch (Exception e){
            e.printStackTrace();
        }

        return page;
    }

2.竞价排名

要让广告商品(isAD = true)排在前面,同时保持原有相关性得分,可以用 function_score 查询,通过 filter + weight 的方式给广告商品额外加分。

2.1 实现代码:代码位置上面标注了

java 复制代码
//1.过滤出加权函数
FunctionScoreQueryBuilder.FilterFunctionBuilder[] functions = {
                new FunctionScoreQueryBuilder.FilterFunctionBuilder(
                        termQuery("isAD", true),  //如果是广告就进行加权
                        weightFactorFunction(100.0f) //设置权重
                )
        };

        // 2. 用带有 FilterFunctionBuilder[] 的构造器
        FunctionScoreQueryBuilder fsqb = new FunctionScoreQueryBuilder(
                bool,        // 你原来的 bool 查询
                functions    // 函数数组
        )
                .scoreMode(FunctionScoreQuery.ScoreMode.SUM) //多个 function 得分相加
                .boostMode(CombineFunction.SUM);// 与原始的得分进行累加

// 3. 替换原来的 query
request.source().query(fsqb);

参数说明:

  • weightFactorFunction(100f):广告商品权重值
  • ScoreMode.SUM:多权重值求和模式
  • CombineFunction.SUM:新分数=原始分+权重分
相关推荐
Memory_荒年36 分钟前
Java + FFmpeg:从“玩具”到“工业级”的音视频实战
后端
码农周1 小时前
告别大体积PDF!基于PDFBox的Java压缩工具
java·spring boot
吕永强2 小时前
基于SpringBoot+Vue小区报修系统的设计与实现(源码+论文+部署)
spring boot·毕业设计·毕业论文·报修系统·小区报修
awljwlj2 小时前
黑马点评复习—缓存相关【包含可能的问题和基础知识复习】
java·后端·spring·缓存
XY_墨莲伊2 小时前
【实战项目】基于B/S结构Flask+Folium技术的出租车轨迹可视化分析系统(文末含完整源代码)
开发语言·后端·python·算法·机器学习·flask
神奇小汤圆2 小时前
为什么Claude Code这么强?我从泄漏的源码里挖到了核心秘密
后端
精品源码屋2 小时前
千万级CSV/Excel表统计教程:基于本地数据库的自然语言单表、多表分析 | DT-Bot工作流
后端
Gopher_HBo2 小时前
CompletableFuture运用原理
java·后端
Leinwin2 小时前
GPT-6 API接入完全指南:Symphony架构下的多模态调用与最佳实践
后端·python·flask