MapReduce学习3:序列化

    • 1 序列化概述
      • 1.1 什么是序列化和反序列化
      • 1.2 为什么要序列化
      • 1.3 为什么不用java序列化
      • 1.4 hadoop序列化特点
    • 2 实现hadoop的Writable接口
      • 2.1 hadoop的基本序列化类型
      • 2.2 接口实现基本步骤
    • 3 序列化案例实操

1 序列化概述

1.1 什么是序列化和反序列化

序列化就是把内存中的对象,转换成字节序列(或其他数据传输协议)以便于存储到磁盘(持久化)网络传输

反序列化就是将收到字节序列(或其他数据传输协议)或者是磁盘的持久化数据,转换成内存中的对象

1.2 为什么要序列化

—般来说,“活的”对象只生存在内存里,关机断电就没有了。而且“活的”对象只能本地的进程使用,不能被发送到网络上的另外一台计算机。然而序列化可以存储“活的”对象,可以将“活的”对象发送到远程计算机。也就是将对象序列化字节序列,然后就能被网络传输或者是存储到磁盘中,而不是存储在内存中,在断电以后就会消失

1.3 为什么不用java序列化

hadoop的信息处理也需要经过序列化,因为数据需要在介质之间传输,但是hadoop的序列化是自定义的,而不是使用Java的序列化。因为Java的序列化是一个重量级序列化框架Serializable),一个对象被序列化后,会附带很多额外的信息(各种校验信息,Header,继承体系等),不便于在网络中高效传输。所以,hadoop自己开发了一套序列化机制(Writable)。

1.4 hadoop序列化特点

  1. 紧凑  :高效使用存储空间。
  2. 快速  :读写数据的额外开销小。
  3. 可扩展 :随着通信协议的升级而可升级
  4. 互操作 :支持多语言的交互

2 实现hadoop的Writable接口

2.1 hadoop的基本序列化类型

hadoop中数据类型是自定义的,Java的对于每个基本类型的数在例如参数传递的场景都会经过序列化,但是hadoop不使用Java的序列化机制,所以就需要自定义自身的基本数据类型。以下是hadoop的基本数据类型和Java的对比
在这里插入图片描述
但是仅仅是基本数据类型的序列化是远远不够的,所以需要自行实现
Writable接口来自定义对象的序列化

2.2 接口实现基本步骤

  1. 自定的类需要实现Writable接口
  2. 提供无参数构造器(反序列化时会通过反射的方式调用无参数构造器来创建对象)重写
  3. write方法实现序列化的过程(自定义序列化的内容)
  4. 重写readFields方法实现反序列化的过程

3 序列化案例实操

1、需求分析:统计每一个手机号耗费的总上行流量、下行流量、总流量
2、期望输出

#手机号		 上行流量  下行流量  总流量
13560436666  1126     954      2080   

2、测试数据

#ID 手机号		IP			   上行流量  下行流量  网络状态码
1   13560436666 120.196.101.99 1126     954      200
2   13560436667 120.196.102.99 1136     954      200
3   13560436668 120.196.103.99 1146     954      200
4   13560436669 120.196.104.99 1156     954      200
5   13560436676 120.196.105.99 1166     954      200
6   13560436686 120.196.106.99 1176     954      200
7   13560436666 120.196.107.99 1126     954      200
8   13560436667 120.196.108.99 1136     954      200
9   13560436668 120.196.109.99 1146     954      200

3、实现思路:在map阶段会将每一行数据按空格进行切分,切分出手机号后,将对应的上行流量以及下行流量处理到一个bean对象,然后序列化输出。虽然是可以使用其他方法,但是这里仅就对序列化学习。对于简单的MapReduce程序编写可以看这里:MapReduce学习2-1:以官方wordcount实例为例的MapReduce程序学习

对于mapper程序通过context.write方法进行参数传递过程中会有一个写入磁盘的过程,所以需要序列化,对于hadoop的基本数据类型是已经实现了序列化而无需自行处理,但是对于其他对象就需要自行实现Writable接口

4、创建FlowBean类并实现Writable接口

package com.writable.maven;

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;

    FlowBean(){
    }


    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 void setSumFlow(){
        this.sumFlow = this.upFlow + this.downFlow;
    }

    public Long getSumFlow() {
        return sumFlow;
    }

    public void setSumFlow(Long sumFlow) {
        this.sumFlow = sumFlow;
    }
	
	// 实现Writable接口必须实现该方法,用以将数据序列化输出,输出顺序为执行顺序以及类型也为设置的类型,如下
    @Override
    public void write(DataOutput out) throws IOException {
        out.writeLong(this.upFlow);
        out.writeLong(this.downFlow);
        out.writeLong(this.sumFlow);
    }
    
	// 实现Writable接口必须实现该方法,用以将数据反序列化输出,执行顺序以及类型也为设置的类型与write方法相适应
    @Override
    public void readFields(DataInput in) throws IOException {
        this.upFlow = in.readLong();
        this.downFlow = in.readLong();
        this.sumFlow = in.readLong();
    }
    @Override
    public String toString() {
        return this.upFlow + "\t" + this.downFlow + "\t" + this.sumFlow;
    }

}

5、创建FlowMapper类

package com.writable.maven;

import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;

import java.io.IOException;


public class FlowMapper extends Mapper<LongWritable, Text, Text, FlowBean> {

    private Text outK = new Text();
    private FlowBean flowBean = new FlowBean();

    @Override
    protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
//        super.map(key, value, context);
		// 获取一行
        String line = value.toString();
		
		// 按空白分割一行
        String[] parts = line.split("\\s+");

        outK.set(parts[1]);

        flowBean.setUpFlow(Long.parseLong(parts[parts.length-3]));
        flowBean.setDownFlow(Long.parseLong(parts[parts.length-2]));
        flowBean.setSumFlow();

        context.write(outK, flowBean);

    }


}

6、创建FlowReducer

package com.writable.maven;

import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;

import java.io.IOException;

public class FlowReducer extends Reducer<Text, FlowBean,Text, FlowBean> {

    private FlowBean flowBean = new FlowBean();
    @Override
    protected void reduce(Text key, Iterable<FlowBean> values, Context context) throws IOException, InterruptedException {
//        super.reduce(key, values, context);

        Long sumUpFlow = 0L;
        Long sumDownFlow = 0L;

        for (FlowBean fb: values){
            sumUpFlow += fb.getUpFlow();
            sumDownFlow += fb.getDownFlow();
        }

        flowBean.setUpFlow(sumUpFlow);
        flowBean.setDownFlow(sumDownFlow);
        flowBean.setSumFlow();

        context.write(key, flowBean);

    }
}

7、创建FlowDriver

package com.writable.maven;

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.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

import java.io.IOException;



public class FlowDriver{

    public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {

        Configuration conf = new Configuration();
        Job job = new Job(conf);

        job.setJarByClass(FlowDriver.class);
        job.setMapperClass(FlowMapper.class);
        job.setReducerClass(FlowReducer.class);

        job.setMapOutputKeyClass(Text.class);
        job.setMapOutputValueClass(FlowBean.class);

        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(FlowBean.class);

		// 这里仅做本地测试
        FileInputFormat.setInputPaths(job, new Path("E:\\bigdata\\study\\test_files\\flowinput\\flow.txt"));
        FileOutputFormat.setOutputPath(job, new Path("E:\\bigdata\\study\\test_files\\flowoutput"));

        job.waitForCompletion(true);
    }

}

上述代码不多做解释,如需详细了解可看这里:MapReduce学习2-1:以官方wordcount实例为例的MapReduce程序学习

8、结果
MapReduce学习3:序列化_第1张图片

你可能感兴趣的:(#,MapReduce基础,mapreduce,hadoop,java)