序列化: 将内存中的对象转换成字节序列,方便磁盘存储。
反序列化: 将收到的字节序列,转换成内存中的对象。
Writable :对Java基本类型提供封装(short和char除外),使其可以实现序列化和反序列。所有的封装包包含get() 和 set() 方法用于读取或者设置封装的值。在Hadoop中定义一个结构化对象都要实现,使得该结构化对象可以序列化为字节流,字节流也可以反序列化为结构化对象。
WritableComparable:WriteCompareable接口是Wirtable接口的二次封装,提供了compareTo(T o)方法,用于序列化对象的比较的比较MapReduce中所有的key值类型都必须实现这个接口,下面是io包简单的类图关系。
字节流、字符流:
字符和字节详解、Java中字节串和字符串相互转换
Java IO 字节流、字符流详解
在Hadoop中,Writable接口定义了两个方法:
Write(): 用于将其状态写入二进制格式的DataOutput流。
read(): 用于从二进制格式的DataInput流读取其状态。
package org.apache.hadoop.io; import java.io.DataOutput; import java.io.DataInput; import java.io.IOException; public interface Writable { void write(DataOutput out) throws IOException; void readFields(DataInput in) throws IOException; }
将来自in(输入流)中对象的字段反序列化。就效率而言,这些实现(implements)应该尝试在可能存在的对象下重用存储。
基于DataInput和DataOutput,实现一个简单、有效、有序列化协议的序列化对象。
Hadoop Map-REDUCE框架中的任何key或value类型都必须实现这些接口。
典型的实现是实现静态的read(DataInput)方法,这个方法构造了一个新的实例;同时调用readFields(DataInput)方法并且返回一个实例。
Implementations typlically
public class MyWritable implements Writable { // Some data private int counter; private long timestamp; public void write(DataOutput out) throws IOException { out.writeInt(counter); out.writeLong(timestamp); } public void readFields(DataInput in) throws IOException { counter = in.readInt(); timestamp = in.readLong(); } public static MyWritable read(DataInput in) throws IOException { MyWritable w = new MyWritable(); w.readFields(in); return w; } }
DataOutput和DataInput
DataOutput接口用于将数据从任意 Java 基本类型转换为一系列字节,并将这些字节写入二进制流。同时还提供了一个将 String 转换成 UTF-8 修改版格式并写入所得到的系列字节的工具。
DataInput接口提供用于读取二进制流字节并重建为任何java原始数据类型,也提供了一个转换为UTF-8编码的字符串类型方法。
2. WritableComparable类WritableComparable继承了Writable接口和Comparable接口,由于WritableComparable中没有定义要实现的方法,所以继承这个接口,要实现的方法都是Writable接口和Comparable接口中的方法。
Writable接口
实现write和readFields方法,write是要对out对象进行序列化 *** 作,readFields是对in对象进行反序列化 *** 作。
public interface Writable { void write(DataOutput out) throws IOException; void readFields(DataInput in) throws IOException; }
Comparable接口
将调用该方法的对象和传入参数对象进行比较
public int compareTo(T o);
返回值有三种:
负整数,此时调用该方法的对象小于指定对象;
0,二者相等;
正整数,调用该方法的对象大于指定对象。
针对key自定义排序示例
public class MyWritableComparable implements WritableComparable{ // Some data private int counter; private long timestamp; public void write(DataOutput out) throws IOException { out.writeInt(counter); out.writeLong(timestamp); } public void readFields(DataInput in) throws IOException { counter = in.readInt(); timestamp = in.readLong(); } public int compareTo(MyWritableComparable o) { int thisValue = this.value; int thatValue = o.value; return (thisValue < thatValue ? -1 : (thisValue==thatValue ? 0 : 1)); } public int hashCode() { final int prime = 31; int result = 1; result = prime * result + counter; result = prime * result + (int) (timestamp ^ (timestamp >>> 32)); return result } }
注意,实现序列化和反序列化方法时,写入和读取属性的顺序一定要相同!!!实现完成之后,这个实现类就可以作为Map阶段输入或者输出数据的key类型,进行输出。在compareTo方法中实现自定义排序。
3. Java基本类型的Writable类
IntWritable 和 VIntWritable 这两个的区别是 IntWriable是固定的4个字节,而 VintWritable 是1~5个字节,是可以变化的。相比与定长格式,变长格式有什么优点:
(1)定长格式适合对整个值域空间中分布均匀的数值进行编码,大多数数值变量的分布都不均匀,而采用变长格式一般更节省空间。
(2)变长格式的 VIntWritable 和 VLlongWritable 可以转换,因为他们的编码实际上一致。选择变长格式,更有增长空间。
参考资料:
Hadoop中Writable类
Hadoop源码解析之Writable类
接口 DataOutput
(一)java.io.DataInput接口及源码详解
自定义排序WritableComparable
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)