目录

需求分析

项目环境

API接口实现


需求分析

通过Elasticsearch完成商品列表查询和分类、品牌、规格参数的分组聚合统计查询

  1. 当用户输入关键字搜索后,查询出商品列表后点击右上角筛选按钮,能够展示该关键词下的全部商品分类(京东用的是二级分类,共3级分类)、品牌、和规格参数作为筛选条件。
  2. 商品分类支持单选、品牌支持多选、规格参数支持多选。
  3. 每当选中或取消选中筛选条件时,都能够实时更新筛选条件商品数量,并更新商品列表或点击确定更新。
  4. 注:这里需要注意的是,各个条件中的列表数据都会随着当前已选中的条件变化而变化,但当前操作的条件栏目(如:分类)中的数据是不变的(这里一般由前端控制),言外之意就是,这里的所有筛选条件都是从所有满足选中条件的商品中聚合出的数据,(例:当选中分类为【手机】时,需要重新调用获取查询条件的接口,这是接口返回的条件数据中分类类目中只有手机的分类,品牌类目里只有商品分类为手机的全部品牌,规格参数也同品牌一样,这样就实现了一个不断下钻聚合的过程)

项目环境

springboot + spring-boot-starter-data-elasticsearch(其中spring boot版本:2.1.6)

elasticsearch(版本:6.8.5)

这里环境搭建就不多赘述了,具体详看源代码


API接口实现

首先我们先实现商品列表的过滤分页查询接口

Spring Data Elasticsearch给我们提供了一系列的聚合查询方法

  1. 索引创建

    @Data
    @Document(indexName = "test", type = "product")
    //indexName索引名称 可以理解为数据库名 必须为小写 不然会报org.elasticsearch.indices.InvalidIndexNameException异常
    //type类型 可以理解为表名
    public class Product {/** @Name: 商品Id* @Example: 1* @Description:*/private Long id;/** @Name: 品牌名称* @Example: 小米* @Description:*/@Field(type = FieldType.Keyword)private String brand;/** @Name: 分类id (1-手机 | 2-笔记本)* @Example:* @Description:*/@Field(type = FieldType.Long)private Long category;/** @Name: 商品名称* @Example: 小米9pro 5G版手机 钛银黑 12G+512G* @Description:*/@Field(type = FieldType.Text)private String name;/** @Name: 商品规格* @Example: [{"attrName": "颜色","attrValue": "钛银黑"},{"attrName": "内存","attrValue": "512G"}]* @Description: 这里一定要使用nested(嵌套类型)* 【与object区别在于可以很好的处理数组对象的内部关系,在内部,嵌套对象将数组中的每个对象索引为单独的隐藏文档,这意味着可以独立于其他对象查询每个嵌套对象】* 详见:https://blog.csdn.net/laoyang360/article/details/82950393*/@Field(type = FieldType.Nested)private List<Attr> attrs;@Datapublic static class Attr{@Field(type = FieldType.Keyword)private String attrName;@Field(type = FieldType.Keyword)private String attrValue;}public interface FieldName {String ID = "id";String NAME = "name";String CATEGORY = "category";String BRAND = "brand";String ATTRS = "attrs";String ATTRS_NAME = "attrs.attrName";String ATTRS_VALUE = "attrs.attrValue";}}
  2. 首先定义查询参数
    @Data
    public class QueryVO {private Long id;/** @Name: 品牌名称* @Example: ["小米", "华为"]* @Description:*/private List<String> brands = Lists.newArrayList();/** @Name: 分类id (1-手机 | 2-笔记本)* @Example: 1* @Description:*/private Long category;/** @Name: 商品名称* @Example: 小米9pro 5G版手机 钛银黑 12G+512G* @Description:*/private String name;/** @Name: 规格参数* @Example: [{"attrName": "颜色","attrValues": ["黑色"]},{"attrName": "内存","attrValues": ["64G", "128G"]}]* @Description:*/private List<AggVO.AttrGroup> attrs = Lists.newArrayList();
    }
  3. 分页查询接口实现
        // 商品分页查询@Overridepublic Page<Product> search(QueryVO query, int page, int size) {Pageable pageable = PageRequest.of(page-1, size);return productRepository.search(this.addFilters(query), pageable);}// 过滤条件private BoolQueryBuilder addFilters(QueryVO query) {BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();List<AggVO.AttrGroup> attrGroups = query.getAttrs();if (attrGroups != null) {// 多属性过滤查询,如(内存、颜色、屏幕尺寸、版本等等)for (AggVO.AttrGroup attrGroup : attrGroups) {BoolQueryBuilder attrBoolQuery = QueryBuilders.boolQuery();attrBoolQuery.filter(QueryBuilders.matchQuery(Product.FieldName.ATTRS_NAME, attrGroup.getAttrName()));attrBoolQuery.filter(QueryBuilders.termsQuery(Product.FieldName.ATTRS_VALUE, attrGroup.getAttrValues())); // 这里多值匹配用【termsQuery】注意区分【termQuery】// 使用NestedQuery查询(嵌套对象的过滤查询)                NestedQueryBuilder nestedQueryBuilder = QueryBuilders.nestedQuery(Product.FieldName.ATTRS, attrBoolQuery, ScoreMode.None);boolQueryBuilder.filter(nestedQueryBuilder);}}if (query.getId() != null) {// 商品Id查询boolQueryBuilder.filter(QueryBuilders.matchQuery(Product.FieldName.ID, query.getId()).operator(Operator.AND));}if (!query.getBrands().isEmpty()) {// 品牌查询boolQueryBuilder.filter(QueryBuilders.termsQuery(Product.FieldName.BRAND, query.getBrands()));}if (query.getCategory() != null) {// 分类查询boolQueryBuilder.filter(QueryBuilders.matchQuery(Product.FieldName.CATEGORY, query.getCategory()).operator(Operator.AND));}if (StringUtils.isNotBlank(query.getName())) {// 商品名称查询(这里暂时没做分词处理)boolQueryBuilder.filter(QueryBuilders.matchQuery(Product.FieldName.NAME, query.getName()).operator(Operator.AND));}return boolQueryBuilder;}

    这里可以将filter查询替换成must查询,区别在于filter性能更好一些,must要进行打分评估,也就是说要进行_score,而filter则不会。

其次我们再实现筛选条件聚合的接口

通过TermsAggregationBuilder、NestedAggregationBuilder来实现字段和内置嵌套对象字段的分组统计查询,具体代码如下:

    // 筛选条件聚合查询接口@Overridepublic AggVO agg(QueryVO query) {Pageable pageable = PageRequest.of(0, 10);//检索条件BoolQueryBuilder boolQueryBuilder = this.addFilters(query);final String BRAND_AGG = "brand_agg";final String CATEGORY_AGG = "category_agg";final String ATTR_AGG = "attr_agg";final String ATTR_NAME_AGG = ATTR_AGG + "_name";final String ATTR_VALUE_AGG = ATTR_AGG+"_value";//聚合条件// 品牌聚合(取命中最多的前500个品牌)TermsAggregationBuilder brandAggBuilder = AggregationBuilders.terms(BRAND_AGG).field(Product.FieldName.BRAND).size(500);// 分类聚合(取命中最多的前20个)TermsAggregationBuilder categoryAggBuilder = AggregationBuilders.terms(CATEGORY_AGG).field(Product.FieldName.CATEGORY).size(20);// 内置对象-规格聚合NestedAggregationBuilder attrAggBuilder = AggregationBuilders.nested(ATTR_AGG, Product.FieldName.ATTRS);// 先聚合规格名称TermsAggregationBuilder attrNameAggBuilder = AggregationBuilders.terms(ATTR_NAME_AGG).field(Product.FieldName.ATTRS_NAME);// 再将名称分组后聚合规格值(取命中最多的前7个规格,聚合分组规格后再在每个分组规格中取命中最多的前15个参数值)attrNameAggBuilder.subAggregation(AggregationBuilders.terms(ATTR_VALUE_AGG).field(Product.FieldName.ATTRS_VALUE).size(15)).size(7);attrAggBuilder.subAggregation(attrNameAggBuilder);//构建查询SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(boolQueryBuilder) // 过滤条件.addAggregation(brandAggBuilder) // 品牌聚合.addAggregation(categoryAggBuilder) // 分类聚合.addAggregation(attrAggBuilder) // 规格参数聚合.withPageable(pageable) // 分页.build();AggregatedPage<Product> search = (AggregatedPage)productRepository.search(searchQuery);AggVO aggVO = new AggVO();// 符合条件的商品总数量aggVO.setTotalNum(search.getTotalElements());// 品牌聚合结果Terms brandAgg = (Terms)search.getAggregation(BRAND_AGG);for (Terms.Bucket bucket : brandAgg.getBuckets()) {String brandName = bucket.getKeyAsString();aggVO.getBrands().add(brandName);}// 分类聚合结果Terms categoryAgg = (Terms)search.getAggregation(CATEGORY_AGG);for (Terms.Bucket bucket : categoryAgg.getBuckets()) {long categoryId = bucket.getKeyAsNumber().longValue();aggVO.getCategories().add(categoryId);}// 规格参数聚合结果InternalNested attrNested = (InternalNested)search.getAggregation(ATTR_AGG);Map<String, Aggregation> aggregationMap = attrNested.getAggregations().asMap();Terms attrNameAgg = (Terms)aggregationMap.get(ATTR_NAME_AGG);for (Terms.Bucket bucket : attrNameAgg.getBuckets()) {String attrName = bucket.getKeyAsString();AggVO.AttrGroup attrGroup = new AggVO.AttrGroup();attrGroup.setAttrName(attrName);Terms attrValueAgg = (Terms)bucket.getAggregations().asMap().get(ATTR_VALUE_AGG);for (Terms.Bucket subBucket : attrValueAgg.getBuckets()) {String attrValue = subBucket.getKeyAsString();attrGroup.getAttrValues().add(attrValue);}aggVO.getAttrs().add(attrGroup);}search.getAggregation(CATEGORY_AGG);return aggVO;}

最后再附上源代码:https://gitee.com/wangsai1109/springboot-es.git

Elasticsearch仿京东、淘宝APP客户端的商品侧边栏筛选条件过滤和分页列表查询的实现案例相关推荐

  1. 菜鸟窝-仿京东淘宝项目学习笔记(二)ToolBar的基本使用

    本篇知识点均来自于菜鸟窝-仿京东淘宝实战项目视频中 今天继续仿京东淘宝项目的学习,第二天,学习ToolBar的基本使用,本篇记录视频中一些重要的笔记 笔记一:ToolBar的一些重要属性 xml st ...

  2. 微信小程序仿京东淘宝商品排序

    微信小程序仿京东淘宝商品排序 效果图如下所示 仿京东微信小程序视频请加QQ:1010753897 下载地址:https://download.csdn.net/download/qq_43764578 ...

  3. 仿京东淘宝等首页广告弹窗广告 dialog

    记录贴 防止以后忘记. 上图 1.dialog布局 图片随便找的 <?xml version="1.0" encoding="utf-8"?> &l ...

  4. Android 仿京东淘宝拼多多的商品分类,双列表联动,RecyclerView嵌套

    淘宝京东的相对简单很多,两个RecyclerView就可实现了. 现在要做的是右边滑动的时候左边跟着联动,如下图: 思路:左右肯定都是RecyclerView了,至于中间的图片嘛当然也是Recycle ...

  5. Android 仿京东淘宝 商品详情页 商品图片效果

    最近重构商品,产品要求,按照淘宝京东来.... 成品如图这个效果 思路就是监听外边ScrollView的滑动监听,然后给上边图片设置margin,二话不说上代码 简单的界面布局 <?xml ve ...

  6. 仿京东淘宝放大镜特效 jqzoom.js

    效果图如下: HTML 文本源码: 1 <!DOCTYPE html> 2 <htmllang="en"> 3 <head> 4 <met ...

  7. Android 仿京东淘宝多规格选择

    上图直接点,下次在修改理论,因为要下班了 这是淘宝的规格选择,我随便选择了一个,将就着看吧 然后再来看看我的效果 这个我是在CSDN上看的一篇文章 我把地址贴出来这是原文地址我是在他的基础改的 我做了 ...

  8. Android自定义控件-仿淘宝ios客户端天猫商品详情界面

    仿照淘宝和聚美优品,在商品详情页,向上拖动时,可以加载下一页.使用ViewDragHelper,滑动比较流畅. scrollView滑动到底部的时候,再行向上拖动时,添加了一些阻力. 项目地址:htt ...

  9. JQ或JS仿京东淘宝属性规格SKU样式

    <!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8" ...

最新文章

  1. mac apache 配置
  2. Quorum-based voting
  3. 纪念自己的第四个App:秘密Secret
  4. 太逗了,面试官让我讲线程 WAITING 状态!
  5. 关于一些对location认识的误区(转)
  6. 计算机网络 | 传输层 :UDP与TCP协议详解
  7. python编程数学函数_【编程】Python数学函数
  8. Android RadioButton 语言切换问题
  9. 计算机telnet命令大全,Telnet命令
  10. ADC驱动器/差分放大器设计指南
  11. 网络版瑞星服务器无法升级
  12. rpm 打包及其命令
  13. 用什么词典可以翻译php,PHP调用有道词典翻译API实现翻译功能及代码
  14. RPG游戏Demo学习笔记一
  15. android 第三方SDK接入一般流程
  16. Java基础篇--继承(inherit),多态(Polymorphism)
  17. python学习之 re库 正则表达式
  18. 金山词霸 v10.4.5 for Android
  19. 机器学习——监督学习之决策树分类模型
  20. 基于51单片机PM2.5空气质量检测仪设计(毕设)

热门文章

  1. Qt嵌入浏览器开发——下载编译
  2. 【软件评测师21天-考点整理】8)软件工程
  3. 云原生之kubectl命令详解
  4. 你真的明白斯卡布罗集市歌词的真正含义吗?
  5. 如何让APP不在settings/Notifications/Recently sent中显示(MTK6757 Android9.0)
  6. linux服务器监控信息,Linux 服务器监控
  7. [转载]历史需要不断解读
  8. 图形和图像计算机基础知识,计算机图形图像基础
  9. 文件属性、用户管理、权限
  10. 网站制作-LAMP环境(分离部署)