大数据之hadoop中的序列化

2、hadoop序列化

        ·概述

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

        ·特点

                紧凑(高效使用存储空间);快速(读写数据较为轻便);互操作(支持多语言交互)

         ·自定义bean对象实现序列化接口

                自我理解:定义序列化接口就是为了将多个参数进行封装统一使用,方面后续的使用。

实现bean对象序列化步骤如下:

        必须实现Writable接口(implements)

        反序列化时,需要反射调用空参构造函数,必须要有空参构造

public FlowBean() {
super();
}

        重写序列化方法

@Override
public void write(DataOutput out) throws IOException {
    out.writeLong(upFlow);
    out.writeLong(downFlow);
    out.writeLong(sumFlow);
}

        重写反序列化方法

@Override
public void readFields(DataInput in) throws IOException {
upFlow = in.readLong();
downFlow = in.readLong();
sumFlow = in.readLong();
}

        注意反序列化的顺序和序列化的顺序完全一致

        要想把结果显示在文件中,需要重写 toString(),可用"\t"分开,方便后续用

        如果需要将自定义的 bean 放在 key 中传输,则还需要实现 Comparable 接口,因为 MapReduce 框中的 Shuffle 过程要求对 key 必须能排序。

@Override
public int compareTo(FlowBean o) {
// 倒序排列,从大到小
return this.sumFlow > o.getSumFlow() ? -1 : 1;
}

         序列化案例        

               首先准备一个数据文本(分别为索引,电话号码,ip,网址,上行流量,下行流量,状态码)。主要需求是计算一个手机号码的上行流量,下行流量和总流量。由于hadoop的map只能输出一个类型数值,因此创建一个FlowBean将上行流量,下行流量和总流量进行封装。

        接着编写一个FlowBean对象

package cn.itjdb.mapreduce.writable;

import org.apache.hadoop.io.Writable;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;

/**
 * 1、定义实现writable接口
 * 2、重写序列化和反序列化方法
 * 3、重写空参构造
 * 4、toString方法
 */
public class FlowBean implements Writable {
    //hadoop的序列化就是将多个参数封装在一起
    private Long upFlow; //上行流量
    private Long downFlow; //下行流量
    private Long 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 setSumFlow() {
        this.sumFlow = this.upFlow+this.downFlow;  //直接进行总流量计算
    }

    //重写空构造方法
    public FlowBean() {
    }

    //重写序列化方法
    @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();
        this.downFlow=dataInput.readLong();
        this.sumFlow=dataInput.readLong();
    }

    //重写toString方法


    @Override
    public String toString() {
        return upFlow +"/t" +downFlow +"/t" + sumFlow ;
    }
}

         编写Mapper类

package cn.itjdb.mapreduce.writable;

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 outV=new FlowBean();
    //重写map方法
    @Override
    protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
        //获取一行数据
        String line=value.toString();

        //将获取的一行数据进行切割
        String[] s = line.split("\t");  //原数据的数据是一个tab键进行分离的

        //获取要进行处理的数据
        String phone=s[1];
        String upFlow=s[s.length-3];
        String downFlow=s[s.length-2];
        //不能s[-3]这样提取数据
        //String upFlow=s[-3];
        //String downFlow=s[-2];
        System.out.println(phone);

        outK.set(phone);  //将String类型的phone转换为hadoop中的Text类型
        //将获取的数据进行封装到FlowBean中
        outV.setUpFlow(Long.parseLong(upFlow));  //若直接填upFlow会显示错误,要先将其转化为Long类型,再进行封装
        outV.setDownFlow(Long.parseLong(downFlow));
        outV.setSumFlow();//可以不写吗?,不可以,这是计算一行的总流量,而在map中计算的是同一个手机号的总流量

        //写出
        context.write(outK,outV);


    }
}

         编写Reduce类

package cn.itjdb.mapreduce.writable;

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

import java.io.IOException;


public class FlowReduce extends Reducer<Text,FlowBean,Text,FlowBean> {
    private FlowBean outV=new FlowBean();
    //重写reduce方法
    @Override
    protected void reduce(Text key, Iterable<FlowBean> values, Context context) throws IOException, InterruptedException {

        //遍历集合累加值
        long totalUp=0;
        long totalDown=0;
        for (FlowBean value : values) {
            totalUp+=value.getUpFlow();
            totalDown+=value.getDownFlow();
        }
        System.out.println("cc:"+key);
        //封装outK(已存在,不需要在定义),outV(全新的FlowBean)
        outV.setUpFlow(totalUp);
        outV.setDownFlow(totalDown);
        outV.setSumFlow();

        //写出
        context.write(key,outV);
    }
}

        编写Driver类

package cn.itjdb.mapreduce.writable;


import org.apache.hadoop.conf.Configuration;
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 java.io.IOException;

public class FlowDriver {
    public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
        //1、获取job
        Configuration configuration = new Configuration();
        Job job = Job.getInstance(configuration);

        //2、获取jar包路径
        job.setJarByClass(FlowDriver.class);

        //3、关联mapper和reduce
        job.setMapperClass(FlowMapper.class);
        job.setReducerClass(FlowReduce.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:\\input\\inputflow"));
        FileOutputFormat.setOutputPath(job,new Path("D:\\input\\outputflow"));

        //7、提交job
        boolean result=job.waitForCompletion(true);
        System.exit(result? 0:1);
    }
}

        本地模式:就可以在D:\\input\\outputflow路径下查看结果。

结果:

 

3、MapReduce框架原理

4、Hadoop数据压缩

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

独创之上

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

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

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

打赏作者

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

抵扣说明:

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

余额充值