IT虾米网

hadoop文件的序列化详解

admin 2018年06月04日 大数据 312 0

目录

    1、为什么要序列化?

    2、什么是序列化?

    3、为什么不用Java的序列化?

    4、为什么序列化对Hadoop很重要?

    5、Hadoop中定义哪些序列化相关的接口呢?

    6、Hadoop 自定义Writable 接口

1、为什么要序列化?

     一般来说,"活的"对象只存在内存里,关机断电就没有了。而且"活的"对象只能由本地的进程使用,不能被发送到网络上的另外一台计算机。 然而序列化可以存储"活的"对象,可以将"活的"对象发送到远程计算机。

2、什么是序列化?

     序列化就是指将对象(实例)转化为字节流(字符数组)。反序列化就是将字节流转化为对象的逆过程。 于是,如果想把"活的"对象存储到文件,存储这串字节即可,如果想把"活的"对象发送到远程主机,发送这串字节即可,需要对象的时候,做一下反序列化,就能将对象"复活"了。

     将对象序列化存储到文件,术语又叫"持久化"。将对象序列化发送到远程计算机,术语又叫"数据通信"。

3、为什么不用Java的序列化?

     Java的序列化机制的缺点就是计算量开销大,且序列化的结果体积大太,有时能达到对象大小的数倍乃至十倍。它的引用机制也会导致大文件不能分割的问题。这些缺点使得Java的序列化机制对Hadoop来说是不合适的。于是Hadoop设计了自己的序列化机制。

4、为什么序列化对Hadoop很重要?

  因为Hadoop在集群之间进行通讯或者RPC调用的时候,需要序列化,而且要求序列化要快,且体积要小,占用带宽要小。所以必须理解Hadoop的序列化机制。

  序列化和反序列化在分布式数据处理领域经常出现:进程通信和永久存储。然而Hadoop中各个节点的通信是通过远程调用(RPC)实现的,那么 RPC序列化要求具有以下特点:
    紧凑:紧凑的格式能让我们能充分利用网络带宽,而带宽是数据中心最稀缺的资源
    快速:进程通信形成了分布式系统的骨架,所以需要尽量减少序列化和反序列化的性能开销,这是基本的
    可扩展:协议为了满足新的需求变化,所以控制客户端和服务器过程中,需要直接引进相应的协议,这些是新协议,原序列化方式能支持新的协议报文
    互操作:能支持不同语言写的客户端和服务端进行交互

5、Hadoop中定义哪些序列化相关的接口呢?

  Hadoop中定义了两个序列化相关的接口:Writable 接口和 Comparable 接口,这两个接口可以合并成一个接口 WritableComparable

  下面我们就了解一下这两个序列化接口:

  • Writable接口

 所有实现了Writable接口的类都可以被序列化和反序列化。 Writable 接口中定义了两个方法,分别为write(DataOutput out)和readFields(DataInput in)。write 用于将对象状态写入二进制格式的DataOutput流,readFields 用于从二进制格式的 DataInput 流中读取对象状态。

 1 package org.apache.hadoop.io; 
 2   3 import java.io.DataOutput; 
 4   5 import java.io.DataInput; 
 6   7 import java.io.IOException; 
 8   9 import org.apache.hadoop.classification.InterfaceAudience; 
10  11 import org.apache.hadoop.classification.InterfaceStability; 
12  13 public interface Writable { 
14     /** 15  16     * 将对象转换为字节流并写入到输出流out中 
17  18     */ 19  20     void write(DataOutput out) throws IOException; 
21      22     /** 23      24     * 从输入流in中读取字节流反序列化为对象 
25      26     */ 27  28     void readFields(DataInput in) throws IOException; 
29 }

对于一个特定的 Writable,我们可以对它进行哪些操作呢?

有两种常用操作:赋值和取值,这里我们以 IntWritable 为例来分别说明(IntWritable是对Java的int类型的封装)

1)通过 set() 函数设置 IntWritable 的值

  IntWritable value = new IntWritable();

  value.set(588)

  类似的,也可以使用构造函数来赋值。

  IntWritable value = new IntWritable(588);

2)通过get()函数获取 IntWritable 的值。

 int result = value.get();// 这里获取的值为588

  • Comparable接口

  所有实现了Comparable的对象都可以和自身相同类型的对象比较大小。该接口定义为:

 1 package java.lang; 
 2   3 import java.util.*; 
 4   5 public interface Comparable<T> { 
 6     /**  7     * 将this对象和对象o进行比较,约定:返回负数为小于,零为大于,整数为大于 
 8     */  9     public int compareTo(T o); 
10 }

6、Hadoop 自定义Writable 接口

  虽然 Hadoop 自带一系列Writable实现,如IntWritable,LongWritable等,可以满足一些简单的数据类型。但有时,复杂的数据类型需要自己自定义实现。通过自定义Writable,能够完全控制二进制表示和排序顺序。

  现有的 Hadoop Writable 应用已得到很好的优化,但为了对付更复杂的结构,最好创建一个新的 Writable 类型,而不是使用已有的类型。下面我们来学习一下如何自定义 Writable 类型,以自定义一个Writable 类型TextPair为例,如下所示

 1 import java.io.*; 
 2   3 import org.apache.hadoop.io.*; 
 4   5 /**   6 * @ProjectName Serialize 
 7 * @ClassName TextPair 
 8 * @Description 自定义Writable类型TextPair 
 9 * @Author 刘吉超 
10 * @Date 2016-04-16 23:59:19 
11 */ 12 public class TextPair implements WritableComparable<TextPair> { 
13     // Text 类型的实例变量 14     private Text first; 
15     // Text 类型的实例变量 16     private Text second; 
17      18     public TextPair() { 
19         set(new Text(), new Text()); 
20     } 
21  22     public TextPair(String first, String second) { 
23         set(new Text(first), new Text(second)); 
24     } 
25  26     public TextPair(Text first, Text second) { 
27         set(first, second); 
28     } 
29  30     public void set(Text first, Text second) { 
31         this.first = first; 
32         this.second = second; 
33     } 
34  35     public Text getFirst() { 
36         return first; 
37     } 
38  39     public Text getSecond() { 
40         return second; 
41     } 
42      43     @Override 
44     // 将对象转换为字节流并写入到输出流out中 45     public void write(DataOutput out) throws IOException { 
46         first.write(out); 
47         second.write(out); 
48     } 
49      50     @Override 
51     // 从输入流in中读取字节流反序列化为对象 52     public void readFields(DataInput in) throws IOException { 
53         first.readFields(in); 
54         second.readFields(in); 
55     } 
56  57     @Override 
58     public int hashCode() { 
59         return first.hashCode() * 163 + second.hashCode(); 
60     } 
61  62     @Override 
63     public boolean equals(Object o) { 
64         if (o instanceof TextPair) { 
65             TextPair tp = (TextPair) o; 
66             return first.equals(tp.first) && second.equals(tp.second); 
67         } 
68         return false; 
69     } 
70  71     @Override 
72     public String toString() { 
73         return first + "\t" + second; 
74     } 
75  76     // 排序 77     @Override 
78     public int compareTo(TextPair tp) { 
79         int cmp = first.compareTo(tp.first); 
80         if (cmp != 0) { 
81             return cmp; 
82         } 
83         return second.compareTo(tp.second); 
84     } 
85 }

  TextPair对象有两个Text实例变量(first和second)、相关的构造函数、get方法和set方法。 所有的Writable实现都必须有一个默认的构造函数,以便MapReduce框架能够对它们进行实例化,进而调用readFields()方法来填充它们的字段。Writable实例是易变的、经常重用的,所以应该尽量避免在 write() 或 readFields() 方法中分配对象。

  通过委托给每个 Text 对象本身,TextPair 的 write() 方法依次序列化输出流中的每一个 Text 对象。同样也通过委托给 Text 对象本身,readFields() 反序列化 输入流中的字节。DataOutput 和 DataInput 接口有丰富的整套方法用于序列化和反序列化 Java 基本类型,所以在一般情况下,能够完全控制 Writable 对象的数据传输格式。

  正如为Java写的任意值对象一样,会重写java.lang.Object的hashCode()、equals()和toString()方法。 HashPartitioner使用hashcode()方法来选择reduce分区,所以应该确保写一个好的哈希函数来确定reduce函数的分区在大小上是相当的。

  TextPair是WritableComparable的实现,所以它提供了compareTo()方法的实现,加入我们希望的排序:通过一个一个String逐个排序.

发布评论

分享到:

IT虾米网

微信公众号号:IT虾米 (左侧二维码扫一扫)欢迎添加!

hadoop自带的writable类型详解
你是第一个吃螃蟹的人
发表评论

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。