一、项目介绍

        电子商务中会产生海量的数据,蕴含着不可估量的数据价值,可通过数据分析来挖掘这些潜在价值,以提升平台的销量。本次实践项目利用 Hadoop 的分布式计算框架 MapReduce 来分析用户行为数据,计算得出商品点击排行、商品分类占比等统计指标,使得更加熟练掌握 MapReduce 程序的设计。

        相关理论知识有,Map 和 Reduce 流程图如下:输入数据(INPUT)首先分割(SPLIT)成若干份,然后每份分别进行 MAP 过程;中间再经过 COMBINE 任务(可选)和 PARTTION 对 MAP 所得的结果进行聚合——把同 key 的结果放到同一组,最后再进行 REDUCE 过程。

 二、项目内容

电商大数据离线计算,主要有六个部分,分别为:

第1部分:统计用户流失情况;

第2部分:统计所有商品点击量排行;

第3部分:统计各个商品类别中点击量最高的商品;

第4部分:统计五种商品类别占比;

第5部分:统计各类商品种类的购买次数;

第6部分:统计五类商品中各自点击量最高的商品的购买次数。

三、功能模块

四、功能分析

统计用户流失情况:就是统计出用户4种不同用户行为的数量,即点击浏览(pv)的数量,购买(buy)的数量等。

统计所有商品点击量排行:即统计出每个商品id中用户行为是pv(点击浏览)的数量,reduce的输出最后是按点击量的大小从大到小排序。

统计各个商品类别中点击量最高的商品:根据用户行为数据,编写 MapReduce 程序来统计各个商品类别中点击量最高的商品。

统计五种商品类别占比:根据用户行为数据,编写 MapReduce 程序来统计出五种商品分类占比数据。

统计出各个商品类别的数量,在把一个商品类别的数量除以所有商品类别的数量即可得到该商品类别的占比。

统计各类商品种类的购买次数:根据用户行为数据,编写 MapReduce 程序来统计出各类商品种类的购买次数。

统计五类商品中各自点击量最高的商品的购买次数:根据用户行为数据,编写 MapReduce 程序来统计出五类商品中各自点击量最高的商品的购买次数。

五、项目步骤

(一)统计用户流失情况

1、项目需求分析及任务

任务:就是统计出用户4种不同用户行为的数量,即点击浏览(pv)的数量,购买(buy)的数量等。

编程要求:

main 方法已给出,其中 Job 和输入输出路径已配置完成,无需更改,

map 和 reduce 的输入输出 key、value 已给出。

预期输出格式

buy,总数

cart,总数

fav,总数

pv,总数

2、技术方法

这是编程中用到的电商数据数据,为 CSV 格式,文件名user_behavior.csv,大小9948行,每一行数据(4列)分别表示: 用户id, 商品id, 商品类别, 用户行为;商品类别有 手机、平板电脑、笔记本、智能手表、耳机,总共5大类别;用户行为中pv代表点击浏览,cart代表加入购物车,fav代表添加到喜欢,buy代表购买。

用户流失情况就是统计出用户4种不同用户行为的数量,即点击浏览(pv)的数量,购买(buy)的数量等。

3、部分截图与相关代码

1.	    public static class ThisMap extends Mapper<Object, Text, Text, IntWritable> {
2.	
3.	        //私有变量1,可重复使用
4.	        private static IntWritable one = new IntWritable(1);
5.	
6.	        @Override
7.	        protected void map(Object key, Text value, Context context) throws IOException, InterruptedException {
8.	
9.	            /*** 在这编写map内容 ****/
10.	            /********** Begin **********/
11.	            //分割每行数据
12.	            String[] atts = value.toString().split(",");
13.	            //得到行为属性
14.	            String behavior = atts[3];
15.	            //行为属性作key,1作value的map输出
16.	            context.write(new Text(behavior), one);
17.	
18.	            /********** End **********/
19.	        }
20.	    }
21.	
22.	    public static class ThisReduce extends Reducer<Text, IntWritable, Text, IntWritable> {
23.	
24.	        @Override
25.	        protected void reduce(Text key, Iterable<IntWritable> values, Context context)
26.	                throws IOException, InterruptedException {
27.	
28.	            /*** 在这编写reduce内容 ****/
29.	            /********** Begin **********/
30.	            //统计同key的values总数
31.	            int sum = 0;
32.	            for(IntWritable one : values){
33.	                sum += one.get();
34.	            }
35.	            //写入到reduce输出
36.	            context.write(key, new IntWritable(sum));
37.	
38.	            /********** End **********/
39.	        }
40.	    }

(二)统计所有商品点击量排行

1、项目需求分析及任务

任务:即统计出每个商品id中用户行为是pv(点击浏览)的数量,reduce的输出最后是按点击量的大小从大到小排序。

编程要求:

main 方法已给出,其中 Job 和输入输出路径已配置完成,无需更改,

map 和 reduce 的输入输出 key、value 已给出。

预期输出格式(按点击量从大到小):

商品id,点击量

商品id,点击量

···

2、技术方法

cleanup()方法

编程中可能会用到 cleanup() 方法,cleanup 方法是 mapper/reduce 对象执行完所有的 map/reduce 方法之后最后执行的方法,可用于清理资源释放或清理工作;默认继承的父类方法为空。

3、部分截图与相关代码

1.	    public static class ThisMap extends Mapper<Object, Text, Text, IntWritable> {
2.	
3.	        private static IntWritable one = new IntWritable(1);
4.	
5.	        @Override
6.	        protected void map(Object key, Text value, Context context) throws IOException, InterruptedException {
7.	
8.	            /*** 在这编写map内容 ****/
9.	            /********** Begin **********/
10.	            //1. 分割每行数据
11.	            String[] atts = value.toString().split(",");
12.	            //2. 得到商品id
13.	            String item = atts[1];
14.	            //3. 得到行为属性
15.	            String behavior = atts[3];
16.	            //4. 如果行为属性是 'pv',则写入到map输出
17.	            if (behavior.equals("pv")) {
18.	                context.write(new Text(item), one);
19.	            }
20.	
21.	            /********** End **********/
22.	
23.	        }
24.	    }
25.	
26.	    public static class ThisReduce extends Reducer<Text, IntWritable, Text, IntWritable> {
27.	
28.	        //对象实例,用来保存reduce方法中处理的数据
29.	        List<Object[]> list = new LinkedList<>();
30.	
31.	        @Override
32.	        protected void reduce(Text key, Iterable<IntWritable> values, Context context)
33.	                throws IOException, InterruptedException {
34.	            /*** 在这编写reduce内容 ****/
35.	            /********** Begin **********/
36.	            // 统计同key总数, 把key和sum写入到list中
37.	            int sum = 0;
38.	            for (IntWritable one : values) {
39.	                sum += one.get();
40.	            }
41.	            list.add(new Object[] { key.toString(), Integer.valueOf(sum) });
42.	
43.	            /********** End **********/
44.	        }
45.	
46.	
47.	
48.	        //cleanup方法,即reduce对象执行完所有的reduce方法后最后执行的方法
49.	        @Override
50.	        protected void cleanup(Reducer<Text, IntWritable, Text, IntWritable>.Context context)
51.	                throws IOException, InterruptedException {
52.	
53.	            // 按照sum的大小对list进行排序,得到的结果是从小到大
54.	            list = list.stream().sorted((o1, o2) -> { return ((int)o1[1] - (int)o2[1]);}).collect(Collectors.toList());
55.	            // 从后向前遍历,即从大到小
56.	            for(int i=list.size()-1; i>=0; i--){
57.	                Object[] o = list.get(i);
58.	                //写入到reduce输出
59.	                context.write(new Text((String) o[0]), new IntWritable((int) o[1]));
60.	            }
61.	        }
62.	    }

(三)统计各个商品类别中点击量最高的商品

1、项目需求分析及任务

任务:根据用户行为数据,编写 MapReduce 程序来统计各个商品类别中点击量最高的商品。

编程要求:

main 方法已给出,其中 Job 和输入输出路径已配置完成,无需更改,

map 和 reduce 的输入输出 key、value 已给出。

预期输出格式

商品类型,点击量最高的商品id

商品类型,点击量最高的商品id

2、技术方法

这是编程中用到的电商数据数据,为 CSV 格式,文件名user_behavior.csv,大小9948行,每一行数据(4列)分别表示: 用户id, 商品id, 商品类别, 用户行为;商品类别有 手机、平板电脑、笔记本、智能手表、耳机,总共5大类别;用户行为中pv代表点击浏览,cart代表加入购物车,fav代表添加到喜欢,buy代表购买。

3、部分截图与相关代码

1.	    public static class ThisMap extends Mapper<Object, Text, Text, Text> {
2.	
3.	        @Override
4.	        protected void map(Object key, Text value, Context context) throws IOException, InterruptedException {
5.	
6.	            /*** 在这编写map内容 ****/
7.	            /********** Begin **********/
8.	            // 作用跟前几关一样,不再描述
9.	            String[] atts = value.toString().split(",");
10.	            String item = atts[1];
11.	            String type = atts[2];
12.	            String behavior = atts[3];
13.	            if (behavior.equals("pv")) {
14.	                context.write(new Text(type), new Text(item));
15.	            }
16.	            /********** End **********/
17.	
18.	        }
19.	    }
20.	
21.	    public static class ThisReduce extends Reducer<Text, Text, Text, Text> {
22.	
23.	        @Override
24.	        protected void reduce(Text key, Iterable<Text> values, Context context)
25.	                throws IOException, InterruptedException {
26.	
27.	            /*** 在这编写reduce内容 ****/
28.	            /********** Begin **********/
29.	
30.	            // 提示: 先得出所有商品id的数量,再从这些数量中找出最大值
31.	
32.	            // 1. 一个map,用来保存各个商品id的数量
33.	            Map<String, Integer> map = new HashMap<>();
34.	            // 2. 统计values中各个value的数量
35.	            for (Text value : values) {
36.	                String item = value.toString();
37.	                Integer count = !map.containsKey(item) ? 1 : map.get(item) + 1;
38.	                map.put(item, count);
39.	            }
40.	            // 3. 找出map中value最大的键值对
41.	            Map.Entry<String, Integer> itemMax = Collections.max(map.entrySet(), (entry1, entry2) -> {
42.	                return entry1.getValue() - entry2.getValue();
43.	            });
44.	            // 4. 结果写入reduce输出
45.	            context.write(key, new Text(itemMax.getKey()));
46.	
47.	            /********** End **********/
48.	        }
49.	
50.	    }

(四)统计五种商品类别占比

1、项目需求分析及任务

任务:根据用户行为数据,编写 MapReduce 程序来统计出五种商品分类占比数据。统计出各个商品类别的数量,在把一个商品类别的数量除以所有商品类别的数量即可得到该商品类别的占比。

编程要求:

main 方法已给出,其中 Job 和输入输出路径已配置完成,无需更改,

map 和 reduce 的输入输出 key、value 已给出。

预期输出格式:

商品类别,占总数比例

商品类别,占总数比例

···

2、技术方法

cleanup()方法

编程中可能会用到 cleanup() 方法,cleanup 方法是 mapper/reduce 对象执行完所有的 map/reduce 方法之后最后执行的方法,可用于清理资源释放或清理工作;默认继承的父类方法为空。

3、部分截图与相关代码

1.	    public static class ThisMap extends Mapper<Object, Text, Text, IntWritable> {
2.	
3.	        private static IntWritable one = new IntWritable(1);
4.	
5.	        @Override
6.	        protected void map(Object key, Text value, Context context) throws IOException, InterruptedException {
7.	            /*** 在这编写map内容 ****/
8.	            /********** Begin **********/
9.	
10.	            String[] atts = value.toString().split(",");
11.	            String type = atts[2];
12.	            context.write(new Text(type), one);
13.	
14.	            /********** End **********/
15.	        }
16.	    }
17.	
18.	    public static class ThisReduce extends Reducer<Text, IntWritable, Text, DoubleWritable> {
19.	
20.	        // 保存reduce方法的处理结果
21.	        Map<String,Integer> map = new HashMap<>();
22.	
23.	        @Override
24.	        protected void reduce(Text key, Iterable<IntWritable> values, Context context)
25.	                throws IOException, InterruptedException {
26.	            /*** 在这编写reduce内容 ****/
27.	            /********** Begin **********/
28.	            int count = 0;
29.	            for (IntWritable one : values) {
30.	                count += one.get();
31.	            }
32.	            map.put(key.toString(), count);
33.	            /********** End **********/
34.	
35.	
36.	        }
37.	
38.	        // 需要重写 cleanup方法
39.	        @Override
40.	        protected void cleanup(Reducer<Text, IntWritable, Text, DoubleWritable>.Context context)
41.	                throws IOException, InterruptedException {
42.	
43.	            // 得到所有商品类别数量的总和
44.	            int sum = 0;
45.	            for (int v : map.values()) {
46.	                sum += v;
47.	            }
48.	            // 得出每个商品类别的占比
49.	            for (String key : map.keySet()) {
50.	                int value = map.get(key);
51.	                double ratio = ((double) value) / sum;
52.	                context.write(new Text(key), new DoubleWritable(ratio));
53.	            }
54.	        }
55.	
56.	    }

(五)统计各类商品种类的购买次数

1、项目需求分析及任务

任务:根据用户行为数据,编写 MapReduce 程序来统计出各类商品种类的购买次数。

编程要求:

main 方法已给出,其中 Job 和输入输出路径已配置完成,无需更改,

map 和 reduce 的输入输出 key、value 已给出。

预期输出格式:

商品类型,购买次数

商品类型,购买次数

···

2、技术方法

这是编程中用到的电商数据数据,为 CSV 格式,文件名user_behavior.csv,大小9948行,每一行数据(4列)分别表示: 用户id, 商品id, 商品类别, 用户行为;商品类别有 手机、平板电脑、笔记本、智能手表、耳机,总共5大类别;用户行为中pv代表点击浏览,cart代表加入购物车,fav代表添加到喜欢,buy代表购买。

3、部分截图与相关代码

1.	    public static class ThisMap extends Mapper<Object, Text, Text, IntWritable> {
2.	
3.	        private static IntWritable one = new IntWritable(1);
4.	
5.	        @Override
6.	        protected void map(Object key, Text value, Context context) throws IOException, InterruptedException {
7.	            /*** 在这编写map内容 ****/
8.	            /********** Begin **********/
9.	            String[] atts = value.toString().split(",");
10.	            String type = atts[2];
11.	            if (atts[3].equals("buy")) {
12.	                context.write(new Text(type), one);
13.	            }
14.	            /********** End **********/
15.	
16.	        }
17.	    }
18.	
19.	    public static class ThisReduce extends Reducer<Text, IntWritable, Text, IntWritable> {
20.	
21.	        @Override
22.	        protected void reduce(Text key, Iterable<IntWritable> values, Context context)
23.	                throws IOException, InterruptedException {
24.	
25.	            /*** 在这编写reduce内容 ****/
26.	            /********** Begin **********/
27.	            int count = 0;
28.	            for (IntWritable one : values) {
29.	                count += one.get();
30.	            }
31.	            context.write(key, new IntWritable(count));
32.	            /********** End **********/
33.	
34.	        }
35.	    }

 (六)统计五类商品中各自点击量最高的商品的购买次数

1、项目需求分析及任务

任务:根据用户行为数据,编写 MapReduce 程序来统计出五类商品中各自点击量最高的商品的购买次数。

编程要求:

main 方法已给出,其中 Job 和输入输出路径已配置完成,无需更改,

map 和 reduce 的输入输出 key、value 已给出。

预期输出格式:

商品类型,本类型中点击量最高的id,购买次数

商品类型,本类型中点击量最高的id,购买次数

···

2、技术方法

这是编程中用到的电商数据数据,为 CSV 格式,文件名user_behavior.csv,大小9948行,每一行数据(4列)分别表示: 用户id, 商品id, 商品类别, 用户行为;商品类别有 手机、平板电脑、笔记本、智能手表、耳机,总共5大类别;用户行为中pv代表点击浏览,cart代表加入购物车,fav代表添加到喜欢,buy代表购买。

3、部分截图与相关代码

1.	    public static class ThisMap extends Mapper<Object, Text, Text, Text> {
2.	
3.	        @Override
4.	        protected void map(Object key, Text value, Context context) throws IOException, InterruptedException {
5.	            /*** 在这编写map内容 ****/
6.	            /********** Begin **********/
7.	            String[] atts = value.toString().split(",");
8.	            String type = atts[2];
9.	            //把value作为map的输出值,因为到时还需要用到一些属性
10.	            context.write(new Text(type), value);
11.	            /********** End **********/
12.	
13.	        }
14.	    }
15.	
16.	    public static class ThisReduce extends Reducer<Text, Text, Text, Text> {
17.	
18.	        @Override
19.	        protected void reduce(Text key, Iterable<Text> values, Context context)
20.	                throws IOException, InterruptedException {
21.	
22.	            /*** 在这编写reduce内容 ****/
23.	            /********** Begin **********/
24.	
25.	            Map<String, Integer> map = new HashMap<>();
26.	            List<String> value_list = new ArrayList<>();
27.	            // 1. 因为需要遍历多次values里的值,把values可迭代对象转化为list
28.	            for (Text v : values) {
29.	                value_list.add(v.toString());
30.	            }
31.	            // 2. 统计所有商品的数量
32.	            for (String v : value_list) {
33.	                String[] atts = v.toString().split(",");
34.	                String item = atts[1];
35.	                Integer count = !map.containsKey(item) ? 1 : map.get(item) + 1;
36.	                map.put(item, count);
37.	            }
38.	            // 3. 找出点击数量最大的商品
39.	            String itemClickMax = Collections.max(map.entrySet(), (entry1, entry2) -> {
40.	                return entry1.getValue() - entry2.getValue();
41.	            }).getKey();
42.	            // 4. 统计点击量最大的商品的购买次数
43.	            int buyCount = 0;
44.	            for (String v : value_list) {
45.	                String[] atts = v.toString().split(",");
46.	                if (atts[1].equals(itemClickMax) && atts[3].equals("buy")) {
47.	                    buyCount++;
48.	                }
49.	            }
50.	            // 5. 把商品类别、点击量最大的商品id、购买次数写入reducer输出
51.	            context.write(key, new Text(itemClickMax + "\t" + buyCount));
52.	
53.	            /********** End **********/
54.	
55.	        }
56.	
57.	    }

六、项目心得

进行作业的过程中的需要仔细阅读题目,步骤的缺漏会影响最终的结果。编写代码时注意括号和分号的使用,遇到困难应该多思考多尝试。

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐