一、对于学过java的朋友来说,对于序列化应该不会陌生,序列化(serialization)指的是将结构化对象转换为字节流以便通过网络进行传输或写入持久化的过程。反序列化指的是将字节流转为一系列结构化对象的过程。
一般序列化在分布式数据处理中主要是应用在
(1)节点之间的进程间通信(Hadoop中是远程过程调用RPC)
(2)数据持久化。
hadoop在org.apache.hadoop.io中定义各种数据传输的类,大家可以点击此链接查看具体内容:
二、Writable接口
在org.apache.hadoop.io中,hadoop使用自己的序列化格式Writables接口,具有紧凑,快速的特点,不过目前只有用Java才能较容易扩展。在hadoop中,它一般用于MapReduce程序的序列化 键值对 。它是基于java.io 中的数据输入输出流DataInput和DataOutput的。
void readFields(DataInput in) //从in流反序列化出内容(在hadoop中,为了高效率,会尽可能优先找到储存中已存在的对象将它取出复用)。
void write(DataOutput out)//把内容序列化到out流
下面就给出hadoop官方文档中推荐的例子:
public class MyWritable implements Writable { //自己定义一个类实现Writable接口,定义两个私有成员变量
// Some data
private int counter;
private long timestamp;
//覆写write方法,该方法使用out参数对象把counter和timestamp写到out中(也就是序列化的过程)。
public void write(DataOutput out) throws IOException {
out.writeInt(counter);
out.writeLong(timestamp);
}
//覆写readFields方法,该方法用in参数对象把数据读取到counter和timestamp中(也就是反序列化的过程)。
public void readFields(DataInput in) throws IOException {
counter = in.readInt();
timestamp = in.readLong();
}
//设定一个静态方法,使用此方法可以返回一个Writable对象实例
public static MyWritable read(DataInput in) throws IOException {
MyWritable w = new MyWritable();
w.readFields(in);
return w;
}
}
让我们再来看一个常用的类IntWritable,它是java对int对象的一个封装,我们可以这样使用构造函数实例化对象。
IntWritable writable = new IntWritable(163);
我们使用内存操作流ByteArrayOutputStream和数据操作流DataOutputStream来查看这个writable中的序列化形式:
static byte [] serialize(Writable writable){
ByteArrayOutputStream out = new ByteArrayOutputStream();
DataOutputStream dataOut = new DataOutputStream(out);
writable.write(dataOut);
dataOut.close();
return out.toByteArray();
}
byte[] bytes = serialize(writable);
再用Junit4断言,得到它的序列化形式为00000a3
三、WritableComparable 和 comparator接口
(1) IntWritalbe 就是实现WritableComparable接口,而WritableComparable又是Writable和java.lang.Comparable接口的子接口。
public interface WritableComparable<T>
extends Writable, Comparable<T>
(2)类型的比较,对MapReduce而言至关重要,键和键之间的比较是在排序阶段完成的,hadoop提供的一个优化方法是从java Comparator的RawComparatro扩展。
它的主要方法为:
int compare(byte[] b1, int s1, int l1, byte[] b2, int s2, int l2) //该方法的作用就是比较字节数组b1和b2,b1比较的位置是从s1到l1,b2比较的位 置是从s2到l2.
可用WritableComparable的get工厂方法取得一个RawComparator实例,例如:
RawComparator<IntWritable> comparator = WritableComparator.get(IntWritable.class);
四、Writable类
除了上述的IntWritable类,hadoop将许多Writable类归入到org.apache.hadoop.io包中,如下所示:
java基本类型 Writable封装 序列化大小
布尔型 BooleanWritable 1
字节型 ByteWritable 1
整形 IntWritable 4
浮点型 FloatWritable 4
长整型 LongWritable 8
hadoop为了灵活性,还定义了一种可变长度格式VintWritable和VLongWritable。能更加节省空间。
(1)Text类
Text类是一种UTF-8格式的Writable。可以将它理解为一种与java.lang.String相类似的Writable。
Text使用int型在字符编码中存储字节数,最最大值是2GB。它有一个find()方法,相当于String的indexOf()。
常用方法有:
void append(byte[] utf8,int start,int len) //增加一段字节到末尾
int byteToCodePoint(ByteBuffer bytes) //在当前buffer位置返回下一个code的位置
void clear() //清空字符串
String decode(byte[] utf8) //使用utf8格式把字节数组转为String
ByteBuffer encode(String string) //把string转为字节
void set(byte[] utf8) //设置内容
上面的set方法我们可以用来重用Text实例:
Text t = new Text("hadoop");
t.set("pig");
(2)BytesWritable类
一个二进制数据数组封装,它的序列化格式是一个int字段。如同Text,ByteWritable是可变的,其值可以通过set()方法改变。
(3)NullWritable类
NullWritable是一个特殊的Writable类型,它的序列化长度是零长度的。没有字节被写入流或从从流中读出。它一般被用作占位符。
(4)ObjectWritable和GenericWritable
针对一些常用java类,ObjectWritable是一种多用途的封装,它使用hadoop的RPC来封送(marshal)和反封送(unmarshal)方法参数和返回类型。
(5)Writable集合
hadoop.io中共有ArrayWritable,TwoDArrayWritable,MapWritable和SortedMapWritable四种集合。
ArrayWritable和TwoDArrayWritable是Writable针对数组和二维数组而设计的,一般在构造时指定。如:
ArrayWritable writable = new ArrayWritable(Text.class);
MapWritable和SortedMapWritable分别是其实就是java.utli.Map(Writable,Writable)和java.util.SortedMap(WritableComparable,Writable)的hadoop实现。
每个键值对的字段类型都是此字段序列化格式的一部分。如下所示:
MapWritable src =https://www.linuxidc.com/Linux/2012-08/new MapWritable();
src.put(new IntWritable(1),new Text("cat"));
(6)序列化框架
虽然很多MapReduce程序都使用Writable键/值类型,但这并不是MapReduce的API,所有类型都能使用。
为了提供相应的支持,hadoop有一个简便的序列化框架API.在org.apache.hadoop.io.serializer包中。
包中的一个类WritableSerialization就是Writable类型的序列化实现。除了WritableSerialization,还有一个JavaSerialization的类,此类让我们能方便的使在MapReduce程序中使用用标准的java类型,不过不如Writable对象有效,不推荐使用。