Hadoop在与用户写的Mapper和Reducer通信的时候,总是使用类型化的数据:从文件读入到Mapper中,Mappers向Reducers提交和Reducers到输出文件,都是存储在Java对象中的。
Writable 类型
可以和文件和网络相互通信的对象必须遵循特定的接口,叫做Writable,它允许Hadoop以一种序列化的形式读写数据以适应于传输。Hadoop提供了几个已经实现了Writable:Text(用来存储字符串),IntWritable,LongWritable,FloadWritable,BooleanWritable,还有其它几个。完整的列表在Hadoop源码的org.apache.hadoop.io包中。
除了这些类型,你可以自由定义实现了Writable接口的其它类型。你可以组织成你需要的组织结构来表示的你的数据和适应Hadoop的传输。一个例子,考虑一个mapper,它提交键值对,其中的键是一个对象的名字,它的值是3维空间中的一个坐标。键就是某种基于字符串的数据,值就是一种结构的形式:
struct Point3D{
float x;
float y;
float z;}
键可以表示成一个Text对象,但是值呢?我们怎样定义一个Piont3D类,而这个类也能被Hadoop传输?答案就是实现Writable接口,它需要实现两个方法:
public interface Writable{
void readFields(DataInput in);
void write(DataOutput out);
}
第一个方法从二进制流in中初始化这个对象的所有的字段。后一个方法将需要的信息重新组成对象写到二进制流out中。其中的DataIput和DataOutput类包含序列化大多数基本类型数据的方法;在你的readFields()和write()之间重要的一条约定是,它们读、写数据到二进制流中的顺序是一直的。下面的代码实现了一个可以被Hadoop使用的Pint3D类:
public class Piont3D implements Writable{
public float x;
public float y;
public float z;
public Piont3D(float x, float y, float z){
this.x = x;
this.y = y;
this.z = z;
}
public Piont3D(){
this(0.0f, 0.0f, 0.0f);
}
public void write(DataOutput out) throws IOException{
out.writeFload(x);
out.writeFloat(y);
out.writeFload(z);
}
public void readFields(DataInput in) throws IOException(){
x = in.readFloat();
y = in.readFloat();
z = in.readFloat();
}
public String toString(){
return Float.toString(x) + "," + Float.toString(y) + "," + Float.toString(z);
}
}