Hadoop 序列化

Hadoop 序列化

Hadoop序列化机制

序列化简介

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

Hadoop序列化机制的起源

​ Hadoop涉及到大量的数据(在Java中就是对象)的传输(IO),并且网络带宽稀缺,因此使用序列化机制迫不及待,序列化就是把内存中的对象转化成二进制流进行传输。数据序列化的要求有四个(紧凑,快速,可扩展,支持互操作),而Java语言自带的序列化机制并不符合这些理想要求,因此专为Hadoop单独设计了一套序列化机制:Writable

Hadoop序列化和Java序列化的区别

  1. Java的序列化是一个重量级序列化框架(Serializable),
  2. 一个对象被序列化后,会附带很多额外的信息(各种校验信息,header,继承体系。),
  3. 不便于在网络中高效传输;

Hadoop的序列化机制Writable具有精简高效的特点。

Hadoop序列化

Hadoop在集群之间进行通讯或者RPC调用的时候,需要序列化,而且要求序列化要快,且体积要小,占用带宽要小。

序列化和反序列化在分布式数据处理领域经常出现:进程通信和永久存储。Hadoop中各个节点的通信是通过远程调用(RPC)实现的,RPC序列化具有以下特点:

  1. 紧凑:紧凑的格式能让我们充分利用网络带宽,而带宽是数据中心最稀缺的资;
  2. 快速:进程通信形成了分布式系统的骨架,所以需要尽量减少序列化和反序列化的性能开销,这是基本的;
  3. 可扩展:协议为了满足新的需求变化,所以控制客户端和服务器过程中,需要直接引进相应的协议,这些是新协议,原序列化方式能支持新的协议报文;
  4. 互操作:能支持不同语言写的客户端和服务端进行交互;

常用数据序列化类型

常用的数据类型对应的hadoop数据序列化类型

Java类型Hadoop Writable类型释义
booleanBooleanWritable标准布尔型数值
byteByteWritable单字节数值
intIntWritable整型数值
floatFloatWritable单精度数
longLongWritable长整型数值
doubleDoubleWritable双精度数
StringText使用UTF8格式存储的文本
mapMapWritable以键值对的形式存储Writable类型的数据
arrayArrayWritable以数组的形式存储Writable类型的数据
nullNullWritable当<key,value>中的key或value为空时使用

Writable 序列化接口

Writable的序列化和反序列化
  • write() 是把每个对象序列化到输出流———Writable序列化
  • readFields()是把输入流字节反序列化———-Writable反序列化
WritableNullWritable

NullWritableWritable 的一个特殊类型,它的序列化长度为0。它并不从数据流中读取数据,也不写入数据。它充当占位符;例如,在MapReduce 中,如果不需要使用键或值,就可以将键或值声明为NullWritable————结果是存储常量空值。如果希望存储一系列数值,与键/值对相对,NullWritable 也可以用作在SequenceFile中的键。它是一个不可变的单实例类型:通过调用NullWritable.get()方法可以获取这个实例。

WritableComparable 排序接口

WritableComparator是对继承自WritableComparable 类的RawComparator类的一个通 用实现。它提供两个主要功能。第一,它提供了对原始 compare()方 法的一个默认实现,该方法能够反序列化将在流中进行比较的对象,并调用对象的compare()方法。第二,它充当的是RawComparator 实例的工厂(已注册Writable的实现)。例如,为了获得IntWratablecomparator, 我们直接如下调用:

RawComparator<IntWritable> comparator = WritableComparator.get(Intwritable.class);

这个comparator可以用于比较两个IntWritable对象:

IntWritable w1 = new IntWritable(163);
IntWritable W2 = new IntWritable(67);
assertThat( comparator . compare(W1, W2), greaterThan(0));

或其序列化表示:

byte[] b1 = serialize(w1);
byte[] b2 = serialize(W2);
assertThat(comparator. compare(b1, B, b1.1ength, b2, 0, b2.1ength),
greaterThan(0));

MapReduce 来说,类型的比较是非常重要的,因为中间有个基于键的排序阶段。Hadoop 提供的一个优化接口是继承自Java ComparatorRawComparator接口:

package org. apache . hadoop.io;

import java . ut il . Comparator;

public interface RawComparator<T> extends Comparator<T> {
	public int compare(byte[] b1, int S1, int 11, byte[] b2,int s2,int 12);
}

该接口允许其实现直接比较数据流中的记录,无须先把数据流反序列化为对象,这样便避免了新建对象的额外开销。例如,使用IntWritable 接口实现的comparator实现了compare()方法,该方法可以从每个字节数组bl和b2中读取给定起始位置(s1和s2)以及长度(l1和I2)的一个整数进而直接进行比较。

自定义对象实现MR的序列化接口

使用自定义类型的原因

自带的类实现了对整形,浮点型,布尔型及StringText类)的封装,都是比较简单的数据类型,在实际应用中,对于一些属于用户自己的功能,系统无法预知,通常需要自定义数据类型。

自定义类型

如果需要将自定义的bean放在key中传输,则还需要实现comparable接口,因为Mapreduce框中的shuffle过程一定会对key进行排序,自定义的bean实现的接口:

public  class  Cat  implements  WritableComparable<Cat>
  • 重写readFields(DataInput in) 方法,实现反序列化
  • 重写write(DataOutput out)方法,实现序列化
  • 重写compareTo(Cat o)方法,实现排序
    • compareTo() 方法返回值
      • 如果 this的值等于传入的参数 返回 0
      • 如果this的值小于传入的参数 返回 负数
      • 如果this的值大于传入的参数 返回 正数

案例

package hadoop.mr.custom.GroupingComparator;

import org.apache.hadoop.io.WritableComparable;

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

/**
 * 订单bean
 */
public class OrderBean implements WritableComparable<OrderBean>{

    private String orderId;

    private String productId;

    private Double amount;

    public String getOrderId() {
        return orderId;
    }

    public void setOrderId(String orderId) {
        this.orderId = orderId;
    }

    public String getProductId() {
        return productId;
    }

    public void setProductId(String productId) {
        this.productId = productId;
    }

    public Double getAmount() {
        return amount;
    }

    public void setAmount(Double amount) {
        this.amount = amount;
    }

    /**
     * 现在需要求出每一个订单中成交金额最大的一笔交易
     * 订单id视为相同订单
     *  相同订单按金额降序排序
     *
     *  compareTo() 方法返回值
     *      如果 this的值等于传入的参数    返回 0
     *      如果this的值小于传入的参数     返回 负数
     *      如果this的值大于传入的参数     返回 正数
     * @param o
     * @return
     */
    @Override
    public int compareTo(OrderBean o) {
        int cmp = this.orderId.compareTo(o.getOrderId());
        if (cmp==0){
            //降序排序
            cmp= -this.amount.compareTo(o.getAmount());
        }
        return cmp;
    }

    @Override
    public void write(DataOutput out) throws IOException {
        out.writeUTF(orderId);
        out.writeUTF(productId);
        out.writeDouble(amount);
    }

    @Override
    public void readFields(DataInput in) throws IOException {
        orderId=in.readUTF();
        productId=in.readUTF();
        amount=in.readDouble();
    }

    @Override
    public String toString() {
        return "orderId='" + orderId + '\'' +
                ", productId='" + productId + '\'' +
                ", amount=" + amount ;
    }
}

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值