需求:

处理以下流量数据,第1列是手机号,第7列是上行流量,第8列是下行流量。将手机号一样的用户进行合并,上行流量汇总,下行流量也汇总,并相加求得总流量。

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
1363157991076 13926435656 20-10-7A-28-CC-0A:CMCC 120.196.100.99 2 4 132 1512 200
1363154400022 13926251106 5C-0E-8B-8B-B1-50:CMCC 120.197.40.4 4 0 240 0 200
1363157993044 18211575961 94-71-AC-CD-E6-18:CMCC-EASY 120.196.100.99 iface.qiyi.com 视频网站 15 12 1527 2106 200
1363157995074 84138413 5C-0E-8B-8C-E8-20:7DaysInn 120.197.40.4 122.72.52.12 20 16 4116 1432 200
1363157993055 13560439658 C4-17-FE-BA-DE-D9:CMCC 120.196.100.99 18 15 1116 954 200
1363157995033 15920133257 5C-0E-8B-C7-BA-20:CMCC 120.197.40.4 sug.so.360.cn 信息安全 20 20 3156 2936 200
1363157983019 13719199419 68-A1-B7-03-07-B1:CMCC-EASY 120.196.100.82 4 0 240 0 200
1363157984041 13660577991 5C-0E-8B-92-5C-20:CMCC-EASY 120.197.40.4 s19.cnzz.com 站点统计 24 9 6960 690 200
1363157973098 15013685858 5C-0E-8B-C7-F7-90:CMCC 120.197.40.4 rank.ie.sogou.com 搜索引擎 28 27 3659 3538 200
1363157986029 15989002119 E8-99-C4-4E-93-E0:CMCC-EASY 120.196.100.99 www.umeng.com 站点统计 3 3 1938 180 200
1363157992093 13560439658 C4-17-FE-BA-DE-D9:CMCC 120.196.100.99 15 9 918 4938 200
1363157986041 13480253104 5C-0E-8B-C7-FC-80:CMCC-EASY 120.197.40.4 3 3 180 180 200
1363157984040 13602846565 5C-0E-8B-8B-B6-00:CMCC 120.197.40.4 2052.flash2-http.qq.com 综合门户 15 12 1938 2910 200
1363157995093 13922314466 00-FD-07-A2-EC-BA:CMCC 120.196.100.82 img.qfc.cn 12 12 3008 3720 200
1363157982040 13502468823 5C-0A-5B-6A-0B-D4:CMCC-EASY 120.196.100.99 y0.ifengimg.com 综合门户 57 102 7335 110349 200
1363157986072 18320173382 84-25-DB-4F-10-1A:CMCC-EASY 120.196.100.99 input.shouji.sogou.com 搜索引擎 21 18 9531 2412 200
1363157990043 13925057413 00-1F-64-E1-E6-9A:CMCC 120.196.100.55 t3.baidu.com 搜索引擎 69 63 11058 48243 200
1363157988072 13760778710 00-FD-07-A4-7B-08:CMCC 120.196.100.82 2 2 120 120 200
1363157985079 13823070001 20-7C-8F-70-68-1F:CMCC 120.196.100.99 6 3 360 180 200
1363157985069 13600217502 00-1F-64-E2-E8-B1:CMCC 120.196.100.55 18 138 1080 186852 200

思考:

和之前mapreduce讲解的那个统计单词的例子类似。在这里我们主要解决的是怎么处理map和reduce的输入输出。

首先看map,其输入的key是LongWritable,value是Text,绝对固定。为什么呢?我们之前说过,默认情况下,框架传递给我们的mapper的输入数据中,key是要处理的文本中一行的起始偏移量,这一行的内容作为value。

输出的key我们可以用手机号表示,那么就是Text,输出value我们既想表示出上行流量,又想表示下行流量,发现没有这种数据类型,所以就需要自定义一个类,进行传递。自定义类,就一定需要序列化,才可以传递哦。

然后看reduce,其输入key就是map的输出key,其输入value就是map的输出value。

输出key我们也可以用手机号表示,就是Text,输出value我们也用一个类进行表示。

下面我们编写该程序:

导入必要的包后,建立文件格式如下:

FlowBean.java:

package cn.darrenchan.hadoop.mr.flow;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException; import org.apache.hadoop.io.Writable; public class FlowBean implements Writable {
private String phoneNum;// 手机号
private long upFlow;// 上行流量
private long downFlow;// 下行流量
private long sumFlow;// 总流量 public FlowBean() {
super();
} public FlowBean(String phoneNum, long upFlow, long downFlow) {
super();
this.phoneNum = phoneNum;
this.upFlow = upFlow;
this.downFlow = downFlow;
this.sumFlow = upFlow + downFlow;
} public String getPhoneNum() {
return phoneNum;
} public void setPhoneNum(String phoneNum) {
this.phoneNum = phoneNum;
} 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;
} public long getSumFlow() {
return sumFlow;
} public void setSumFlow(long sumFlow) {
this.sumFlow = sumFlow;
} @Override
public String toString() {
return upFlow + "\t" + downFlow + "\t" + sumFlow;
} // 从数据流中反序列出对象的数据
// 从数据流中读出对象字段时,必须跟序列化时的顺序保持一致
@Override
public void readFields(DataInput in) throws IOException {
phoneNum = in.readUTF();
upFlow = in.readLong();
downFlow = in.readLong();
sumFlow = in.readLong();
} // 将对象数据序列化到流中
@Override
public void write(DataOutput out) throws IOException {
out.writeUTF(phoneNum);
out.writeLong(upFlow);
out.writeLong(downFlow);
out.writeLong(sumFlow);
} }

FlowMapper.java:

package cn.darrenchan.hadoop.mr.flow;

import java.io.IOException;

import org.apache.commons.lang.StringUtils;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper; public class FlowMapper extends Mapper<LongWritable, Text, Text, FlowBean> {
@Override
protected void map(LongWritable key, Text value, Context context)
throws IOException, InterruptedException {
// 将这一行的内容转换成string类型
String line = value.toString();
// 对这一行的文本按特定分隔符切分
String[] words = StringUtils.split(line, "\t"); //拿到我们需要的字段
String phoneNum = words[0];
long upFlow = Long.parseLong(words[7]);
long downFlow = Long.parseLong(words[8]); //封装数据为kv并输出
context.write(new Text(phoneNum), new FlowBean(phoneNum, upFlow, downFlow));
}
}

FlowReducer.java:

package cn.darrenchan.hadoop.mr.flow;

import java.io.IOException;

import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer; public class FlowReducer extends Reducer<Text, FlowBean, Text, FlowBean> { // 框架每传递一组数据<1387788654,{flowbean,flowbean,flowbean,flowbean.....}>调用一次我们的reduce方法
// reduce中的业务逻辑就是遍历values,然后进行累加求和再输出
@Override
protected void reduce(Text key, Iterable<FlowBean> values, Context context)
throws IOException, InterruptedException {
long upFlowCounter = 0;
long downFlowCounter = 0;
for (FlowBean flowBean : values) {
upFlowCounter += flowBean.getUpFlow();
downFlowCounter += flowBean.getDownFlow();
} context.write(key, new FlowBean(key.toString(), upFlowCounter,
downFlowCounter));
}
}

FlowRunner.java:

package cn.darrenchan.hadoop.mr.flow;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.conf.Configured;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.util.Tool;
import org.apache.hadoop.util.ToolRunner; //这是job描述和提交类的规范写法
//执行命令: hadoop jar flow.jar cn.darrenchan.hadoop.mr.flow.FlowRunner /flow/srcdata /flow/output
public class FlowRunner extends Configured implements Tool { @Override
public int run(String[] args) throws Exception {
Configuration conf = new Configuration();
Job job = Job.getInstance(conf); // 设置整个job所用的那些类在哪个jar包
job.setJarByClass(FlowRunner.class); // 本job使用的mapper和reducer的类
job.setMapperClass(FlowMapper.class);
job.setReducerClass(FlowReducer.class); job.setOutputKeyClass(Text.class);
job.setOutputValueClass(FlowBean.class); job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(FlowBean.class); // 指定要处理的输入数据存放路径
FileInputFormat.setInputPaths(job, new Path(args[0]));
// 指定处理结果的输出数据存放路径
FileOutputFormat.setOutputPath(job, new Path(args[1]));
// 将job提交给集群运行 ,将运行状态进行打印
return job.waitForCompletion(true) ? 0 : 1;
} public static void main(String[] args) throws Exception {
int res = ToolRunner.run(new Configuration(), new FlowRunner(), args);
System.exit(res);
} }

将要处理的文件上传到hdfs上一个目录,我的是/flow/srcdata。将程序打成jar包flow.jar,然后执行命令:

hadoop jar flow.jar cn.darrenchan.hadoop.mr.flow.FlowRunner /flow/srcdata /flow/output。

我们会得到如下运行效果:

17/02/26 04:35:23 INFO client.RMProxy: Connecting to ResourceManager at weekend110/192.168.230.134:8032
17/02/26 04:35:23 WARN mapreduce.JobSubmitter: Hadoop command-line option parsing not performed. Implement the Tool interface and execute your application with ToolRunner to remedy this.
17/02/26 04:35:24 INFO input.FileInputFormat: Total input paths to process : 1
17/02/26 04:35:24 INFO mapreduce.JobSubmitter: number of splits:1
17/02/26 04:35:24 INFO mapreduce.JobSubmitter: Submitting tokens for job: job_1488112052214_0001
17/02/26 04:35:25 INFO impl.YarnClientImpl: Submitted application application_1488112052214_0001
17/02/26 04:35:25 INFO mapreduce.Job: The url to track the job: http://weekend110:8088/proxy/application_1488112052214_0001/
17/02/26 04:35:25 INFO mapreduce.Job: Running job: job_1488112052214_0001
17/02/26 04:35:34 INFO mapreduce.Job: Job job_1488112052214_0001 running in uber mode : false
17/02/26 04:35:34 INFO mapreduce.Job: map 0% reduce 0%
17/02/26 04:35:39 INFO mapreduce.Job: map 100% reduce 0%
17/02/26 04:35:44 INFO mapreduce.Job: map 100% reduce 100%
17/02/26 04:35:44 INFO mapreduce.Job: Job job_1488112052214_0001 completed successfully
17/02/26 04:35:44 INFO mapreduce.Job: Counters: 49
File System Counters
FILE: Number of bytes read=1266
FILE: Number of bytes written=188391
FILE: Number of read operations=0
FILE: Number of large read operations=0
FILE: Number of write operations=0
HDFS: Number of bytes read=2338
HDFS: Number of bytes written=623
HDFS: Number of read operations=6
HDFS: Number of large read operations=0
HDFS: Number of write operations=2
Job Counters
Launched map tasks=1
Launched reduce tasks=1
Data-local map tasks=1
Total time spent by all maps in occupied slots (ms)=3661
Total time spent by all reduces in occupied slots (ms)=2568
Total time spent by all map tasks (ms)=3661
Total time spent by all reduce tasks (ms)=2568
Total vcore-seconds taken by all map tasks=3661
Total vcore-seconds taken by all reduce tasks=2568
Total megabyte-seconds taken by all map tasks=3748864
Total megabyte-seconds taken by all reduce tasks=2629632
Map-Reduce Framework
Map input records=22
Map output records=22
Map output bytes=1216
Map output materialized bytes=1266
Input split bytes=124
Combine input records=0
Combine output records=0
Reduce input groups=22
Reduce shuffle bytes=1266
Reduce input records=22
Reduce output records=22
Spilled Records=44
Shuffled Maps =1
Failed Shuffles=0
Merged Map outputs=1
GC time elapsed (ms)=147
CPU time spent (ms)=1400
Physical memory (bytes) snapshot=218402816
Virtual memory (bytes) snapshot=726446080
Total committed heap usage (bytes)=137433088
Shuffle Errors
BAD_ID=0
CONNECTION=0
IO_ERROR=0
WRONG_LENGTH=0
WRONG_MAP=0
WRONG_REDUCE=0
File Input Format Counters
Bytes Read=2214
File Output Format Counters
Bytes Written=623

最终的结果如下所示:

1363154400022 0 200 200
1363157973098 27 3659 3686
1363157982040 102 7335 7437
1363157983019 0 200 200
1363157984040 12 1938 1950
1363157984041 9 6960 6969
1363157985069 186852 200 187052
1363157985079 180 200 380
1363157986029 3 1938 1941
1363157986041 180 200 380
1363157986072 18 9531 9549
1363157988072 120 200 320
1363157990043 63 11058 11121
1363157991076 1512 200 1712
1363157992093 4938 200 5138
1363157993044 12 1527 1539
1363157993055 954 200 1154
1363157995033 20 3156 3176
1363157995052 0 200 200
1363157995074 4116 1432 5548
1363157995093 3008 3720 6728
1363157985066 2481 24681 27162

MapReduce实战(一)自定义类型的更多相关文章

  1. MapReduce实战:自定义输入格式实现成绩管理

    1. 项目需求 我们取有一份学生五门课程的期末考试成绩数据,现在我们希望统计每个学生的总成绩和平均成绩. 样本数据如下所示,每行数据的数据格式为:学号.姓名.语文成绩.数学成绩.英语成绩.物理成绩.化 ...

  2. 《Go语言实战》Go 类型:基本类型、引用类型、结构类型、自定义类型

    Go 语言是一种静态类型的编程语言,所以在编译器进行编译的时候,就要知道每个值的类型,这样编译器就知道要为这个值分配多少内存,并且知道这段分配的内存表示什么. 提前知道值的类型的好处有很多,比如编译器 ...

  3. Hadoop学习笔记—5.自定义类型处理手机上网日志

    转载自http://www.cnblogs.com/edisonchou/p/4288737.html Hadoop学习笔记—5.自定义类型处理手机上网日志 一.测试数据:手机上网日志 1.1 关于这 ...

  4. Android For JNI(五)——C语言多级指针,结构体,联合体,枚举,自定义类型

    Android For JNI(五)--C语言多级指针,结构体,联合体,枚举,自定义类型 我们的C已经渐渐的步入正轨了,基础过去之后,就是我们的NDK和JNI实战了 一.多级指针 指针的概念我们在前面 ...

  5. Hadoop日记Day13---使用hadoop自定义类型处理手机上网日志

    测试数据的下载地址为:http://pan.baidu.com/s/1gdgSn6r 一.文件分析 首先可以用文本编辑器打开一个HTTP_20130313143750.dat的二进制文件,这个文件的内 ...

  6. Hadoop生态圈-Azkaban实战之Command类型执行指定脚本

    Hadoop生态圈-Azkaban实战之Command类型执行指定脚本 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 1>.服务端测试代码(别忘记添加权限哟!) [yinzh ...

  7. golang 自定义类型的排序sort

    sort包中提供了很多排序算法,对自定义类型进行排序时,只需要实现sort的Interface即可,包括: func Len() int {... } func Swap(i, j int) {... ...

  8. Hadoop自定义类型处理手机上网日志

    job提交源码分析 在eclipse中的写的代码如何提交作业到JobTracker中的哪?(1)在eclipse中调用的job.waitForCompletion(true)实际上执行如下方法 con ...

  9. 【Hadoop离线基础总结】MapReduce案例之自定义groupingComparator

    MapReduce案例之自定义groupingComparator 求取Top 1的数据 需求 求出每一个订单中成交金额最大的一笔交易 订单id 商品id 成交金额 Order_0000005 Pdt ...

  10. 《精通C#》自定义类型转化-扩展方法-匿名类型-指针类型(11.3-11.6)

    1.类型转化在C#中有很多,常用的是int类型转string等,这些都有微软给我们定义好的,我们需要的时候直接调用就是了,这是值类型中的转化,有时候我们还会需要类类型(包括结构struct)的转化,还 ...

随机推荐

  1. Java笔记16:多线程共享数据

    一.Thread实现 public class ThreadDemo4 { publicstaticvoid main(String[] args) { new ThreadTest4().start ...

  2. git 超前一个版本 落后一个版本的解决方案

    在使用SourceTree的时候经常会遇见超前一个版本,落后N个版本的情况,遇见这种情况应该怎么办呢? 首先打开终端,最好是从SourceTree里面打开,菜单栏有个终端按钮. 然后输入: $ git ...

  3. 利用squid配置代理服务器-Fedora 19

    我的系统:  x86_64位Feodra 18 # yum install squid 不需要用户名密码认证的配置方式 edit /etc/squid/squid.conf # # Recommend ...

  4. os.waitpid()无法获取sys.exit()退出时的status code

    [目的] 父进程使用os.waitpid()等待子进程退出,并检测子进程的exit code,以决定是否重启子进程. (常见的应用场景是:子进程接收外部命令,收到"stop"时退出 ...

  5. wireshark在windows下无法抓取localhost数据包

    在调试SSL时要抓包,通过tcpview和minisniffer等工具明明看到tcp连接已经建立并开始收发数据了,但wireshark却总是无法抓到相应的数据包. 今天早上,HQ的高工告诉我“wire ...

  6. 【java】Could not find or load main class

    https://stackoverflow.com/questions/18093928/what-does-could-not-find-or-load-main-class-mean A comm ...

  7. 利用HTML5与jQuery技术创建一个简单的自动表单完成

    来源:GBin1.com 在线演示   在线下载 谷歌快速搜索自带大量自动完成插件——库中甚至还有一个附带的jQuery UI共享选项.然而今天我要寻找一个替代的解决方案.由DevBridge开发的j ...

  8. Cocos2dx&amp;Lua - UI显示优化之怎样解决解析大量json文件

    GUIReader中有个widgetFromJsonFile的方法,此方法是用于解析json文件(cocostudio生成的UI的)并返回该文件的父节点(Widget),然后便于进一步的UI操作(如获 ...

  9. webDriver API——第15部分Expected conditions Support

    class selenium.webdriver.support.expected_conditions.alert_is_present Bases: object Expect an alert ...

  10. 【Python】学习笔记八:面向对象

    举例 面向对象的合理解释就是:我是人这个类,对象化以后我就是一个个体OLIVER 对象化就是在人这个大类中,将某个人指名道姓,具体到某个人 下面是一个具体的实例一: #!/usr/bin/python ...