流量统计
1363157985066 13726230503 00-FD-07-A4-72-B8:CMCC 120.196.100.82 i02.c.aliimg.com 24 27 2481 24681 200
1363157995052 13826544101 5C-0E-8B-C7-F1-E0:CMCC 120.197.40.4 4 0 264 0 200
1、对流量日志中的用户统计总上、下行、总流量
主要考虑的是map和reduce。
map端的输入是不用考虑的,都是以文本的形式输入行。map考虑的是输出,数据以什么样去处理比较好。
reduce端的输入是迭代器,要知道输入的迭代器是什么,数据还是要考虑的,以什么样的规则将数据传递给reduce,这是reduce调用的规则,要考虑框架的规则。输出的key是什么,输出的value是什么
因为一个手机号表示一个用户,所以key就是手机号。先考虑Reduce的输入,在考虑map的输出,总上、下行、总流量则为value,包含那么多字符串,可以封装为一个对象。整成了自定义类
mapreduce
map
输入
-------------------------------------------------------
输出:
key:phonenum
value:flowBean(上、下行、总流量) 作为一个整体
数据:(用什么样的数据进行处理)
=======================================================
reduce
输入:
key:phonenum
value:flowBean(上、下行、总流量)作为一个整体
-------------------------------------------------------
输出:
key:phonenum
value:flowBean(上、下行、总流量)作为一个整体
up:down:total
在这里是不需要排序的,因为排序是基于key的,而这里的key只有一个
1、定义一个自定义类,然后类里面包含所需要的属性
2、map端输出,Reduce要拉取数据,所以数据都是需要可序列化的,所以要实现可序列化接口。并且实现它的方法
要有两个构造方法,一个是无参构造,一个是有参构造。有参构造返回的是两个相加
对属性添加get,set的方法
实现序列化的方法(序列化和反序列化的顺序要一致)
实现tostring方法
到此,JavaBean就OK了。
接下来就要写MapReduce(map端一次只处理一行数据)
定义一个类flowCount,而且要继承Mapper,Reduce
1、先将value转为字符串,2、通过空格tab进行切割,3、获取数值,4、调用参数方法计算,5、获取到的k,v放到上下文
实现Reduce方法
1、同一个手机号的values循环,2将值进行统计累加,3、传给参数方法,4、返回的信息给到上下文
驱动方法
13480253104 180 180 360
13502468823 7335 110349 117684
13560436666 1116 954 2070
13560439658 2034 5892 7926
13602846565 1938 2910 4848
最终是要排倒叙的,reduce端的输入是要什么数据,才能得出reduce端所要输出的内容
统计流量且按照流量大小倒序排序(总量倒序、下行、上行倒序,phoneNum正序) 要统计还要倒叙
其实上面第一个Reduce输出的时候,已经是统计完了,现在这个Reduce要对他们进行排序,而排序只是对key进行排序
所以,Reduce的输入就是类,flowBean,则也就是将第一个Reduce的输出的k,v调换为第二个map的输出。
mapreduce
map
输入
key:phonenum
value:13480253104 180 180 360 flowBean
----------------------------------------------------
输出:
key:flowBean
value:phonenum
数据:
=====================================================
reduce
输入:
key:flowBean
value:phonenum
这个是Reduce调用后的,传给Reduce方法(倒叙排序)
------------------------------------------------------
输出:
key:phonenum
value:flowBean(上、下行、总流量)
up:down:total
结果如图
具体代码分析如下
要做比较,所以继承比较的接口,比较flowBean这个类
返回比较的顺序(内部用的是分区加排序)自定义比较
到此flowBean改完了
到此map端改完了
驱动方法的输入输出修改一下
自定义分区
3、统计流量且按照手机号的归属地,将结果数据输出到不同的省份文件中
134 江西0
135 北京1
136 上海2
137 天津3
138 重庆4
139 深圳5
其他 其他
map阶段
输出:
key:
value:
===========================
reducetask:7 7个分区,设置7个reducetask
===========================
reduce阶段
输入:
key:
value:
----------------------------
输出:
key:phonenum (按照号码段输出)
value:flowBean
要自定义Patition类分区,要实现partitioner方法,按照省份进行分区
patitioner是在map端的输出之后,进行分区,patitioner要获取到k值,则需要对key进行分区
数据类型要和map端的输出一样
进行分区
在flowCount类里面修改,将自定义的分区加入。已经设置Reduce的接收的参数
在客户端指定分区数
修改下面的hash取模的分区数
这个是源码的写法
这个是自定义的写法
分组Top1的实现
top-1的value可以不要,top-n的value是要的
map端输出的是类,shuffle的过程就是要进行分区,还有金额倒序,
Reduce端要将shuffle后端 合并成一个文件,合并过程中也是要排序的,用comparTo排序(比较大小而已)
循环迭代,就是比较key是否相等,而用groupingcomparator欺骗迭代器,也就是实现了同一个订单号调用一次Reduce方法
TOP 1
<Order_0000001,Pdt_01,222.8>
<Order_0000001,Pdt_05,25.8 >
<Order_0000002,Pdt_05,325.8>
<Order_0000002,Pdt_03,522.8>
<Order_0000002,Pdt_04,122.4>
<Order_0000003,Pdt_01,222.8>
先写一个类OrderBean,而且需要实现比较的接口,而且需要序列化
到此Javabean实现了。比普通类多实现序列化方法,和比较方法。
自定义partitioner,将订单号相同的orderBean发到一个Reduce,按订单号进行分区,订单号相同作为一个分区
按照订单号进行分组,功能就是用于欺骗迭代器,
先要实现一个无参构造,而且实现一个比较方法
最后要实现TopN
写一个驱动方法
在Reduce输出之前呢,将自定义分区,和分组比较的功能加上
top3是三次输出,但是这个是固定写死的
初始化和清空资源,通过context去获取资源,默认设置一个3的参数
方法一:topn的设置,可以动态设置top个数,可以作为参数进行传参
方法二:如果将上面这个注掉,将xml文件引入进来
context是全局性的,每一个参数都可以拿得到
初始化清空资源
setup
reduce
reduce
reduce
.....
cleanup