一.序列化简介

什么是序列化呢?

【Hadoop】:MapReduce实现序列化_MapReduce

 

 

序列化:对象———》字节序列

反序列化:字节序列——》对象

备注:对象在内存(RAM)当中

字节序列:可以在磁盘(ROM)当中,也可以在网络当中进行传输

序列化的根本缘故:将对象从RAM里的数据 转化成ROM里的数据

二.序列化案例

我们这里将要编写的序列化的程序的流程如下图所示,是一个统计手机耗费总流量的case:
【Hadoop】:MapReduce实现序列化_MapReduce_02

 

 对于这个案例而言。为什么需要进行序列化呢?

因为在第三阶段,我们将手机的上行流量和下行流量都分别封装进了一个对象当中,一个手机号对应两个流量。因此一个bean对象(就是一个普通的对象,拥有方法,属性等)当中具有多个数据,因此需要进行序列化。

三.编写Bean类

现在我们开始封装这个手机的数据,代码如下所示。代码主要是为了封装value,也就是手机的上行流量以及下行流量,这里不处理手机号,不将手机号进行封装。因为手机号在我们的mapper阶段,我们将其视为Key同时注意要想把结果显示在文件中,需要重写toString(),且用"\t"分开,方便后续用。

import org.apache.hadoop.io.Writable;import java.io.DataInput;import java.io.DataOutput;import java.io.IOException;//建立每一个手机号所对应的对象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;
        sumFlow=upFlow+upFlow;
    }    //序列化方法,这样这个对象就可以很方便地进行序列化和反序列化了!    //序列化的方法必须和反序列化相同    @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 {        //必须要求和序列化要求顺序一致,顺序一致就可以进行接收
        upFlow=dataInput.readLong();
        downFlow= dataInput.readLong();
        sumFlow=dataInput.readLong();
    }

    @Override    public String toString() {        return upFlow + "\t" + downFlow + "\t" + 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;
    }    public long getSumFlow() {        return sumFlow;
    }    public void setSumFlow(long sumFlow) {        this.sumFlow = sumFlow;
    }    public void set(long upFlow,long downFlow)
    {
        upFlow=upFlow;
        downFlow=downFlow;
        sumFlow=upFlow+downFlow;
    }

}

在编写这个bean类当中,我们拥有了一个bean类所有的特征,比如get/set方法,以及需要拥有的序列化以及反序列化方法,可以在后续调用这个bean对象的时候,更加方便地进行序列化和反序列化。

四.编写Mapper类

将获得的手机号码设定为key,手机号的上行流量和下行流量分别设定为value,value使用bean类FlowBean来表示。(因为有两个value,而在mapper里面又只能够有一个输出,因此只能使用一个类来代表mapper的输出(valueout)了)

import org.apache.hadoop.io.LongWritable;import org.apache.hadoop.io.Text;import org.apache.hadoop.mapreduce.Mapper;import java.io.IOException;public class FlowCountMapper extends Mapper {
    @Override    protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
        Text k=new Text();
        FlowBean v=new FlowBean();        //1.获取一行,tostring方法已经被改写,因此
         String line=value.toString();        //2.切割
        String[] fields=line.split("\t");        //3.封装对象
        k.set(fields[1]);//封装手机号        //封装
        long upFlow= Long.parseLong(fields[fields.length-3]);        long downFlow=Long.parseLong(fields[fields.length-2]);
        v.setUpFlow(upFlow);
        v.setUpFlow(downFlow);        //v.set();        //4.写出        context.write(k,v);
    }
}

五.编写Reducer类

import org.apache.hadoop.mapreduce.Reducer;import javax.xml.soap.Text;import java.io.IOException;public class FlowCountReducer extends Reducer {
   FlowBean v=new FlowBean();
    @Override    protected void reduce(Text key, Iterablevalues, Context context) throws IOException, InterruptedException {        long sum_upFlow=0;        long sum_downflow=0;        //1.累加求和
        for (FlowBean flowBean:values)
        {
            sum_upFlow+=flowBean.getUpFlow();
            sum_downflow+=flowBean.getDownFlow();
        }

       v.set(sum_upFlow,sum_downflow);        //2.写出        context.write(key,v);
    }
}

六.编写Driver类

编写driver类是一个固定的步骤,可以直接根据注释当中的步骤进行编写即可,代码如下所示:

import org.apache.hadoop.conf.Configuration;import org.apache.hadoop.fs.Path;import org.apache.hadoop.mapreduce.Job;import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;import javax.xml.soap.Text;import java.io.IOException;public class FlowsumDriver {    public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
        Configuration configuration=new Configuration();        //1.获取job对象
        Job job=Job.getInstance(configuration);        //2.设置jar路径
        job.setJarByClass(FlowsumDriver.class);        //3.关联mapper和reducer
        job.setMapperClass(FlowCountMapper.class);
        job.setReducerClass(FlowCountReducer.class);        //4.设置mapper输出的key和value类型
        job.setMapOutputKeyClass(Text.class);
        job.setMapOutputKeyClass(FlowBean.class);        //5.设置最终输出的key和value类型
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(FlowBean.class);        //6.设置输出路径
        FileInputFormat.setInputPaths(job, new Path(args[0]));
        FileOutputFormat.setOutputPath(job,new Path(args[1]));        //7.提交job

        boolean result=job.waitForCompletion(true);
        System.out.println(result);
    }
}

这样我们就可以完成这个任务了!