当前位置: 首页 > news >正文

分布式专题——50 电商项目仿京东商品搜索服务实战

1 业务场景——电商商城商品搜索

  • 对于平台中的商品,可以根据关键字査询、品牌、商品类别、商品属性信息、价格区间、是否有库存筛选査询,根据销量、价格、上架时间等排序。

2 商品文档建模

2.1 商品文档

{"id": "26","name": "小米 11 手机","keywords": "小米手机","subTitle": "AI智慧全面屏 6GB +64GB 亮黑色 全网通版 移动联通电信4G手机 双卡双待 双卡双待","price": "3999","promotionPrice": "2999","originalPrice": "5999","pic": "http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/images/20180615/xiaomi.jpg","sale": 999,"hasStock": true,"salecount":999,"putawayDate":"2021-04-01","brandId": 6,"brandName": "小米","brandImg": "http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/images/20190129/1e34aef2a409119018a4c6258e39ecfb_222_222.png","categoryId": 19,"categoryName": "手机通讯","attrs": [{"attrId": 1,"attrName": "cpu","attrValue": "2核"},{"attrId": 2,"attrName": "颜色","attrValue": "黑色"}]
}{"id": "30","name": "HLA海澜之家简约动物印花短袖T恤","keywords": "海澜之家衣服","subTitle": "HLA海澜之家短袖T恤","price": "199","promotionPrice": "99","originalPrice": "299","pic": "http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/images/20180615/5ad83a4fN6ff67ecd.jpg!cc_350x449.jpg","sale": 999,"hasStock": true,"salecount":19,"putawayDate":"2021-04-05","brandId": 50,"brandName": "海澜之家","brandImg": "http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/images/20190129/99d3279f1029d32b929343b09d3c72de_222_222.jpg","categoryId": 8,"categoryName": "T恤","attrs": [{"attrId": 3,"attrName": "尺寸","attrValue": "M"},{"attrId": 4,"attrName": "颜色","attrValue": "黑色"}]
}

2.2 建模分析

  • name(商品名称)、keywords(搜索关键词)、subTitle(商品副标题)需使用中文分词器(如 IK 分词器)。原因是中文词汇需要拆分(如“小米 11 手机”拆为“小米”“11”“手机”),才能支持用户的关键词模糊搜索(如搜“小米手机”能命中该商品);

  • categoryName(分类名称)、brandName(品牌名称)等字段类型设为 keywordkeyword 类型是不分词的精确类型,适合用于筛选、聚合、精确匹配场景(如筛选“手机通讯”分类下的商品,或统计各品牌商品数量);

  • 不同商品属性不同(如手机有“cpu”,衣服有“尺寸”),且属性与商品是关联关系,同时属性“不会频繁更新”。因此选择 nested 类型(嵌套类型),它能保持文档存储的紧凑性,且适配“以查询为主、更新较少”的场景;

  • 嵌套文档 vs 父子文档

    维度Nested Object(嵌套文档)Parent / Child(父子文档)
    优点文档存储在一起,读取性能高子文档可以独立更新(无需更新整个父文档)
    缺点更新嵌套的子文档时,需要更新整个文档需要额外内存维护关系,读取性能相对差
    适用场景子文档偶尔更新,以查询为主子文档更新频繁
  • 结合电商商品属性的场景(属性不频繁更新,查询需求多),所以商品属性 attrs 选择 nested 类型是合理的。

2.3 Mapping 定义(索引结构)

PUT product_db
{"mappings": {"properties": {"id": {"type": "long"},"name": {// 类型 text,并指定分词器 ik_max_word(IK 分词的“细粒度分词”模式,最大化拆分词汇,提升搜索召回率)"type": "text","analyzer": "ik_max_word"},"keywords": {"type": "text","analyzer": "ik_max_word"},"subTitle": {"type": "text","analyzer": "ik_max_word"},"salecount":{"type": "long"},"putawayDate":{"type": "date"},"price": {"type": "double"},// 类型 keyword,若仅用于精确匹配或聚合(如“按原价区间筛选”),用 keyword 保证精确性"promotionPrice": {"type": "keyword"},"originalPrice": {"type": "keyword"},"pic": {"type": "keyword"},"sale": {"type": "long"},"hasStock": {"type": "boolean"},"brandId": {"type": "long"},// 类型 keyword,存储品牌、分类名称,支持精确筛选、聚合(如 “统计各品牌商品数量”)"brandName": {"type": "keyword"},"brandImg": {"type": "keyword"},"categoryId": {"type": "long"},"categoryName": {"type": "keyword"},"attrs": {"type": "nested","properties": {"attrId": {"type": "long"},"attrName": {"type": "keyword"},"attrValue": {"type": "keyword"}}}}}
}

2.4 测试数据

PUT /product_db/_doc/1
{"id": "26","name": "小米 11 手机","keywords": "小米手机","subTitle": "AI智慧全面屏 6GB +64GB 亮黑色 全网通版 移动联通电信4G手机 双卡双待 双卡双待","price": "3999","promotionPrice": "2999","originalPrice": "5999","pic": "http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/images/20180615/xiaomi.jpg","sale": 999,"hasStock": true,"salecount":999,"putawayDate":"2021-04-01","brandId": 6,"brandName": "小米","brandImg": "http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/images/20190129/1e34aef2a409119018a4c6258e39ecfb_222_222.png","categoryId": 19,"categoryName": "手机通讯","attrs": [{"attrId": 1,"attrName": "cpu","attrValue": "2核"},{"attrId": 2,"attrName": "颜色","attrValue": "黑色"}]
}PUT /product_db/_doc/2
{"id": "27","name": "小米 10 手机","keywords": "小米手机","subTitle": "AI智慧全面屏 4GB +64GB 亮白色 全网通版 移动联通电信4G手机 双卡双待 双卡双待","price": "2999","promotionPrice": "1999","originalPrice": "3999","pic": "http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/images/20180615/xiaomi.jpg","sale": 999,"hasStock": false,"salecount":99,"putawayDate":"2021-04-02","brandId": 6,"brandName": "小米","brandImg": "http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/images/20190129/1e34aef2a409119018a4c6258e39ecfb_222_222.png","categoryId": 19,"categoryName": "手机通讯","attrs": [{"attrId": 1,"attrName": "cpu","attrValue": "4核"},{"attrId": 2,"attrName": "颜色","attrValue": "白色"}]
}
PUT /product_db/_doc/3
{"id": "28","name": "小米  手机","keywords": "小米手机","subTitle": "AI智慧全面屏 4GB +64GB 亮蓝色 全网通版 移动联通电信4G手机 双卡双待 双卡双待","price": "2999","promotionPrice": "1999","originalPrice": "3999","pic": "http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/images/20180615/xiaomi.jpg","sale": 999,"hasStock": true,"salecount":199,"putawayDate":"2021-04-03","brandId": 6,"brandName": "小米","brandImg": "http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/images/20190129/1e34aef2a409119018a4c6258e39ecfb_222_222.png","categoryId": 19,"categoryName": "手机通讯","attrs": [{"attrId": 1,"attrName": "cpu","attrValue": "2核"},{"attrId": 2,"attrName": "颜色","attrValue": "蓝色"}]
}
PUT /product_db/_doc/4
{"id": "29","name": "Apple iPhone 8 Plus 64GB 金色特别版 移动联通电信4G手机","keywords": "苹果手机","subTitle": "苹果手机 Apple产品年中狂欢节,好物尽享,美在智慧!速来 >> 勾选[保障服务][原厂保2年],获得AppleCare+全方位服务计划,原厂延保售后无忧。","price": "5999","promotionPrice": "4999","originalPrice": "7999","pic": "http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/images/20180615/5acc5248N6a5f81cd.jpg","sale": 999,"hasStock": true,"salecount":1199,"putawayDate":"2021-04-04","brandId": 51,"brandName": "苹果","brandImg": "http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/images/20180607/timg.jpg","categoryId": 19,"categoryName": "手机通讯","attrs": [{"attrId": 1,"attrName": "cpu","attrValue": "4核"},{"attrId": 2,"attrName": "颜色","attrValue": "金色"}]
}
PUT /product_db/_doc/5
{"id": "30","name": "HLA海澜之家简约动物印花短袖T恤","keywords": "海澜之家衣服","subTitle": "HLA海澜之家短袖T恤","price": "199","promotionPrice": "99","originalPrice": "299","pic": "http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/images/20180615/5ad83a4fN6ff67ecd.jpg!cc_350x449.jpg","sale": 999,"hasStock": true,"salecount":19,"putawayDate":"2021-04-05","brandId": 50,"brandName": "海澜之家","brandImg": "http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/images/20190129/99d3279f1029d32b929343b09d3c72de_222_222.jpg","categoryId": 8,"categoryName": "T恤","attrs": [{"attrId": 3,"attrName": "尺寸","attrValue": "M"},{"attrId": 4,"attrName": "颜色","attrValue": "黑色"}]
}
PUT /product_db/_doc/6
{"id": "31","name": "HLA海澜之家蓝灰花纹圆领针织布短袖T恤","keywords": "海澜之家衣服","subTitle": "HLA海澜之家短袖T恤","price": "299","promotionPrice": "199","originalPrice": "299","pic": "http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/images/20180615/5ac98b64N70acd82f.jpg!cc_350x449.jpg","sale": 999,"hasStock": true,"salecount":399,"putawayDate":"2021-04-06","brandId": 50,"brandName": "海澜之家","brandImg": "http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/images/20190129/99d3279f1029d32b929343b09d3c72de_222_222.jpg","categoryId": 8,"categoryName": "T恤","attrs": [{"attrId": 3,"attrName": "尺寸","attrValue": "X"},{"attrId": 4,"attrName": "颜色","attrValue": "蓝灰"}]
}
PUT /product_db/_doc/7
{"id": "32","name": "HLA海澜之家短袖T恤男基础款","keywords": "海澜之家衣服","subTitle": "HLA海澜之家短袖T恤","price": "269","promotionPrice": "169","originalPrice": "399","pic": "http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/images/20180615/5a51eb88Na4797877.jpg","sale": 999,"hasStock": true,"salecount":399,"putawayDate":"2021-04-07","brandId": 50,"brandName": "海澜之家","brandImg": "http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/images/20190129/99d3279f1029d32b929343b09d3c72de_222_222.jpg","categoryId": 8,"categoryName": "T恤","attrs": [{"attrId": 3,"attrName": "尺寸","attrValue": "L"},{"attrId": 4,"attrName": "颜色","attrValue": "蓝色"}]
}
PUT /product_db/_doc/8
{"id": "33","name": "小米(MI)小米电视4A ","keywords": "小米电视机家用电器","subTitle": "小米(MI)小米电视4A 55英寸 L55M5-AZ/L55M5-AD 2GB+8GB HDR 4K超高清 人工智能网络液晶平板电视","price": "2269","promotionPrice": "2169","originalPrice": "2399","pic": "http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/images/20180615/5b02804dN66004d73.jpg","sale": 999,"hasStock": true,"salecount":132,"putawayDate":"2021-04-09","brandId": 6,"brandName": "小米","brandImg": "http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/images/20190129/1e34aef2a409119018a4c6258e39ecfb_222_222.png","categoryId": 35,"categoryName": "手机数码","attrs": [{"attrId": 5,"attrName": "屏幕尺寸","attrValue": "52"},{"attrId": 6,"attrName": "机身颜色","attrValue": "黑色"}]
}
PUT /product_db/_doc/9
{"id": "34","name": "小米(MI)小米电视4A 65英寸","keywords": "小米电视机家用电器","subTitle": "小米(MI)小米电视4A 65英寸 L55M5-AZ/L55M5-AD 2GB+8GB HDR 4K超高清 人工智能网络液晶平板电视","price": "3269","promotionPrice": "3169","originalPrice": "3399","pic": "http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/images/20180615/5b028530N51eee7d4.jpg","sale": 999,"hasStock": true,"salecount":999,"putawayDate":"2021-04-10","brandId": 6,"brandName": "小米","brandImg": "http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/images/20190129/1e34aef2a409119018a4c6258e39ecfb_222_222.png","categoryId": 35,"categoryName": "手机数码","attrs": [{"attrId": 5,"attrName": "屏幕尺寸","attrValue": "65"},{"attrId": 6,"attrName": "机身颜色","attrValue": "金色"}]
}
PUT /product_db/_doc/10
{"id": "35","name": "耐克NIKE 男子 休闲鞋 ROSHE RUN 运动鞋 511881-010黑色41码","keywords": "耐克运动鞋 鞋子","subTitle": "耐克NIKE 男子 休闲鞋 ROSHE RUN 运动鞋 511881-010黑色41码","price": "569","promotionPrice": "369","originalPrice": "899","pic": "http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/images/20180615/5b235bb9Nf606460b.jpg","sale": 999,"hasStock": true,"salecount":399,"putawayDate":"2021-04-11","brandId": 58,"brandName": "NIKE","brandImg": "http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/images/20180615/timg (51).jpg","categoryId": 29,"categoryName": "男鞋","attrs": [{"attrId": 7,"attrName": "尺码","attrValue": "42"},{"attrId": 8,"attrName": "颜色","attrValue": "黑色"}]
}
PUT /product_db/_doc/11
{"id": "36","name": "耐克NIKE 男子 气垫 休闲鞋 AIR MAX 90 ESSENTIAL 运动鞋 AJ1285-101白色41码","keywords": "耐克运动鞋 鞋子","subTitle": "AIR MAX 90 ESSENTIAL 运动鞋 AJ1285-101白色","price": "769","promotionPrice": "469","originalPrice": "999","pic": "http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/images/20180615/5b19403eN9f0b3cb8.jpg","sale": 999,"hasStock": true,"salecount":499,"putawayDate":"2021-04-13","brandId": 58,"brandName": "NIKE","brandImg": "http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/images/20180615/timg (51).jpg","categoryId": 29,"categoryName": "男鞋","attrs": [{"attrId": 7,"attrName": "尺码","attrValue": "44"},{"attrId": 8,"attrName": "颜色","attrValue": "白色"}]
}
PUT /product_db/_doc/12
{"id": "37","name": "(华为)HUAWEI MateBook X Pro 2019款 13.9英寸3K触控全面屏 轻薄笔记本","keywords": "轻薄笔记本华为 笔记本电脑","subTitle": "轻薄华为笔记本 电脑","price": "4769","promotionPrice": "4469","originalPrice": "4999","pic": "http://shisan-mall.oss-cn-shenzhen.aliyuncs.com/shisanmall/images/20200317/800_800_1555752016264mp.png","sale": 999,"hasStock": true,"salecount":699,"putawayDate":"2021-04-14","brandId": 3,"brandName": "华为","brandImg": "http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/images/20190129/17f2dd9756d9d333bee8e60ce8c03e4c_222_222.jpg","categoryId": 19,"categoryName": "手机通讯","attrs": [{"attrId": 9,"attrName": "容量","attrValue": "16G"},{"attrId": 10,"attrName": "网络","attrValue": "4G"}]
}
PUT /product_db/_doc/13
{"id": "38","name": "华为nova6se 手机 绮境森林 全网通(8G+128G)","keywords": "轻薄笔记本华为 手机","subTitle": "华为nova6se 手机","price": "6769","promotionPrice": "6469","originalPrice": "6999","pic": "http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/images/20180607/5ac1bf58Ndefaac16.jpg","sale": 999,"hasStock": true,"salecount":899,"putawayDate":"2021-04-15","brandId": 3,"brandName": "华为","brandImg": "http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/images/20190129/17f2dd9756d9d333bee8e60ce8c03e4c_222_222.jpg","categoryId": 19,"categoryName": "手机通讯","attrs": [{"attrId": 9,"attrName": "容量","attrValue": "64G"},{"attrId": 10,"attrName": "网络","attrValue": "5G"}]
}
PUT /product_db/_doc/14
{"id": "39","name": "iPhone7/6s/8钢化膜苹果8Plus全屏复盖抗蓝光防窥防偷看手机膜","keywords": "手机膜","subTitle": "iPhone7/6s/8钢化膜苹果8Plus全屏复盖抗蓝光防窥防偷看手机膜","price": "29","promotionPrice": "39","originalPrice": "49","pic": "http://shisan-mall.oss-cn-shenzhen.aliyuncs.com/shisanmall/images/20200311/6df99dab78bb2014.jpg","sale": 999,"hasStock": true,"salecount":799,"putawayDate":"2021-04-16","brandId": 51,"brandName": "苹果","brandImg": "http://shisan-mall.oss-cn-shenzhen.aliyuncs.com/shisanmall/images/20200311/2b84746650fc122d67749a876c453619.png","categoryId": 30,"categoryName": "手机配件","attrs": [{"attrId": 11,"attrName": "手机膜-材料","attrValue": "钢化"},{"attrId": 12,"attrName": "手机膜-颜色","attrValue": "白色"}]
}PUT /product_db/_doc/15
{"id": "40","name": "七匹狼短袖T恤男纯棉舒适春夏修身运动休闲短袖三条装 圆领3条装","keywords": "七匹狼服装 衣服","subTitle": "七匹狼短袖T恤男纯棉舒适春夏修身运动休闲短袖三条装 圆领3条装","price": "129","promotionPrice": "139","originalPrice": "149","pic": "http://shisan-mall.oss-cn-shenzhen.aliyuncs.com/shisanmall/images/20200311/19e846e727dff337.jpg","sale": 999,"hasStock": true,"salecount":199,"putawayDate":"2021-04-20","brandId": 49,"brandName": "七匹狼","brandImg": "http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/images/20190129/18d8bc3eb13533fab466d702a0d3fd1f40345bcd.jpg","categoryId": 8,"categoryName": "T恤","attrs": [{"attrId": 3,"attrName": "尺寸","attrValue": "M"},{"attrId": 4,"attrName": "颜色","attrValue": "白色"}]
}
PUT /product_db/_doc/16
{"id": "41","name": "华为P40 Pro手机","keywords": "华为手机","subTitle": "华为P40 Pro手机","price": "2129","promotionPrice": "2139","originalPrice": "2149","pic": "http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/images/20180607/5ac1bf58Ndefaac16.jpg","sale": 999,"hasStock": true,"salecount":199,"putawayDate":"2021-05-03","brandId": 3,"brandName": "华为","brandImg": "http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/images/20190129/17f2dd9756d9d333bee8e60ce8c03e4c_222_222.jpg","categoryId": 19,"categoryName": "手机通讯","attrs": [{"attrId": 9,"attrName": "容量","attrValue": "128G"},{"attrId": 10,"attrName": "网络","attrValue": "5G"}]
}
PUT /product_db/_doc/17
{"id": "42","name": "朵唯智能手机 4G全网通 老人学生双卡双待手机","keywords": "朵唯手机","subTitle": "朵唯手机后置双摄,国产虎贲芯片!优化散热结构!浅薄机身!朵唯4月特惠!","price": "3129","promotionPrice": "3139","originalPrice": "3249","pic": "http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/images/20180615/xiaomi.jpg","sale": 999,"hasStock": true,"salecount":1199,"putawayDate":"2021-06-01","brandId": 59,"brandName": "朵唯","brandImg": "http://shisan-mall.oss-cn-shenzhen.aliyuncs.com/shisanmall/images/20200311/2b84746650fc122d67749a876c453619.png","categoryId": 19,"categoryName": "手机通讯","attrs": [{"attrId": 9,"attrName": "容量","attrValue": "32G"},{"attrId": 10,"attrName": "网络","attrValue": "4G"}]
}

3 构建DSL语句实现商品搜索

POST /product_db/_doc/_search
{"from": 0, // 从第 0 条数据开始(即第一页)"size": 8, // 每页返回 8 条结果"query": {"bool": { // 查询组合多条件"must": [ // 参与算分(影响结果排序权重),用于“用户输入的关键词匹配”{"match": { // match查询,在name字段中匹配关键词“手机”(如“小米 11 手机”会被命中)"name": {"query": "手机"}}}],"filter": [ // 不参与算分,仅用于筛选,性能更优(可缓存),用于“库存、价格范围”等过滤条件{"term": { // 筛选hasStock: true(有库存)的商品(term用于精确匹配,适合boolean、keyword类型字段)"hasStock": {"value": true}}},{"range": { // 筛选价格在指定区间的商品,支持数值范围过滤(电商常见的“价格筛选”功能)"price": {"from": "1","to": "5000"}}}]}},"sort": [{"salecount": { // 基于salecount(销量)字段排序"order": "asc" // 升序,从低销量到高销量}}],"aggregations": { // 聚合:用于实现电商搜索中的 “筛选条件面板”(如品牌列表、分类列表、属性列表)"brand_agg": {"terms": { // 按brandId分组(terms聚合),获取前 50/10 个品牌 ID"field": "brandId","size": 50},// 品牌聚合:子聚合brand_name_agg/brand_img_agg:关联查询每个品牌 ID 对应的brandName和brandImg(用于前端展示品牌名称和logo)"aggregations": {"brand_name_agg": {"terms": {"field": "brandName"}},"brand_img_agg": {"terms": {"field": "brandImg"}}}},// 分类聚合:按categoryId分组。min_doc_count: 1:只返回至少有 1 条数据的分类(过滤无结果的分类)"category_agg": {"terms": {"field": "categoryId","size": 50,"min_doc_count": 1},"aggregations": {"category_name_agg": { // 关联查询分类名称"terms": {"field": "categoryName"}}}},// 属性聚合:因attrs是nested类型(嵌套文档),需先用nested聚合指定路径path: "attrs",否则无法访问嵌套字段"attr_agg": {"nested": {"path": "attrs"},// 按attrs.attrId分组,子聚合获取attrName和attrValue(如:“颜色:黑色”“尺寸:M”)"aggregations": {"attr_id_agg": {"terms": {"field": "attrs.attrId"},"aggregations": {"attr_name_agg": {"terms": {"field": "attrs.attrName"}},"attr_value_agg": {"terms": {"field": "attrs.attrValue"}}}}}}},// 高亮显示:用于在搜索结果中突出显示匹配的关键词(提升用户体验)"highlight": {"pre_tags": ["<b style='color:red'>"],"post_tags": ["</b>"],"fields": {"name": {}}}
}
GET product_db/_search
{"from": 0,"size": 20, // 每页返回 20 条结果"query": {"bool": {"must": [{"multi_match": { // multi_match查询,在name、keywords、subTitle三个字段中同时匹配“手机”(扩大搜索范围,比如keywords含“手机”的商品也会被召回,提升搜索召回率)"query": "手机","fields": ["name","keywords","subTitle"]}}],"filter": [{"term": {"hasStock": "true"}},{"range": {"price": {"gte": 2000,"lte": 5000}}}]}},"aggs": {"brandId_aggs": {"terms": {"field": "brandId","size": 10},"aggs": {"brandName_aggs": {"terms": {"field": "brandName"}},"brandImg_aggs": {"terms": {"field": "brandImg"}}}},"categoryId_aggs": {"terms": {"field": "categoryId","size": 10},"aggs": {"categoryName_aggs": {"terms": {"field": "categoryName"}}}},"attrs_aggs": {"nested": {"path": "attrs"},"aggs": {"attrId_aggs": {"terms": {"field": "attrs.attrId"},"aggs": {"attrName_aggs": {"terms": {"field": "attrs.attrName"}},"attrValue_aggs": {"terms": {"field": "attrs.attrValue"}}}}}}},"sort": [{"salecount": {"order": "desc" // 降序,从高销量到低销量,更符合电商“按销量排序”的主流需求}}], "highlight": {"fields": {"*": {}}}
}

4 微服务实现商品搜索功能

  • 引入依赖:

    <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-elasticsearch</artifactId>
    </dependency>
    
  • 核心代码:

    @Service(value = "shisanMallSearchService")
    public class shisanMallSearchServiceImpl implements shisanMallSearchService {@Qualifier("elasticsearchClient")@Autowired // 注入ElasticsearchClientElasticsearchClient client;// 对外提供的搜索入口方法@Overridepublic ESResponseResult search(ESRequestParam param) {try {// 构建 ES 查询请求SearchRequest searchRequest = startBuildRequestParam(param);// 执行查询,获取SearchResponseSearchResponse response = client.search(searchRequest, EsProduct.class);System.out.println("response:" + response);// 解析响应结果,封装为ESResponseResult并返回ESResponseResult responseResult = startBuildResponseResult(response, param);return responseResult;} catch (Exception e) {e.printStackTrace();}return null;}// 查询请求构建// 该方法将前端参数(如关键词、价格范围、筛选条件等)转换为 ES 的SearchRequest// 包含查询条件、排序、分页、高亮、聚合五大核心逻辑private SearchRequest startBuildRequestParam(ESRequestParam param) {SearchRequest.Builder searchRequestBuilder = new SearchRequest.Builder();// 使用BoolQuery.Builder构建多条件组合查询,区分must(算分)和filter(过滤,不算分)BoolQuery.Builder boolQueryBuilder = new BoolQuery.Builder();// 关键词匹配(must子句)if (!StringUtils.isEmpty(param.getKeyword())) {// 单字段查询//            boolQueryBuilder.must(QueryBuilders.match(//                    m->m.field("name").query(param.getKeyword())//            ));// 多字段查询// 传入keyword(如 “手机”),使用multi_match查询,在name、keywords、subTitle三个字段中同时匹配boolQueryBuilder.must(m->m.multiMatch(q->q.fields("name", "keywords", "subTitle").query(param.getKeyword())));}// 过滤条件(filter子句):包含分类、品牌、属性、库存、价格等筛选逻辑,均不影响相关性得分// 分类筛选:通过term查询匹配categoryId(如筛选“手机通讯”分类)if (null != param.getCategoryId()) {boolQueryBuilder.filter(QueryBuilders.term(t -> t.field("categoryId").value(param.getCategoryId())));}// 品牌筛选:通过terms查询匹配多个brandId(如同时筛选“小米”“华为”)if (null != param.getBrandId() && param.getBrandId().size() > 0) {List<FieldValue> brandIds = param.getBrandId().stream().map(b -> FieldValue.of(b)).collect(Collectors.toList());boolQueryBuilder.filter(QueryBuilders.terms(t -> t.field("brandId").terms(v -> v.value(brandIds))));}// 属性筛选:针对attrs嵌套字段,使用nested查询 +bool组合条件(如“颜色 = 黑色且尺寸 = M”),需指定path: "attrs"if (param.getAttrs() != null && param.getAttrs().size() > 0) {param.getAttrs().forEach(item -> {// attrs参数格式:属性ID_属性值,多个值用冒号分隔,如 1_黑色:白色&2_8核:4核BoolQuery.Builder boolQuery = QueryBuilders.bool();// attrs=1_64GString[] s = item.split("_");String attrId = s[0];String[] attrValues = s[1].split(":"); // 这个属性检索用的值boolQuery.filter(QueryBuilders.term(t -> t.field("attrs.attrId").value(attrId)));List<FieldValue> attrValueList = Arrays.stream(attrValues).map(b -> FieldValue.of(b)).collect(Collectors.toList());boolQuery.filter(QueryBuilders.terms(t -> t.field("attrs.attrValue").terms(v -> v.value(attrValueList))));NestedQuery.Builder nestedQueryBuilder = new NestedQuery.Builder();// nested查询nestedQueryBuilder.path("attrs").query(q -> q.bool(boolQuery.build())).scoreMode(ChildScoreMode.None);boolQueryBuilder.filter(q -> q.nested(nestedQueryBuilder.build()));});}// 库存筛选:term查询匹配hasStock(true/false)if (null != param.getHasStock()) {boolQueryBuilder.filter(QueryBuilders.term(t -> t.field("hasStock").value(param.getHasStock() == 1)));}// 价格范围筛选:解析price参数(格式如 “1000_5000”“3000”“2000”),通过range查询实现gte(大于等于)、lte(小于等于)逻辑if (!StringUtils.isEmpty(param.getPrice())) {// 价格的输入形式为:10_100(起始价格和最终价格)或_100(不指定起始价格)或10_(不限制最终价格)RangeQuery.Builder rangeQueryBuilder = QueryBuilders.range().field("price");String[] price = param.getPrice().split("_");if (price.length == 2) {// price: _5000   [, 5000]if (param.getPrice().startsWith("_")) {rangeQueryBuilder.lte(JsonData.of(price[1]));} else {// price: 1_5000  [1, 5000]rangeQueryBuilder.gte(JsonData.of(price[0])).lte(JsonData.of(price[1]));}} else if (price.length == 1) {// price: 1_     [1]if (param.getPrice().endsWith("_")) {rangeQueryBuilder.gte(JsonData.of(price[0]));}}boolQueryBuilder.filter(r -> r.range(rangeQueryBuilder.build()));}// 封装所有查询条件searchRequestBuilder.query(q -> q.bool(boolQueryBuilder.build()));// 排序(sort):解析前端传入的sort参数(格式如 “salecount_asc”“price_desc”),转换为 ES 排序条件// 按字段(如salecount销量、price价格)和方向(asc升序 /desc降序)构建FieldSort,添加到查询请求if (!StringUtils.isEmpty(param.getSort())) {String sort = param.getSort();String[] sortFileds = sort.split("_");if (!StringUtils.isEmpty(sortFileds[0])) {SortOrder sortOrder = "asc".equalsIgnoreCase(sortFileds[1]) ? SortOrder.Asc : SortOrder.Desc;// 排序FieldSort fieldSort = SortOptionsBuilders.field().field(sortFileds[0]).order(sortOrder).build();searchRequestBuilder.sort(s -> s.field(fieldSort));}}// 分页(from/size)// 计算分页起始位置searchRequestBuilder.from((param.getPageNum() - 1) * SearchConstant.PAGE_SIZE);// 设置每页条数searchRequestBuilder.size(SearchConstant.PAGE_SIZE);// 高亮显示。若传入keyword,对name字段设置高亮if (!StringUtils.isEmpty(param.getKeyword())) {HighlightField highlightField = new HighlightField.Builder().preTags("<b style='color:red'>").postTags("</b>").build();searchRequestBuilder.highlight(h -> h.fields("name", highlightField));}// 聚合分析(aggregations)// 品牌聚合:按brandId分组(terms聚合),子聚合获取brandName(品牌名)和brandImg(品牌图片),用于展示可选品牌列表// 品牌名称聚合:按brandName字段分组,取第一个值Aggregation brand_name_agg = AggregationBuilders.terms(t -> t.field("brandName").size(1));// 品牌图片聚合:按brandImg字段分组,取第一个值  Aggregation brand_img_agg = AggregationBuilders.terms(t -> t.field("brandImg").size(1));Aggregation brand_agg = new Aggregation.Builder()//按照品牌id进行聚合.terms(t -> t.field("brandId").size(50)).aggregations("brand_name_agg", brand_name_agg).aggregations("brand_img_agg", brand_img_agg).build();searchRequestBuilder.aggregations("brand_agg", brand_agg);// 分类聚合:按categoryId分组,子聚合获取categoryName(分类名),用于展示可选分类列表Aggregation category_agg = new Aggregation.Builder().terms(t -> t.field("categoryId").size(50)).aggregations("category_name_agg", AggregationBuilders.terms(t -> t.field("categoryName").size(1))).build();searchRequestBuilder.aggregations("category_agg", category_agg);// 属性聚合:针对attrs嵌套字段,先通过nested聚合指定路径,再按attrs.attrId分组,子聚合获取attrName(属性名)和attrValue(属性值列表),用于展示可选规格属性(如 “颜色:黑 / 白 / 红”)NestedAggregation attrs = new NestedAggregation.Builder().path("attrs").build();Aggregation attr_id_agg = new Aggregation.Builder()// 按照属性ID进行聚合.terms(t -> t.field("attrs.attrId"))// 在每个属性ID下,按照属性名进行聚合.aggregations("attr_name_agg", AggregationBuilders.terms(t -> t.field("attrs.attrName").size(1)))// 在每个属性ID下,按照属性值进行聚合.aggregations("attr_value_agg", AggregationBuilders.terms(t -> t.field("attrs.attrValue").size(1))).build();Aggregation attrs_agg = new Aggregation.Builder().nested(attrs).aggregations("attr_id_agg", attr_id_agg).build();searchRequestBuilder.aggregations("attrs_agg", attrs_agg);System.out.println("构建的DSL语句:" + searchRequestBuilder.toString());SearchRequest searchRequest = searchRequestBuilder.index(SearchConstant.INDEX_NAME).build();return searchRequest;}// 响应结果处理// 将 ES 返回的SearchResponse解析为前端所需的ESResponseResult,包含商品列表、聚合结果、分页信息三大块private ESResponseResult startBuildResponseResult(SearchResponse response, ESRequestParam param) {// 构建返回结果ESResponseResult result = new ESResponseResult();// 从hits中提取商品数据(EsProduct),若开启高亮(有keyword),则用高亮后的name替换原始名称(如 “<b>手机</b>”)HitsMetadata<EsProduct> hitsMetadata = response.hits();List<Hit<EsProduct>> hits = hitsMetadata.hits();List<EsProduct> esProducts = new ArrayList<>();// 遍历所有商品信息if (!hits.isEmpty()) {for (Hit<EsProduct> hit : hits) {EsProduct product = hit.source();// 判断是否按关键字检索,若是就显示高亮,否则不显示if (!StringUtils.isEmpty(param.getKeyword())) {// 拿到高亮信息显示标题List<String> name = hit.highlight().get("name");// 判断name中是否含有查询的关键字(因为是多字段查询,因此可能不包含指定的关键字,假设不包含则显示原始name字段的信息)String nameValue = name != null ? name.get(0) : product.getName();product.setName(nameValue);}esProducts.add(product);}}result.setProducts(esProducts);// 聚合结果解析:// 品牌列表(brands):解析brand_agg聚合结果,提取brandId、brandName、brandImg,封装为BrandVo列表(去重后展示)// 当前商品涉及到的所有品牌信息,小米手机和小米电脑都属于小米品牌,过滤重复品牌信息List<ESResponseResult.BrandVo> brandVos = new ArrayList<>();// 获取聚合结果Map<String, Aggregate> aggs = response.aggregations();Aggregate brandAgg = aggs.get("brand_agg");if (brandAgg != null) {List<LongTermsBucket> brandIdBuckets = brandAgg.lterms().buckets().array();for (LongTermsBucket brandIdBucket : brandIdBuckets) {// 构建品牌信息ESResponseResult.BrandVo brandVo = new ESResponseResult.BrandVo();// 设置品牌IDbrandVo.setBrandId(brandIdBucket.key());Aggregate brandImgAgg = brandIdBucket.aggregations().get("brand_img_agg");Aggregate brandNameAgg = brandIdBucket.aggregations().get("brand_name_agg");if (brandImgAgg != null && brandNameAgg != null) {StringTermsBucket imgBucket = brandImgAgg.sterms().buckets().array().get(0);StringTermsBucket nameBucket = brandNameAgg.sterms().buckets().array().get(0);// 设置品牌的图片和名称brandVo.setBrandImg(imgBucket.key().stringValue());brandVo.setBrandName(nameBucket.key().stringValue());}brandVos.add(brandVo);}}result.setBrands(brandVos);// 分类列表(categorys):解析category_agg聚合结果,提取categoryId、categoryName,封装为categoryVo列表List<ESResponseResult.categoryVo> categoryVos = new ArrayList<>();Aggregate categoryAgg = aggs.get("category_agg");if (categoryAgg != null) {List<LongTermsBucket> categoryBuckets = categoryAgg.lterms().buckets().array();for (LongTermsBucket categoryBucket : categoryBuckets) {// 构建分类信息ESResponseResult.categoryVo categoryVo = new ESResponseResult.categoryVo();// 设置分类IDcategoryVo.setCategoryId(categoryBucket.key());Aggregate categoryNameAgg = categoryBucket.aggregations().get("category_name_agg");if (categoryNameAgg != null) {StringTermsBucket nameBucket = categoryNameAgg.sterms().buckets().array().get(0);// 设置分类名称categoryVo.setCategoryName(nameBucket.key().stringValue());}categoryVos.add(categoryVo);}}result.setCategorys(categoryVos);// 属性列表(attrs):解析attrs_agg嵌套聚合结果,提取attrId、attrName及多个attrValue,封装为AttrVo列表(如 “颜色:[黑、白]”)List<ESResponseResult.AttrVo> attrVos = new ArrayList<>();// 获取属性信息的聚合Aggregate attrsAgg = aggs.get("attrs_agg");if (attrsAgg != null) {// 获取属性id的集合Aggregate attrIdAgg = attrsAgg.nested().aggregations().get("attr_id_agg");List<LongTermsBucket> attrBuckets = attrIdAgg.lterms().buckets().array();for (LongTermsBucket attrBucket : attrBuckets) {// 构建属性信息ESResponseResult.AttrVo attrVo = new ESResponseResult.AttrVo();// 设置属性IDattrVo.setAttrId(attrBucket.key());Aggregate attrNameAgg = attrBucket.aggregations().get("attr_name_agg");Aggregate attrValueAgg = attrBucket.aggregations().get("attr_value_agg");if (attrNameAgg != null && attrValueAgg != null) {StringTermsBucket attrNameBucket = attrNameAgg.sterms().buckets().array().get(0);// 设置属性名称attrVo.setAttrName(attrNameBucket.key().stringValue());List<StringTermsBucket> attrValueBuckets = attrValueAgg.sterms().buckets().array();List<String> attrValues = new ArrayList<>();for (StringTermsBucket attrValueBucket : attrValueBuckets) {attrValues.add(attrValueBucket.key().stringValue());}// 设置属性值attrVo.setAttrValue(attrValues);}attrVos.add(attrVo);}}result.setAttrs(attrVos);// 分页信息:包含当前页码(pageNum)、总条数(total)、总页数(totalPages)、页码导航(pageNavs),用于前端分页控件渲染result.setPageNum(param.getPageNum());// 获取总记录数long total = hitsMetadata.total().value();result.setTotal(total);// 计算总页码int totalPages = (int) total % SearchConstant.PAGE_SIZE == 0 ? (int) total / SearchConstant.PAGE_SIZE : ((int) total / SearchConstant.PAGE_SIZE + 1);result.setTotalPages(totalPages);List<Integer> pageNavs = new ArrayList<>();for (int i = 1; i <= totalPages; i++) {pageNavs.add(i);}result.setPageNavs(pageNavs);return result;}
    }
    
http://www.dtcms.com/a/594390.html

相关文章:

  • 第三方应用软件提权之symantic pcanywhere提权
  • 科普:LLM领域中的“样本(sample)”、“指令(instruction)”和“提示词(prompt)”
  • 宁波网站运营优化系统推广营销方案
  • 【WIP】大模型运维中GPU机器介绍
  • 在家没事做建什么网站好joomla 网站建设教程
  • explorer.exe源代码分析之热键的注册和处理
  • 免费做网站通栏广告做企业网站哪家好
  • 后端开发CRUD实现
  • 4.忘记密码页测试用例
  • 怎么建设个网站做网站用啥软件
  • 凡科可以做淘宝客网站吗上海企业登记在线电子签名
  • 网站关键词优化代理山东临沂市需要建设网站的公司
  • Hello-Agents task1 智能体与语言模型基础
  • 做宣传手册的网站智慧团建网站登录忘记密码
  • 山西省建设监理协会官方网站外链代发免费
  • 区间|单调栈
  • 基于Springboot的电器商城管理系统
  • 做摄影网站的目的是什么意思wordpress创建角色
  • 公司网站设计开发公司注册域名阿里云
  • 强化学习3 Q-learning
  • 惠州制作公司网站pythone网站开发
  • 企业只有建立自己的网站平台广西麒铭建设有限公司网站
  • 使用gpio 的/sys 属性来模拟调试信号的操作
  • 专业网站建设公司兴田德润怎么样沈阳网站建设小工作室
  • 秦皇岛建设网站官网农产品跨境电商平台有哪些
  • 回溯专题之二叉树
  • 网站建设工具的种类aspnet网站开发实例项目
  • 怎样制造网站图片教程公司网站建设费用 知乎
  • Python 3.6.1 报错 “module ‘enum‘ has no attribute ‘IntFlag‘” 的真正原因与解决办法
  • 建设网站的重要意义wordpress 去除归档链接