HADOOP序列化框架的使用以及AVRO介绍

作者: admin 分类: Hadoop 发布时间: 2018-03-06 14:26  阅读: 756 views

Hadoop有一个抽象的文件系统概念,HDFS只是其中的一个实现。
java抽象类org.apache.hadoop.fs.FileSystem定义了Hadoop中的一个文件系统借口。
hadoop是用Java写的,通过Java API可以调用所有Hadoop文件系统的交互操作。

大多数MapReduce程序使用的都是Writable类型的键和值,但这并不是MapReduce API强制使用的。事实可以用任何类型,只要能有一种机制对每个类型进行类型与二进制表示的来回转换。

为了支持这一机制,Hadoop有一个针对可替换序列化框架(serialization framework)的API.序列化框架用一个Serialization实现来表示。如WritableSerialization类是对writable类型的serialization实现。

Serialization对象定义了从类型到Serializer实例(将对象转换为字节流)和Deserializer实例(将字节流转换为对象)的定义方式。
Hadoop包含一个名为JavaSerialization的类,虽方便使用标准的java类型,如Integer或String,但不如Writable高效。Hadoop不用serialization,因为他看起来太复杂,不用RMI也处于类似的考虑。不满足先前列出的序列化格式标准:精简、快速、可扩展、支持互操作。

Java Serialization并不精简,实例化java.io.Serializable或者java.io.Externalizable的类需要将其类名和对象表示写入序列化后的数据流中。同一个类后续的实例只引用第一次出现的句柄,这占5个字节。

引用句柄不太适用于随机访问,因为被引用的类可能出现在先前数据流的任何位置。也就是说,需要在数据流中存储状态。更甚的是,句柄引用会对序列化数据流中的排序记录造成巨大的破坏,因为一个特定类的第一个记录是不同的,必须当做特殊情况区别对待。

不把类名写到数据流可以避免所有这些问题,Writable接口采取的正是这种做法,这需要假设客户端知道会收到什么类型。结果是,这个格式比java Serialization更精简,同时又支持随机存取和排序,因为流中的每一条记录均独立于其他记录(所以数据流是无状态的)。

Java Serialization是序列化图对象的通用机制,所以它有序列化和反序列化开销。更有甚者,它有一些从数据流中反序列化对象时,反序列化程序需要为每一个对象新建一个实例。另一方面,Writable对象可以重用。

Avro(http://avro.apache.org)是一个独立于编程语言的数据序列化系统。旨在解决Hadoop中writable类型的不足:缺乏语言的可移植性。拥有一个可被多种语言处理的数据格式与绑定到单一语言的数据格式相比,前者更易于与公众共享数据集.Avro同时也更具生命力。该语言将使得数据具有更长的生命周期,即原先用于读写该数据的语言已经不再使用。为什么要有一个新的数据序列化系统?与其他相比Avro有其独有的特性。Avro数据是用语言无关的模式定义的。但与其他系统不同,在Avro中,代码生成是可选的,这说明可以对遵循制定模式的数据进行读/写操作,即使在此之前代码从来没有见过这个特殊的数据模式。为此,Avro假设数据模式总是存在的,形成的是非常精简的编码,因为编码后的数值不需要用字段标识来打标签。

Avro模式通常用JSON来写,数据通常采用二进制格式来编码,但也有其他选择。
有一种高级语言成为 Avro IDL, 可以使用开发人员更熟悉的类C语言来写
还有基于JSON的数据编码方式(对构建原型和调试Avro数据很有用,因为可读)

Avro规范精确定义所实现都必须支持二进制格式。同时还指定这些实现还需要支持的其他Avro特性。
Avro有丰富的模式解析能力。
Avro为一系列对象制定了一个对象容器格式-类似于Hadoop的顺序文件。


Avro基本类型

类型 描述 模式示例
null 空值 “null”
boolean 二进制值 “boolean”
int 32位带符号整数 “int”
long 64位带符号整数 “long”
float 单精度-32位 “float”
double 双精度-64位 “double”
bytes 8位无符号字节序列 “bytes”
string Unicode字符序列 “string”

Avro复杂类型

类型 描述 模式示例
array 一个排过序的对象集合。特定数组中的所有对象必须模式相同 {“type”:”array”,”items”:”long”}
map 未排过序的键值对。键必须是字符串,值可以是任何类型,但一个特定map中所有值必须模式相同 {“type”:”map”,”values”:”string”}
record 一个任意类型的命名字段集合 {“type”:”record”,”name”:”WeatherRecord”,”doc”:”A weather reading.”,”fields”:[“”:””,””:'”]}
enum 一个命名的值集合 “long”
fixed 一组固定数量的8位无符号字节
union 模式的并集。并集可用JSON数组标识,其中每个元素为一个模式。

 

 


Avro为序列化和反序列化提供了API。
写一个JAVA程序,从数据流读/写Avro数据,先存储到类路径下名为StringPair.avsc文件。
{
“type”:”record”,
“name”:”StingPair”,
“doc”:”A pair of strings.”,
“fields”:[
{“name”:”left”,”type”:”string”},
{“name”:”right”,”type”:”string”},
]
}

Schema.Parser parser = new Schema.Parser();
Schema schema = parser.parse(getClass().getResourceAsStream("StringPair.avsc"));

GenericRecord datum = new GenericData.Record(schema);
datum.put("left",new Utf8("L"));
datum.put("right",new Utf8("R"));

ByteArrayOutputStream out = new ByteArrayOutputStream();
DatumWriter<GenericRecord> writer = new GenericDatuWriter<GenericRecord>(schema);
Encoder encoder = EncoderFactory.get().binaryEncoder(out,null);
writer.write(datum,encoder);
encoder.flush();
out.close();

 

这里有两个重要对象:DatumWriter和Encoder。DatumWriter对象将数据翻译成Encoder对象可以理解的类型,然后由后者写到输出流。

方向处理从字节缓冲区读回对象。

DatumWriter<GenericRecord> writer = new GenericDatuWriter<GenericRecord>(schema);
Decoder decoder = DecoderFactory.get().createBinaryDecoder(out.toByteArray(),null);
GenericRecord result = reader.read(null,decoder);
assertThat(resutl.get("left").toString(),is("L"));
assertThat(result.get("right").toString,is("R"));

 

Avro数据容器文件格式主要用于存储Avro对象序列。这与Hadoop顺序文件的设计非常相似。

Avro有互操作的特性【一个语言写入数据,另一种语言读取数据】


   原创文章,转载请标明本文链接: HADOOP序列化框架的使用以及AVRO介绍

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!

发表评论

电子邮件地址不会被公开。 必填项已用*标注

更多阅读