SpringBoot整合Elasticsearch实现商品搜索

本文主要介绍在Elasticsearch中实现商品搜索功能

中文分词器

  • Elasticsearch有默认的分词器,默认分词器只是将中文逐词分隔,并不符合我们的需求。

    get hanzo/_analyze
    {
      "text": "小米手机",
      "tokenizer": "standard"
    }
    
  • 需要安装与Elasticsearch版本相同的ik分词器,ik分词器将小米手机分为小米和手机,符合我们的要求。

get hanzo/_analyze
{
  "text": "小米手机",
  "tokenizer": "ik_max_word"
}

在SpringBoot中使用

在商品信息实体类中用@Document、@Field等注解。对于需要中文分词的字段,我们直接使用@Field注解属性设置为ik_max_word。

/**
 * @Author 皓宇QAQ
 * @Date 2020/6/4 20:49
 * @Description:搜索中的商品信息
 */
@Document(indexName = "hanzo", type = "product",shards = 1,replicas = 0)
@Data
public class EsProduct implements Serializable {
    private static final long serialVersionUID = -1L;
    @Id
    private Long goodsId;
    @Field(analyzer = "ik_max_word",type = FieldType.Text)
    private String goodsName;
    @Field(analyzer = "ik_max_word",type = FieldType.Text)
    private String goodsIntro;

    private Long goodsCategoryId;

    private String goodsCoverImg;

    private String goodsCarousel;

    private Integer originalPrice;

    private Integer sellingPrice;

    private Integer stockNum;

    private String tag;

    private Byte goodsSellStatus;

    private Integer createUser;

    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date createTime;

    private Integer updateUser;

    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date updateTime;
    @Field(type = FieldType.Keyword)
    private String goodsDetailContent;
}

简单商品搜索

先实现一个最简单的商品搜索功能,搜索包括商品名称,商品简介,商品标签中包含指定的关键字的商品和一个直接根据商品分类进行查询商品的功能

  • 在SpringBoot中实现,使用Elasticsearch Repositories的衍生查询来搜索;

    public interface EsProductRepository extends ElasticsearchRepository<EsProduct, Long> {
        /**
         * 衍生搜索关键字查询
         *
         * @param goodsName          商品名称
         * @param goodsIntro         商品简介
         * @param tag               商品标签
         * @param page              分页信息
         * @return
         */
        Page<EsProduct> findByGoodsNameOrGoodsIntroOrTag(String goodsName, String goodsIntro, String tag,Pageable page);
        
       /**
         * 衍生搜索商品分类定位查询
         *
         * @param goodsCategoryId   商品分类
         * @param page              分页信息
         * @return
         */
        Page<EsProduct> findByGoodsCategoryId(Long goodsCategoryId, Pageable page);
    
    }
    
  • 衍生查询其实原理很简单,就是将一定规则方法名称的方法转化为Elasticsearch的Query DSL语句,看完下面这张表你就懂了。

product_search_04.png

综合商品搜索

接下来我们来实现一个复杂的商品搜索,涉及到过滤、不同字段匹配权重不同以及可以进行排序。

  • 首先来说下我们的需求,按输入的关键字搜索商品名称、商品简介和 商品标签,默认按相关度进行排序;
  • 这里我们有一点特殊的需求,比如商品名称匹配关键字的的商品我们认为与搜索条件更匹配,其次是商品简介和商品标签,这时就需要用到function_score查询了;
  • 在Elasticsearch中搜索到文档的相关性由_score字段来表示的,文档的_score字段值越高,表示与搜索条件越匹配,而function_score查询可以通过设置权重来影响_score字段值,使用它我们就可以实现上面的需求了;
  • 在SpringBoot中实现,使用Elasticsearch Repositories的search方法来实现,但需要自定义查询条件QueryBuilder;
 @Override
    public Page<EsProduct> sortSearch(String keyword, Integer pageNum, Integer pageSize, Integer sort) {
        Pageable pageable = PageRequest.of(pageNum, pageSize);
        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
        //分页
        nativeSearchQueryBuilder.withPageable(pageable);
        //过滤
        
        //搜索
        if (StringUtils.isEmpty(keyword)) {
            nativeSearchQueryBuilder.withQuery(QueryBuilders.matchAllQuery());
        } else {
            List<FunctionScoreQueryBuilder.FilterFunctionBuilder> filterFunctionBuilders = new ArrayList<>();
            filterFunctionBuilders.add(new FunctionScoreQueryBuilder.FilterFunctionBuilder(QueryBuilders.matchQuery("goodsName", keyword),
                    ScoreFunctionBuilders.weightFactorFunction(10)));
            filterFunctionBuilders.add(new FunctionScoreQueryBuilder.FilterFunctionBuilder(QueryBuilders.matchQuery("goodsIntro", keyword),
                    ScoreFunctionBuilders.weightFactorFunction(5)));
            filterFunctionBuilders.add(new FunctionScoreQueryBuilder.FilterFunctionBuilder(QueryBuilders.matchQuery("tag", keyword),
                    ScoreFunctionBuilders.weightFactorFunction(2)));
            FunctionScoreQueryBuilder.FilterFunctionBuilder[] builders = new FunctionScoreQueryBuilder.FilterFunctionBuilder[filterFunctionBuilders.size()];
            filterFunctionBuilders.toArray(builders);
            FunctionScoreQueryBuilder functionScoreQueryBuilder = QueryBuilders.functionScoreQuery(builders)
                    .scoreMode(FunctionScoreQuery.ScoreMode.SUM)
                    .setMinScore(2);
            nativeSearchQueryBuilder.withQuery(functionScoreQueryBuilder);
        }
        //排序
        if(sort==1){
            //按新品从新到旧
            nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort("goodsId").order(SortOrder.DESC));
        }else if(sort==2){
            //按库存从高到低
            nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort("stockNum").order(SortOrder.DESC));
        }else if(sort==3){
            //按价格从低到高
            nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort("sellingPrice").order(SortOrder.ASC));
        }else if(sort==4){
            //按价格从高到低
            nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort("sellingPrice").order(SortOrder.DESC));
        }else{
            //按相关度
            nativeSearchQueryBuilder.withSort(SortBuilders.scoreSort().order(SortOrder.DESC));
        }
        nativeSearchQueryBuilder.withSort(SortBuilders.scoreSort().order(SortOrder.DESC));
        NativeSearchQuery searchQuery = nativeSearchQueryBuilder.build();
        log.info("DSL:{}", searchQuery.getQuery().toString());
        return productRepository.search(searchQuery);
    }

相关商品推荐

当我们查看相关商品的时候,一般底部会有一些商品推荐,这里使用Elasticsearch来简单实现下。

  • 首先来说下我们的需求,可以根据指定商品的ID来查找相关商品;

  • 这里我们的实现原理是这样的:首先根据ID获取指定商品信息,然后以指定商品的名称、商品简介、商品标签和分类来搜索商品,并且要过滤掉当前商品,调整搜索条件中的权重以获取最好的匹配度;

  • 在SpringBoot中实现,使用Elasticsearch Repositories的search方法来实现,但需要自定义查询条件QueryBuilder;

    @Override
        public Page<EsProduct> recommend(Long id, Integer pageNum, Integer pageSize) {
            Pageable pageable = PageRequest.of(pageNum, pageSize);
            List<EsProduct> esProductList = productDao.getAllEsProductList(id);
            if (esProductList.size() > 0) {
                EsProduct esProduct = esProductList.get(0);
                String keyword = esProduct.getGoodsName();
                Long goodsCategoryId = esProduct.getGoodsCategoryId();
                //根据商品名称、商品简介,商品标签,分类进行搜索
                List<FunctionScoreQueryBuilder.FilterFunctionBuilder> filterFunctionBuilders = new ArrayList<>();
                filterFunctionBuilders.add(new FunctionScoreQueryBuilder.FilterFunctionBuilder(QueryBuilders.matchQuery("goodsName", keyword),
                        ScoreFunctionBuilders.weightFactorFunction(8)));
                filterFunctionBuilders.add(new FunctionScoreQueryBuilder.FilterFunctionBuilder(QueryBuilders.matchQuery("goodsIntro", keyword),
                        ScoreFunctionBuilders.weightFactorFunction(2)));
                filterFunctionBuilders.add(new FunctionScoreQueryBuilder.FilterFunctionBuilder(QueryBuilders.matchQuery("tag", keyword),
                        ScoreFunctionBuilders.weightFactorFunction(2)));
                filterFunctionBuilders.add(new FunctionScoreQueryBuilder.FilterFunctionBuilder(QueryBuilders.matchQuery("goodsCategoryId", goodsCategoryId),
                        ScoreFunctionBuilders.weightFactorFunction(6)));
                FunctionScoreQueryBuilder.FilterFunctionBuilder[] builders = new FunctionScoreQueryBuilder.FilterFunctionBuilder[filterFunctionBuilders.size()];
                filterFunctionBuilders.toArray(builders);
                FunctionScoreQueryBuilder functionScoreQueryBuilder = QueryBuilders.functionScoreQuery(builders)
                        .scoreMode(FunctionScoreQuery.ScoreMode.SUM)
                        .setMinScore(2);
                NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
                builder.withQuery(functionScoreQueryBuilder);
                builder.withPageable(pageable);
                NativeSearchQuery searchQuery = builder.build();
                log.info("DSL:{}", searchQuery.getQuery().toString());
                return productRepository.search(searchQuery);
            }
            return new PageImpl<>(null);
        }
    

参考代码以及接口文档

Github

Swagger UI 文档

总结

知识只有分享出来才有价值。如果有问题的话,可以在关于我的页面,通过我的邮箱联系我进行探讨。

<p> <br /> </p> <p style="color:#333333;"> <strong>Elasticsearch 简介</strong> </p> <p style="color:#333333;"> ElasticSearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口。Elasticsearch是用Java开发的,并作为Apache许可条款下的开放源码发布,是当前流行的企业级搜索引擎。设计用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便。 </p> <p style="color:#333333;"> <br /> </p> <p style="color:#333333;"> <strong>elasticSearch 的使用场景</strong> </p> <p style="color:#333333;"> 1、在海量数据前提下,对数据进行检索。比如:京东,淘宝等电商项目 </p> <p style="color:#333333;"> <br /> </p> <p style="color:#333333;"> <strong>课程目标:</strong> </p> <p style="color:#333333;"> 1. 了解企业级搜索引擎 </p> <p style="color:#333333;"> 2. 安装elasticsearch {linux 系统} </p> <p style="color:#333333;"> 3. 安装kibana并利用kibana对Elasticsearch 索引中的数据进行搜索、查看、交互操作 </p> <p style="color:#333333;"> 4. 项目实战{ELK} </p> <p style="color:#333333;"> <br /> </p> <p style="color:#333333;"> <strong>课程目录:</strong> </p> <p style="color:#333333;"> 01 课程介绍<br /> 02 elasticsearch 简介<br /> 03 elasticsearch 使用场景<br /> 04 安装elasticsearch 之前先安装jdk<br /> 05 安装elasticsearch<br /> 06 测试elasticsearch是否安装成功 <br /> 07 安装kibana<br /> 08 elasticsearch 基本认识 以及添加索引和删除索引<br /> 09 elasticsearch 添加查询数据<br /> 10 elasticsearch 修改删除数据<br /> 11 elasticsearch 有条件的查询<br /> 12 分词子属性fuzzy查询<br /> 13 elasticsearch 过滤使用<br /> 14 elasticsearch 排序与分页<br /> 15 elasticsearch 如何查询指定的字段<br /> 16 elasticsearch 高亮显示<br /> 17 elasticsearch 聚合<br /> 18 elasticsearch mapping 概念<br /> 19 elasticsearch 的中文词库<br /> 20 elasticsearch 中文词库安装测试<br /> 21 elasticsearch 中文词库的使用案例<br /> 22 elasticsearch 自定义词库配置<br /> 23 安装nginx 配置中文词库<br /> 24 测试elasticsearch 自定义中文词库<br /> 25 搭建项目父工程<br /> 26 搭建项目bean-interface-common<br /> 27 搭建search 的service web 项目<br /> 28 测试项目是否能与elasticsearch联通<br /> 29 创建数据库并搭建首页<br /> 30 数据上传功能的实现类完成<br /> 31 数据上传控制器完成<br /> 32 dubbo 介绍以及安装zookeeper<br /> 33 将数据从mysql 上传到elasticsearch 中<br /> 34 elasticsearch查询功能分析<br /> 35 编写业务需求的dsl 语句<br /> 36 编写输入参数返回结果集的实体类<br /> 37 实现类编写<br /> 38 编写实现类中dsl 语句<br /> 39 返回集结果转换<br /> 40 结果测试<br /> 41 测试通过输入查询条件并将数据显示到页面 </p>
参与评论 您还未登录,请先 登录 后发表或查看评论

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

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页

打赏作者

在无人区看超市

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

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

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

打赏作者

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

抵扣说明:

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

余额充值