Hadoop案例(九)流量汇总案例
流量汇总程序案例
1.自定义输出
统计手机号耗费的总上行流量、下行流量、总流量(序列化)
1)需求: 统计每一个手机号耗费的总上行流量、下行流量、总流量
2)数据准备 phone_date.txt
-FD--A4--B8:CMCC 120.196.100.82 i02.c.aliimg.com
5C-0E-8B-C7-F1-E0:CMCC 120.197.40.4
--7A--CC-0A:CMCC 120.196.100.99
5C-0E-8B-8B-B1-:CMCC 120.197.40.4
--AC-CD-E6-:CMCC-EASY 120.196.100.99 iface.qiyi.com 视频网站
5C-0E-8B-8C-E8-:7DaysInn 120.197.40.4 122.72.52.12
C4--FE-BA-DE-D9:CMCC 120.196.100.99
5C-0E-8B-C7-BA-:CMCC 120.197.40.4 sug.so..cn 信息安全
-A1-B7---B1:CMCC-EASY 120.196.100.82
5C-0E-8B--5C-:CMCC-EASY 120.197.40.4 s19.cnzz.com 站点统计
5C-0E-8B-C7-F7-:CMCC 120.197.40.4 rank.ie.sogou.com 搜索引擎
E8--C4-4E--E0:CMCC-EASY 120.196.100.99 www.umeng.com 站点统计
C4--FE-BA-DE-D9:CMCC 120.196.100.99
5C-0E-8B-C7-FC-:CMCC-EASY 120.197.40.4
5C-0E-8B-8B-B6-:CMCC 120.197.40.4 .flash2-http.qq.com 综合门户
-FD--A2-EC-BA:CMCC 120.196.100.82 img.qfc.cn
5C-0A-5B-6A-0B-D4:CMCC-EASY 120.196.100.99 y0.ifengimg.com 综合门户
--DB-4F--1A:CMCC-EASY 120.196.100.99 input.shouji.sogou.com 搜索引擎
-1F--E1-E6-9A:CMCC 120.196.100.55 t3.baidu.com 搜索引擎
-FD--A4-7B-:CMCC 120.196.100.82
-FD--A4--B8:CMCC 120.196.100.82 i02.c.aliimg.com
C4--FE-BA-DE-D9:CMCC 120.196.100.99
输入数据格式:
1363157993055 13560436666 C4-17-FE-BA-DE-D9:CMCC 120.196.100.99 18 15 1116 954 200
手机号码 上行流量 下行流量
输出数据格式
13560436666 1116 954 2070
手机号码 上行流量 下行流量 总流量
3)分析
基本思路:
Map阶段:
(1)读取一行数据,切分字段
(2)抽取手机号、上行流量、下行流量
(3)以手机号为key,bean对象为value输出,即context.write(手机号,bean);
Reduce阶段:
(1)累加上行流量和下行流量得到总流量。
(2)实现自定义的bean来封装流量信息,并将bean作为map输出的key来传输
(3)MR程序在处理数据的过程中会对数据排序(map输出的kv对传输到reduce之前,会排序),排序的依据是map输出的key
所以,我们如果要实现自己需要的排序规则,则可以考虑将排序因素放到key中,让key实现接口:WritableComparable。
然后重写key的compareTo方法。
4)编写mapreduce程序
(1)编写流量统计的bean对象
package com.xyg.mr.flowsum;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import org.apache.hadoop.io.Writable; // bean对象要实例化
public class FlowBean implements Writable { private long upFlow;
private long downFlow;
private long sumFlow; // 反序列化时,需要反射调用空参构造函数,所以必须有
public FlowBean() {
super();
} public FlowBean(long upFlow, long downFlow) {
super();
this.upFlow = upFlow;
this.downFlow = downFlow;
this.sumFlow = upFlow + downFlow;
} public long getSumFlow() {
return sumFlow;
} public void setSumFlow(long sumFlow) {
this.sumFlow = sumFlow;
} public long getUpFlow() {
return upFlow;
} public void setUpFlow(long upFlow) {
this.upFlow = upFlow;
} public long getDownFlow() {
return downFlow;
} public void setDownFlow(long downFlow) {
this.downFlow = downFlow;
} /**
* 序列化方法
*
* @param out
* @throws IOException
*/
@Override
public void write(DataOutput out) throws IOException {
out.writeLong(upFlow);
out.writeLong(downFlow);
out.writeLong(sumFlow);
} /**
* 反序列化方法
注意反序列化的顺序和序列化的顺序完全一致
*
* @param in
* @throws IOException
*/
@Override
public void readFields(DataInput in) throws IOException {
upFlow = in.readLong();
downFlow = in.readLong();
sumFlow = in.readLong();
} @Override
public String toString() {
return upFlow + "\t" + downFlow + "\t" + sumFlow;
}
}
(2)编写mapreduce主程序
package com.xyg.mr.flowsum;
import java.io.IOException;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; public class FlowCount { static class FlowCountMapper extends Mapper<LongWritable, Text, Text, FlowBean> { @Override
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
// 1 将一行内容转成string
String ling = value.toString(); // 2 切分字段
String[] fields = ling.split("\t"); // 3 取出手机号码
String phoneNum = fields[]; // 4 取出上行流量和下行流量
long upFlow = Long.parseLong(fields[fields.length - ]);
long downFlow = Long.parseLong(fields[fields.length - ]); // 5 写出数据
context.write(new Text(phoneNum), new FlowBean(upFlow, downFlow));
}
} static class FlowCountReducer extends Reducer<Text, FlowBean, Text, FlowBean> {
@Override
protected void reduce(Text key, Iterable<FlowBean> values, Context context)
throws IOException, InterruptedException {
long sum_upFlow = ;
long sum_downFlow = ; // 1 遍历所用bean,将其中的上行流量,下行流量分别累加
for (FlowBean bean : values) {
sum_upFlow += bean.getUpFlow();
sum_downFlow += bean.getDownFlow();
} // 2 封装对象
FlowBean resultBean = new FlowBean(sum_upFlow, sum_downFlow);
context.write(key, resultBean);
}
} public static void main(String[] args) throws Exception {
// 1 获取配置信息,或者job对象实例
Configuration configuration = new Configuration();
Job job = Job.getInstance(configuration); // 6 指定本程序的jar包所在的本地路径
job.setJarByClass(FlowCount.class); // 2 指定本业务job要使用的mapper/Reducer业务类
job.setMapperClass(FlowCountMapper.class);
job.setReducerClass(FlowCountReducer.class); // 3 指定mapper输出数据的kv类型
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(FlowBean.class); // 4 指定最终输出的数据的kv类型
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(FlowBean.class); // 5 指定job的输入原始文件所在目录
FileInputFormat.setInputPaths(job, new Path(args[]));
FileOutputFormat.setOutputPath(job, new Path(args[])); // 7 将job中配置的相关参数,以及job所用的java类所在的jar包, 提交给yarn去运行
boolean result = job.waitForCompletion(true);
System.exit(result ? : );
}
}
(3)将程序打成jar包,然后拷贝到hadoop集群中。
(4)启动hadoop集群(3)将程序打成jar包,然后拷贝到hadoop集群中。
(5)执行flowcount程序
[root@node21 ~]$ hadoop jar flowcount.jar com.xyg.mr.flowsum.FlowCount /user/root/flowcount/input/ /user/root/flowcount/output
(6)查看结果
[root@node21 ~]$ hadoop fs -cat /user/root/flowcount/output/part-r-00000
13480253104 FlowBean [upFlow=180, downFlow=180, sumFlow=360]
13502468823 FlowBean [upFlow=7335, downFlow=110349, sumFlow=117684]
13560436666 FlowBean [upFlow=1116, downFlow=954, sumFlow=2070]
13560439658 FlowBean [upFlow=2034, downFlow=5892, sumFlow=7926]
13602846565 FlowBean [upFlow=1938, downFlow=2910, sumFlow=4848]
。。。
2.自定义分区
将统计结果按照手机归属地不同省份输出到不同文件中(Partitioner)
0)需求:将统计结果按照手机归属地不同省份输出到不同文件中(分区)
1)数据准备 phone_date.txt
2)分析
(1)Mapreduce中会将map输出的kv对,按照相同key分组,然后分发给不同的reducetask。默认的分发规则为:根据key的hashcode%reducetask数来分发
(2)如果要按照我们自己的需求进行分组,则需要改写数据分发(分组)组件Partitioner
自定义一个CustomPartitioner继承抽象类:Partitioner
(3)在job驱动中,设置自定义partitioner: job.setPartitionerClass(CustomPartitioner.class)
3)在需求1的基础上,增加一个分区类
package com.xyg.mr.partitioner;
import java.util.HashMap;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Partitioner; /**
* K2 V2 对应的是map输出kv类型
* @author Administrator
*/
public class ProvincePartitioner extends Partitioner<Text, FlowBean> {
@Override
public int getPartition(Text key, FlowBean value, int numPartitions) {
// 1 获取电话号码的前三位
String preNum = key.toString().substring(, ); int partition = ; // 2 判断是哪个省
if ("".equals(preNum)) {
partition = ;
}else if ("".equals(preNum)) {
partition = ;
}else if ("".equals(preNum)) {
partition = ;
}else if ("".equals(preNum)) {
partition = ;
}
return partition;
}
}
2)在驱动函数中增加自定义数据分区设置和reduce task设置
public static void main(String[] args) throws Exception {
// 1 获取配置信息,或者job对象实例
Configuration configuration = new Configuration();
Job job = Job.getInstance(configuration); // 6 指定本程序的jar包所在的本地路径
job.setJarByClass(FlowCount.class); // 8 指定自定义数据分区
job.setPartitionerClass(ProvincePartitioner.class); // 9 同时指定相应数量的reduce task
job.setNumReduceTasks(); // 2 指定本业务job要使用的mapper/Reducer业务类
job.setMapperClass(FlowCountMapper.class);
job.setReducerClass(FlowCountReducer.class); // 3 指定mapper输出数据的kv类型
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(FlowBean.class); // 4 指定最终输出的数据的kv类型
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(FlowBean.class); // 5 指定job的输入原始文件所在目录
FileInputFormat.setInputPaths(job, new Path(args[]));
FileOutputFormat.setOutputPath(job, new Path(args[])); // 7 将job中配置的相关参数,以及job所用的java类所在的jar包, 提交给yarn去运行
boolean result = job.waitForCompletion(true);
System.exit(result ? : );
}
3)将程序打成jar包,然后拷贝到hadoop集群中。
4)启动hadoop集群
5)执行flowcountPartitionser程序
[root@node21 ~]$ hadoop jar flowcountPartitionser.jar com.xyg.mr.partitioner.FlowCount /user/root/flowcount/input /user/root/flowcount/output
6)查看结果
[root@node21 ~]]$ hadoop fs -lsr /
/user/root/flowcount/output/part-r-00000
/user/root/flowcount/output/part-r-00001
/user/root/flowcount/output/part-r-00002
/user/root/flowcount/output/part-r-00003
/user/root/flowcount/output/part-r-00004
3.自定义全排序
将统计结果按照总流量倒序排序(全排序)
0)需求 根据需求1产生的结果再次对总流量进行排序。
1)数据准备 phone_date.txt
2)分析
(1)把程序分两步走,第一步正常统计总流量,第二步再把结果进行排序
(2)context.write(总流量,手机号)
(3)FlowBean实现WritableComparable接口重写compareTo方法
@Override
public int compareTo(FlowBean o) {
// 倒序排列,从大到小
return this.sumFlow > o.getSumFlow() ? -1 : 1;
}
package com.xyg.mr.sort;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import org.apache.hadoop.io.WritableComparable; public class FlowBean implements WritableComparable<FlowBean> { private long upFlow;
private long downFlow;
private long sumFlow; // 反序列化时,需要反射调用空参构造函数,所以必须有
public FlowBean() {
super();
} public FlowBean(long upFlow, long downFlow) {
super();
this.upFlow = upFlow;
this.downFlow = downFlow;
this.sumFlow = upFlow + downFlow;
} public void set(long upFlow, long downFlow) {
this.upFlow = upFlow;
this.downFlow = downFlow;
this.sumFlow = upFlow + downFlow;
} public long getSumFlow() {
return sumFlow;
} public void setSumFlow(long sumFlow) {
this.sumFlow = sumFlow;
} public long getUpFlow() {
return upFlow;
} public void setUpFlow(long upFlow) {
this.upFlow = upFlow;
} public long getDownFlow() {
return downFlow;
} public void setDownFlow(long downFlow) {
this.downFlow = downFlow;
} /**
* 序列化方法
* @param out
* @throws IOException
*/
@Override
public void write(DataOutput out) throws IOException {
out.writeLong(upFlow);
out.writeLong(downFlow);
out.writeLong(sumFlow);
} /**
* 反序列化方法 注意反序列化的顺序和序列化的顺序完全一致
* @param in
* @throws IOException
*/
@Override
public void readFields(DataInput in) throws IOException {
upFlow = in.readLong();
downFlow = in.readLong();
sumFlow = in.readLong();
} @Override
public String toString() {
return upFlow + "\t" + downFlow + "\t" + sumFlow;
} @Override
public int compareTo(FlowBean o) {
// 倒序排列,从大到小
return this.sumFlow > o.getSumFlow() ? - : ;
}
}
4)Map方法优化为一个对象,reduce方法则直接输出结果即可,驱动函数根据输入输出重写配置即可。3)FlowBean对象在在需求1基础上增加了比较功能
package com.xyg.mr.sort;
import java.io.IOException;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; public class FlowCountSort {
static class FlowCountSortMapper extends Mapper<LongWritable, Text, FlowBean, Text>{
FlowBean bean = new FlowBean();
Text v = new Text(); @Override
protected void map(LongWritable key, Text value, Context context)
throws IOException, InterruptedException { // 1 拿到的是上一个统计程序输出的结果,已经是各手机号的总流量信息
String line = value.toString(); // 2 截取字符串并获取电话号、上行流量、下行流量
String[] fields = line.split("\t");
String phoneNbr = fields[]; long upFlow = Long.parseLong(fields[]);
long downFlow = Long.parseLong(fields[]); // 3 封装对象
bean.set(upFlow, downFlow);
v.set(phoneNbr); // 4 输出
context.write(bean, v);
}
} static class FlowCountSortReducer extends Reducer<FlowBean, Text, Text, FlowBean>{ @Override
protected void reduce(FlowBean bean, Iterable<Text> values, Context context)
throws IOException, InterruptedException {
context.write(values.iterator().next(), bean);
}
} public static void main(String[] args) throws Exception {
// 1 获取配置信息,或者job对象实例
Configuration configuration = new Configuration();
Job job = Job.getInstance(configuration); // 6 指定本程序的jar包所在的本地路径
job.setJarByClass(FlowCountSort.class); // 2 指定本业务job要使用的mapper/Reducer业务类
job.setMapperClass(FlowCountSortMapper.class);
job.setReducerClass(FlowCountSortReducer.class); // 3 指定mapper输出数据的kv类型
job.setMapOutputKeyClass(FlowBean.class);
job.setMapOutputValueClass(Text.class); // 4 指定最终输出的数据的kv类型
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(FlowBean.class); // 5 指定job的输入原始文件所在目录
FileInputFormat.setInputPaths(job, new Path(args[])); Path outPath = new Path(args[]);
// FileSystem fs = FileSystem.get(configuration);
// if (fs.exists(outPath)) {
// fs.delete(outPath, true);
// }
FileOutputFormat.setOutputPath(job, outPath); // 7 将job中配置的相关参数,以及job所用的java类所在的jar包, 提交给yarn去运行
boolean result = job.waitForCompletion(true);
System.exit(result ? : );
}
}
5)将程序打成jar包,然后拷贝到hadoop集群中。
6)启动hadoop集群5)将程序打成jar包,然后拷贝到hadoop集群中。
7)执行flowcountsort程序
[root@node21 module]$ hadoop jar flowcountsort.jar com.xyg.mr.sort.FlowCountSort /user/root/flowcount/output /user/root/flowcount/output_sort
8)查看结果
[root@node21 module]$ hadoop fs -cat /user/flowcount/output_sort/part-r-00000
13502468823 7335 110349 117684
13925057413 11058 48243 59301
13726238888 2481 24681 27162
13726230503 2481 24681 27162
18320173382 9531 2412 11943
4.自定义局部排序
不同省份输出文件内部排序(部分排序)
1)需求 要求每个省份手机号输出的文件中按照总流量内部排序。
2)分析 基于需求3,增加自定义分区类即可。
3)案例实操
(1)增加自定义分区类
package com.xyg.reduce.flowsort; import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Partitioner; public class FlowSortPartitioner extends Partitioner<FlowBean, Text> { @Override
public int getPartition(FlowBean key, Text value, int numPartitions) { int partition = ;
String preNum = value.toString().substring(, ); if (" ".equals(preNum)) {
partition = ;
} else {
if ("".equals(preNum)) {
partition = ;
} else if ("".equals(preNum)) {
partition = ;
} else if ("".equals(preNum)) {
partition = ;
} else if ("".equals(preNum)) {
partition = ;
}
}
return partition;
}
}
(2)在驱动类中添加分区类
job.setPartitionerClass(FlowSortPartitioner.class);
job.setNumReduceTasks(5);
Hadoop案例(九)流量汇总案例的更多相关文章
- Hadoop序列化-流量汇总案例
Hadoop序列化案例-流量汇总需求 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.Hadoop序列化 1>.为什么要序列化 一般来说,“活的”对象只生存在内存里,关机断 ...
- js上 十九、综合案例
十九.综合案例 题目一: 封装一个函数equal(a1,a2),传入两个一维数组,判断两个数组是否包含相同的元素,如果相等,函数的返回值为true, 不相等,函数的返回值为false 1)例:arr1 ...
- MapReduce分析流量汇总
一.MapReduce编程规范 一.MapReduce编程规范 用户编写mr程序主要分为三个部分:Mapper,Reducer,Driver 1.Mapper阶段 (1)用户自定义Mapper类 要继 ...
- 【hadoop代码笔记】hadoop作业提交之汇总
一.概述 在本篇博文中,试图通过代码了解hadoop job执行的整个流程.即用户提交的mapreduce的jar文件.输入提交到hadoop的集群,并在集群中运行.重点在代码的角度描述整个流程,有些 ...
- atitit.ajax bp dwr 3.该票据安排使用的流量汇总 VO9o.....
atitit.ajax bp dwr 3.该票据安排使用的流量汇总 VO9o..... 1. 安装配置 1 1.1. 下载 dwr.jar 1M 1 1.2. 配置注解方式..web.xml 1 2 ...
- 22_Android中的本地音乐播放器和网络音乐播放器的编写,本地视频播放器和网络视频播放器,照相机案例,偷拍案例实现
1 编写以下案例: 当点击了"播放"之后,在手机上的/mnt/sdcard2/natural.mp3就会播放. 2 编写布局文件activity_main.xml <Line ...
- hadoop namenode格式化问题汇总
hadoop namenode格式化问题汇总 (持续更新) 0 Hadoop集群环境 3台rhel6.4,2个namenode+2个zkfc, 3个journalnode+zookeeper-serv ...
- 北京U3D外包团队 UE4红军抗战案例 Unity3D红军抗战案例 UE4下载和安装虚幻4游戏引擎
刚完整UE4红军抗战案例 Unity3D红军抗战案例,有在线演示(版权关系不方便发图),有UE4或Unity项目定制外包开发的欢迎联系我们 进入虚幻4的官方主页(https://www.unreale ...
- 第2节 mapreduce深入学习:8、手机流量汇总求和
第2节 mapreduce深入学习:8.手机流量汇总求和 例子:MapReduce综合练习之上网流量统计. 数据格式参见资料夹 需求一:统计求和 统计每个手机号的上行流量总和,下行流量总和,上行总流量 ...
随机推荐
- array_filter 过滤一维中空数组,数组的序列不变
<?php header('Content-type:text;charset=utf8'); $str = "%11111%22222%333333%"; $arr = e ...
- 深度学习voc数据集图片resize
本人新写的3个pyhton脚本. (1)单张图片的resize: # coding = utf-8 import Image def convert(width,height): im = Image ...
- spring boot 2.0.3+spring cloud (Finchley)8、微服务监控Spring Boot Admin
参考:Spring Boot Admin 2.0 上手 Spring Boot Admin 用于管理和监控一个或多个Spring Boot程序,在 Spring Boot Actuator 的基础上提 ...
- 对拍 bat
:loop maker.exe std.exe my.exe fc std.out my.out goto loop pause
- bzoj 2502 清理雪道 (有源汇上下界最小流)
2502: 清理雪道 Time Limit: 10 Sec Memory Limit: 128 MB Description 滑雪场坐落在FJ省西北部的若干座山上. 从空中鸟瞰,滑雪场 ...
- javascript 获取函数形参
/** * 获取函数的形参个数 * @param {Function} func [要获取的函数] * @return {*} [形参的数组或undefind] */ function getFunc ...
- 区分IE8 、IE9 的专属css hack
一般来说,我们写的结构比较好的时候,IE8/9下是没区别的.所以可能很少人关注只有IE8或只有IE9才识别的css hack. 因为IE8及以下版本是不支持CSS3的,但是我们如果使用css3,在IE ...
- input复选框checkbox默认样式纯css修改
修改之前的样式 修改之后的样式 html <input type="checkbox" name="btn" id="btn1"&g ...
- VC拷贝字符串到剪切板
] ="中华人民共和国"; DWORD dwLength = ; // 要复制的字串长度 HANDLE hGlobalMemory = GlobalAlloc(GHND, dwLe ...
- VC连接access
(1)首先拷贝 c:\program files\common files\system\ado\ 目录中的 msado15.dll 文件到项目中. (2)在VC中加入DLL,具体方法如下: (3)创 ...