MapReduce-day02-第二章Hadoop序列化

本文介绍了一个基于Hadoop的流量统计案例,通过自定义序列化方式提高数据处理效率。案例详细讲解了如何利用MapReduce计算每个手机号的总上行流量、总下行流量及总流量。

1:序列化概述

        1:序列化就是内存中的对象转换成字节序列,反序列化就是字节序列转换成内存中的对象。

        2:原因:因为把一个虚拟机的内存中的对象数据传给另一台虚拟机内存,没办法传。

        3:不用Java的序列化原因:  因为Java的一个对象被序列化后,会覆盖很多额外的信息(各种校验信息、头、继承体系),不便于在网络中进行高效传输。

        4:特点:结构紧凑,高效使用存储空间。快速,读写数据的额外开销小。互操作性:支持多语言的交互。加入Hadoop102用Java语言编写,Hadoop103用C语言也可完成反序列化。

2:案例

1、# 需求:统计每一个手机号耗费的总上行流量、总下行流量、总流量

2、# 输入的数据文件是phone_data.txt
   # 输入的数据格式为:
   7    11012013044    110.120.130.44    1116     954     200
   id   手机号码       网络ip             上行流量 下行流量 网络状态码

3、#期望输出数据格式
   11012013044    1116    954     2070
   手机号码       上行流量 下行流量 总流量  
4、Map阶段
    1、读取一行数据、切分字段(\t空格都可以切割)
        7    11012013044    110.120.130.44    1116    954    200
    2、因为切割完是一个数组,可抽取手机号、上行流量、下行流量
        11012013044    1116      954
        手机号码        上行流量  下行流量   
    3、以手机号为key,bean对象为value输出,即context.write(手机号,bean)
    4、bean对象要想能够传输,必须实现序列化接口
5、Reduce阶段
    1、累加上行流量和下行流量得到总流量
        11012013044    1116    +    954    =    2070
        手机号码        上行流量     下行流量    总流量     

3:编码

        1:实体类

//1 继承 Writable 接口
public class FlowBean implements Writable {
    private long upFlow; //上行流量
    private long downFlow; //下行流量
    private long sumFlow; //总流量

    //2 提供无参构造
    public FlowBean() {
    }    

    //3 提供三个参数的 getter 和 setter 方法,三个参数都要进行,这里就列举一个,后续还有重写  toString方法,这里也不写了
    public long getUpFlow() {
        return upFlow;
    }
    public void setUpFlow(long upFlow) {
        this.upFlow = upFlow;
    }

    public void setSumFlow() {//这个比较特殊,因为最后要计算
        this.sumFlow = this.upFlow + this.downFlow;
    }


    //4 实现序列化和反序列化方法,注意顺序一定要保持一致
    @Override
    public void write(DataOutput dataOutput) throws IOException {
        dataOutput.writeLong(upFlow);
        dataOutput.writeLong(downFlow);
        dataOutput.writeLong(sumFlow);
    }
    @Override
    public void readFields(DataInput dataInput) throws IOException {
        this.upFlow = dataInput.readLong();//这个数据顺序和上面write方法里面对应
        this.downFlow = dataInput.readLong();
        this.sumFlow = dataInput.readLong();
    }

        2:Mapper类

public class FlowMapper extends Mapper<LongWritable, Text, Text, FlowBean> {
    private Text outK = new Text();
    private FlowBean outV = new FlowBean();

    @Override
    protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
    //1 获取一行数据,转成字符串   1   11012013044   110.120.130.44   1116   954  200
    String line = value.toString();
    //2 切割数据
    //1,11012013044,110.120.130.44,1116,954,200
    String[] split = line.split("\t");
    //3 抓取我们需要的数据:手机号,上行流量,下行流量
    String phone = split[1];
    String up = split[split.length - 3];
    String down = split[split.length - 2];
    //4 封装 outK outV
    outK.set(phone);
    outV.setUpFlow(Long.parseLong(up));
    outV.setDownFlow(Long.parseLong(down));
    outV.setSumFlow();//这个是上面那个单独设置的无参的set方法
    //5 写出 outK outV
    context.write(outK, outV);

        3:Reducer类

public class FlowReducer extends Reducer<Text, FlowBean, Text, FlowBean> {
    private FlowBean outV = new FlowBean();
    @Override
    protected void reduce(Text key, Iterable<FlowBean> values, Context context) throws     IOException, InterruptedException {
    //key为手机号,values是相同手机号对应的FlowBean
    //因为一个手机号可能对应多个上行和下行,所以有以下的参数值
    long totalUp = 0;
    long totalDown = 0;
    //1 遍历 values,将其中的上行流量,下行流量分别累加
    for (FlowBean flowBean : values) {
        totalUp += flowBean.getUpFlow();
        totalDown += flowBean.getDownFlow();
    }
    //2 封装 outKV
    outV.setUpFlow(totalUp);
    outV.setDownFlow(totalDown);
    outV.setSumFlow();
    //3 写出 outK outV
    context.write(key,outV);
    }
}

        4:Driver类

public class FlowDriver {
    public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
    //1 获取 job 对象
    Configuration conf = new Configuration();
    Job job = Job.getInstance(conf);
    //2 关联本 Driver 类
    job.setJarByClass(FlowDriver.class);
    //3 关联 Mapper 和 Reducer
    job.setMapperClass(FlowMapper.class);
    job.setReducerClass(FlowReducer.class);
 
    //4 设置 Map 端输出 KV 类型
    job.setMapOutputKeyClass(Text.class);
    job.setMapOutputValueClass(FlowBean.class);
 
    //5 设置程序最终输出的 KV 类型
    job.setOutputKeyClass(Text.class);
    job.setOutputValueClass(FlowBean.class);
 
    //6 设置程序的输入输出路径
    FileInputFormat.setInputPaths(job, new Path("D:\\inputflow"));
    FileOutputFormat.setOutputPath(job, new Path("D:\\flowoutput"));
 
    //7 提交 Job
    boolean b = job.waitForCompletion(true);
    System.exit(b ? 0 : 1);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

总会有天明

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值