需求:

处理以下流量数据,第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. Fedora 中的容器技术:systemd-nspawn

    本文将说明你可以怎样使用 Fedora 中各种可用的容器技术和学习“systemd-nspawn”的相关知识. 容器是什么? 一个容器就是一个用户空间实例,它能够在与托管容器的系统(叫做宿主系统)相隔 ...

  2. 如何使用awk的比较操作符

    对于使用 awk 命令的用户来说,处理一行文本中的数字或者字符串时,使用比较运算符来过滤文本和字符串是十分方便的.下面的部分我们介绍"awk"的比较运算符. awk 中的比较运算符 ...

  3. 我的自动化测试历程(Selenium+TestNG+Java+ReportNG+Jenkins)

    原地址:http://blog.csdn.net/shilinjie_8952/article/details/53380373?locationNum=11&fps=1 测试环境:Java+ ...

  4. 云计算之路-试用Azure:一次失败的SQL Server向SQL Azure的迁移尝试

    如果数据库用的是SQL Server,那SQL Azure无疑是最吸引人的地方之一.在测试了虚拟机磁盘IO之后,我们迫不急待地进行了SQL Azure的测试. (一) 首先进入manage.windo ...

  5. 2013年八月GBin1月刊

    2013年八月GBin1月刊 推荐十款来自极客标签的超棒前端特效[第十二期] 本周,我们带来了极客社区推荐的10款前端特效,仍然是非常有趣的小动态效果的页面生成.喜欢的可以直接将我们的在线调试代码插入 ...

  6. C++ Primer笔记2_四种类型转换_异常机制

    1.类型转换 命名的强制类型转换: 有static_cast.dynamic_cast.const_cast.reinterpret_cast static_cast: 编译器隐式运行的不论什么类型转 ...

  7. 使用 ssh 从 Gerrit 获取 patch 信息

    使用命令行(ssh)对Gerrit进行查询, 官方地址:https://review.openstack.org/Documentation/cmd-query.html 程序例子 import os ...

  8. C 输入一串数字,去掉当中含7的和能被7整除的数

    C 输入一串数字,去掉当中含7的和能被7整除的数,每一个数小于10000,数字个数小于100 输入样例:1,7,56,77,87,2,45,42,97,9977 输出:1,2,45 注意:输入个数不确 ...

  9. C++11: reference_wrapper

    https://oopscenities.net/2012/08/09/reference_wrapper/ Look at this piece of code: 1 2 3 4 5 6 7 8 9 ...

  10. Chisel Tutorial(六)——port

    下面内容根据2015-7-10版的Chisel 2.2 Tutorial整理 port就是硬件单元对外的接口,须要指明方向(输入还是输出).一个port声明的样例例如以下: class Decoupl ...