写点什么

基于华为开发者空间,用大数据带你挖掘电商 Top10 热门品类

  • 2025-09-11
    中国香港
  • 本文字数:7870 字

    阅读完需:约 26 分钟

基于华为开发者空间,用大数据带你挖掘电商Top10热门品类

1 概述

1.1 背景介绍

随着电商行业的蓬勃发展,海量交易数据不断产生。了解哪些品类在市场中最受消费者青睐,成为商家优化库存、制定营销策略以及平台规划布局的关键依据。

1.2 适用对象

  • 企业

  • 个人开发者

  • 高校学生(有一定代码基础)

1.3 案例时间

本案例总时长预计 30 分钟。

1.4 案例流程


说明:① 用户登录云主机;② 打开 CodeArts IDE 获取项目代码;③ 进行环境准备,配置 JDK17;④ 启动项目的前后端代码,在浏览器中进行页面结果展示。

大数据带你挖掘电商Top10热门品类 👈👈👈体验完整版案例,点击这里。

2 操作步骤

2.1 数据格式简介

本案例的数据是采集电商网站的用户行为数据,主要包含用户的 4 种行为:搜索、点击、下单和支付。数据格式说明如下:(1)数据采用下划线分割字段;(2)每一行表示用户的一个行为,所以每一行只能是 4 种行为中的一种;(3)如果搜索关键字是 null,表示这次不是搜索;(4)如果点击的品类 id 和产品 id 是-1 表示这次不是点击;(5)下单行为来说一次可以下单多个产品,所以品类 id 和产品 id 都是多个,id 之间使用逗号分割。如果本次不是下单行为,则他们相关数据用 null 来表示;(6)支付行为和下单行为类似。


2.2 需求分析

Top10 热门品类,是指产品的分类。分别统计每个品类点击的次数,下单的次数和支付的次数。先按照点击数排名,靠前的就排名高;如果点击数相同,再比较下单数;下单数再相同,就比较支付数。计算结果格式类似:


智能手机 ,点击品类书,下单品类数,支付品类数宠物玩具 ,点击品类书,下单品类数,支付品类数休闲食品,点击品类书,下单品类数,支付品类数
复制代码

2.3 环境准备

2.3.1 获取项目代码

1.拉取前端代码


git clone https://gitcode.com/CaseDeveloper/E-Commerce-commerce-top10-Web.git
复制代码


前端部署参考案例:在云主机上进行电商项目VUE前端部署2.拉取后端代码


git clone https://gitcode.com/CaseDeveloper/E-Commerce-commerce-top10.git
复制代码


后端部署参考案例:基于云主机的CodeArts IDE运行Java电商项目

2.3.2 编写代码

1.打开 CodeArts IDE for Java



2.打开工程 E-Commerce-commerce-top10



3.打开项目代码


  • 在工程 src 下 datas 文件夹中 user_visit_action.txt 是需要用到的数据。

  • 在 utils 下 Top10.java 是实现代码。

  • Top10.java 代码如下:


package org.example.utils;
import org.apache.spark.SparkConf;import org.apache.spark.api.java.JavaRDD;import org.apache.spark.api.java.JavaSparkContext;import org.apache.spark.api.java.function.VoidFunction;import org.apache.spark.util.AccumulatorV2;import org.example.Entity.BusinessData;import org.example.Entity.CategoryCountInfo;import org.example.Entity.ProductIdToNameMapEnum;import org.example.Entity.UserVisitAction;import scala.Tuple2;import java.io.Serializable;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;
//自定义AccumulatorV2实现类,用于累加计算品类相关的点击、下单、支付次数class CategoryCountAccumulator extends AccumulatorV2<UserVisitAction, Map<Tuple2<String, String>, Long>> implements Serializable{
private Map<Tuple2<String, String>, Long> map1 = new HashMap<>();
// 判断是否为初始状态(即map为空) @Override public boolean isZero() { return map1.isEmpty(); }
// 复制累加器实例 @Override public AccumulatorV2<UserVisitAction, Map<Tuple2<String, String>, Long>> copy() { CategoryCountAccumulator newACC = new CategoryCountAccumulator(); newACC.map1 = new HashMap<>(this.map1); return newACC; }
// 重置累加器,清空内部存储的map数据 @Override public void reset() { map1.clear(); }
// 处理单个分区内的数据,根据不同的业务行为(点击、下单、支付)累加相应的次数 @Override public void add(UserVisitAction action) { // 点击行为 if (action.getClick_category_id()!= -1) { Tuple2<String, String> key = new Tuple2<>(action.getClick_category_id() + "", "click"); map1.put(key, map1.getOrDefault(key, 0L) + 1L); } // 下单行为 else if (!"null".equals(action.getOrder_category_ids())) { String[] ids = action.getOrder_category_ids().split(","); for (String id : ids) { Tuple2<String, String> key = new Tuple2<>(id, "order"); map1.put(key, map1.getOrDefault(key, 0L) + 1L); } } // 支付行为 else if (!"null".equals(action.getPay_category_ids())) { String[] ids = action.getPay_category_ids().split(","); for (String id : ids) { Tuple2<String, String> key = new Tuple2<>(id, "pay"); map1.put(key, map1.getOrDefault(key, 0L) + 1L); } } }
// 合并不同分区的累加结果 @Override public void merge(AccumulatorV2<UserVisitAction, Map<Tuple2<String, String>, Long>> other) { Map<Tuple2<String, String>, Long> map2 = other.value(); for (Map.Entry<Tuple2<String, String>, Long> entry : map2.entrySet()) { Tuple2<String, String> k = entry.getKey(); Long v = entry.getValue(); map1.put(k, map1.getOrDefault(k, 0L) + v); } }
// 获取累加器当前的值(即存储了各品类操作次数的map) @Override public Map<Tuple2<String, String>, Long> value() { return map1; }}
public class Top10 implements Serializable { public static List<BusinessData> top10() { SparkConf conf = new SparkConf().setAppName("Top10").setMaster("local[*]"); // 创建JavaSparkContext,该对象是提交的入口 JavaSparkContext sc = new JavaSparkContext(conf); Top10 top10 = new Top10(); List<BusinessData> sparkRun = top10.sparkRun(sc); // 9. 关闭连接 sc.stop(); return sparkRun; } public List<BusinessData> sparkRun(JavaSparkContext sc) {
// public static void main(String[] args) { // 创建SparkConf // SparkConf conf = new SparkConf().setAppName("Top10").setMaster("local[*]"); // 创建JavaSparkContext,该对象是提交的入口 // JavaSparkContext sc = new JavaSparkContext(conf);
// 后续代码部分,如数据读取、处理、累加器使用、排序取前10以及关闭连接等操作保持不变 // 1. 读取数据 JavaRDD<String> dataRDD = sc.textFile("src/datas/user_visit_action.txt");
// 2. 将读到的数据进行切分,并且将切分的内容封装为UserVisitAction对象 JavaRDD<UserVisitAction> actionRDD = dataRDD.map(line -> { String[] fields = line.split("_"); return new UserVisitAction( fields[0], Long.parseLong(fields[1]), fields[2], Long.parseLong(fields[3]), fields[4], fields[5], Long.parseLong(fields[6]), Long.parseLong(fields[7]), fields[8], fields[9], fields[10], fields[11], Long.parseLong(fields[12]) ); });
// 3. 创建累加器并注册 CategoryCountAccumulator acc = new CategoryCountAccumulator(); sc.sc().register(acc, "myAcc");
// 4. 遍历actionRDD,使用累加器进行统计 actionRDD.foreach(new VoidFunction<UserVisitAction>() { @Override public void call(UserVisitAction action) { acc.add(action); } });
// 5. 获取累加器的值 Map<Tuple2<String, String>, Long> accMap = acc.value();
// 6. 对累加出来的数据按照类别进行分组 Map<String, Map<Tuple2<String, String>, Long>> groupMap = new HashMap<>(); for (Map.Entry<Tuple2<String, String>, Long> entry : accMap.entrySet()) { Tuple2<String, String> key = entry.getKey(); String categoryId = key._1; if (!groupMap.containsKey(categoryId)) { groupMap.put(categoryId, new HashMap<>()); } groupMap.get(categoryId).put(key, entry.getValue()); }
// 7. 对分组后的数据进行结构的转换为CategoryCountInfo对象 List<CategoryCountInfo> categoryCountInfoList = new ArrayList<>(); for (Map.Entry<String, Map<Tuple2<String, String>, Long>> entry : groupMap.entrySet()) { String id = entry.getKey(); Map<Tuple2<String, String>, Long> map = entry.getValue(); long clickCount = map.getOrDefault(new Tuple2<>(id, "click"), 0L); long orderCount = map.getOrDefault(new Tuple2<>(id, "order"), 0L); long payCount = map.getOrDefault(new Tuple2<>(id, "pay"), 0L); categoryCountInfoList.add(new CategoryCountInfo(id, clickCount, orderCount, payCount)); }
// 8. 将转换后的数据进行排序(降序)取前10名 categoryCountInfoList.sort((left, right) -> { // 先按照点击次数降序比较 int clickCountCompare = Long.compare(right.getClickCount(), left.getClickCount()); if (clickCountCompare!= 0) { return clickCountCompare; } // 点击次数相同,按照订单次数降序比较 int orderCountCompare = Long.compare(right.getOrderCount(), left.getOrderCount()); if (orderCountCompare!= 0) { return orderCountCompare; } // 订单次数相同,按照支付次数降序比较 return Long.compare(right.getPayCount(), left.getPayCount()); }); Map<String, String> productIdToNameMap = ProductIdToNameMapEnum.INSTANCE.getProductIdToNameMap(); List<CategoryCountInfo> top10List = categoryCountInfoList.size() > 10? categoryCountInfoList.subList(0, 10) : categoryCountInfoList; List<BusinessData> businessData = new ArrayList<>();
for (CategoryCountInfo info : top10List) { String productName = productIdToNameMap.getOrDefault(info.getCategoryId(), info.getCategoryId()); BusinessData data = new BusinessData(); data.setCategory(productName); data.setClickCount(info.getClickCount()); data.setOrderCount(info.getOrderCount()); data.setPaymentCount(info.getPayCount()); businessData.add(data); // System.out.println("CategoryCountInfo(" + productName + ", " + info.getClickCount() + ", " + info.getOrderCount() + ", " + info.getPayCount() + ")");
} // 9. 关闭连接 // sc.stop(); return businessData; }}
复制代码


  • entity 下,CategoryCountInfo,ProductIdToNameMapEnum,UserVisitAction 是实体类。

  • 代码如下:a) CategoryCountInfo 类:


package com.example.entity;import java.io.Serializable;
public class CategoryCountInfo implements Serializable { private String categoryId; private long clickCount; private long orderCount; private long payCount;
public CategoryCountInfo(String categoryId, long clickCount, long orderCount, long payCount) { this.categoryId = categoryId; this.clickCount = clickCount; this.orderCount = orderCount; this.payCount = payCount; }
public String getCategoryId() { return categoryId; }
public long getClickCount() { return clickCount; }
public void setClickCount(long clickCount) { this.clickCount = clickCount; }
public long getOrderCount() { return orderCount; }
public void setOrderCount(long orderCount) { this.orderCount = orderCount; }
public long getPayCount() { return payCount; }
public void setPayCount(long payCount) { this.payCount = payCount; }
// 重写toString方法,按照期望的格式返回对象的字符串表示 @Override public String toString() { return "CategoryCountInfo(" + categoryId + ',' + + clickCount + ','+ + orderCount + ','+ + payCount + ')'; }}
复制代码


b) ProductIdToNameMapEnum 类(枚举类,商品分类 id 和商品分类的对应关系):


package com.example.entity;
import java.util.HashMap;import java.util.Map;
public enum ProductIdToNameMapEnum { INSTANCE;
private final Map<String, String> productIdToNameMap;
ProductIdToNameMapEnum() { productIdToNameMap = new HashMap<>(); productIdToNameMap.put("1", "智能手机"); productIdToNameMap.put("2", "护肤品套装"); productIdToNameMap.put("3", "运动鞋"); productIdToNameMap.put("4", "平板电脑"); productIdToNameMap.put("5", "休闲食品"); productIdToNameMap.put("6", "智能手环"); productIdToNameMap.put("7", "运动水杯"); productIdToNameMap.put("8", "儿童玩具"); productIdToNameMap.put("9", "营养补充剂"); productIdToNameMap.put("10", "家用小电器"); productIdToNameMap.put("11", "时尚外套"); productIdToNameMap.put("12", "蓝牙耳机"); productIdToNameMap.put("13", "创意家居饰品"); productIdToNameMap.put("14", "车载香水"); productIdToNameMap.put("15", "智能手表"); productIdToNameMap.put("16", "美妆工具"); productIdToNameMap.put("17", "电子游戏"); productIdToNameMap.put("18", "户外背包"); productIdToNameMap.put("19", "宠物玩具"); productIdToNameMap.put("20", "健身器材"); }
public Map<String, String> getProductIdToNameMap() { return productIdToNameMap; }}
复制代码


c) UserVisitAction 类:


package com.example.entity;// 用户访问动作表对应的Java类public class UserVisitAction {    private String date;    private long user_id;    private String session_id;    private long page_id;    private String action_time;    private String search_keyword;    private long click_category_id;    private long click_product_id;    private String order_category_ids;    private String order_product_ids;    private String pay_category_ids;    private String pay_product_ids;    private long city_id;
public UserVisitAction(String date, long user_id, String session_id, long page_id, String action_time, String search_keyword, long click_category_id, long click_product_id, String order_category_ids, String order_product_ids, String pay_category_ids, String pay_product_ids, long city_id) { this.date = date; this.user_id = user_id; this.session_id = session_id; this.page_id = page_id; this.action_time = action_time; this.search_keyword = search_keyword; this.click_category_id = click_category_id; this.click_product_id = click_product_id; this.order_category_ids = order_category_ids; this.order_product_ids = order_product_ids; this.pay_category_ids = pay_category_ids; this.pay_product_ids = pay_product_ids; this.city_id = city_id; }
public String getDate() { return date; }
public long getUser_id() { return user_id; }
public String getSession_id() { return session_id; }
public long getPage_id() { return page_id; }
public String getAction_time() { return action_time; }
public String getSearch_keyword() { return search_keyword; }
public long getClick_category_id() { return click_category_id; }
public long getClick_product_id() { return click_product_id; }
public String getOrder_category_ids() { return order_category_ids; }
public String getOrder_product_ids() { return order_product_ids; }
public String getPay_category_ids() { return pay_category_ids; }
public String getPay_product_ids() { return pay_product_ids; }
public long getCity_id() { return city_id; }}
复制代码

2.3.3 编辑配置

点击右上角编辑配置。



在 VM options: 配置项,添加如下配置(jdk 版本高于 1.8 需要添加)。


--add-opens java.base/sun.nio.ch=ALL-UNNAMED
复制代码


2.4 运行代码

1.点击页面右上角的执行按钮运行后端代码。



2.在命令行运行前端代码在前端代码目录执行命令:


npm run dev
复制代码



运行成功后显示如下:



3.打开页面http://localhost:3000/products,访问电商项目页面。



注册账号并登录,然后点击页面的“top10”商品按钮。



可以看到 Top10 热门的商品品类展示如下。



至此,电商 top10 热门品类挖掘实操全部完成。


用户头像

提供全面深入的云计算技术干货 2020-07-14 加入

生于云,长于云,让开发者成为决定性力量

评论

发布
暂无评论
基于华为开发者空间,用大数据带你挖掘电商Top10热门品类_华为开发者空间_华为云开发者联盟_InfoQ写作社区