AVRO – 快速指南
AVRO – 快速指南
AVRO – 概述
要通过网络传输数据或其持久存储,您需要序列化数据。在Java 和 Hadoop 提供的序列化 API之前,我们有一个特殊的实用程序,称为Avro,这是一种基于模式的序列化技术。
本教程教您如何使用 Avro 序列化和反序列化数据。Avro 为各种编程语言提供了库。在本教程中,我们将演示使用 Java 库的示例。
什么是阿夫罗?
Apache Avro 是一种语言中立的数据序列化系统。它是由 Hadoop 之父 Doug Cut 开发的。由于 Hadoop 可写类缺乏语言可移植性,Avro 变得非常有用,因为它处理可以由多种语言处理的数据格式。Avro 是在 Hadoop 中序列化数据的首选工具。
Avro 有一个基于模式的系统。独立于语言的模式与其读写操作相关联。Avro 序列化具有内置架构的数据。Avro 将数据序列化为紧凑的二进制格式,可以被任何应用程序反序列化。
Avro 使用 JSON 格式来声明数据结构。目前,它支持 Java、C、C++、C#、Python 和 Ruby 等语言。
Avro 架构
Avro 严重依赖其架构。它允许在没有模式的先验知识的情况下写入每个数据。它序列化速度快,结果序列化数据的大小更小。架构与 Avro 数据一起存储在文件中以供进一步处理。
在 RPC 中,客户端和服务器在连接期间交换模式。这种交换有助于同名字段、缺失字段、额外字段等之间的通信。
Avro 模式是用 JSON 定义的,使用 JSON 库简化了它在语言中的实现。
与 Avro 一样,Hadoop 中还有其他序列化机制,例如Sequence Files、Protocol Buffers和Thrift。
与 Thrift 和 Protocol Buffers 的比较
Thrift和Protocol Buffers是 Avro 最强大的库。Avro 在以下方面与这些框架不同 –
-
Avro 根据需要支持动态和静态类型。Protocol Buffers 和 Thrift 使用接口定义语言 (IDL) 来指定模式及其类型。这些 IDL 用于生成用于序列化和反序列化的代码。
-
Avro 构建在 Hadoop 生态系统中。Thrift 和 Protocol Buffers 不是在 Hadoop 生态系统中构建的。
与 Thrift 和 Protocol Buffer 不同,Avro 的模式定义是在 JSON 中而不是在任何专有的 IDL 中。
Property | 阿夫罗 | 节俭和协议缓冲区 |
---|---|---|
Dynamic schema | 是的 | 不 |
Built into Hadoop | 是的 | 不 |
Schema in JSON | 是的 | 不 |
No need to compile | 是的 | 不 |
No need to declare IDs | 是的 | 不 |
Bleeding edge | 是的 | 不 |
Avro 的特点
下面列出了 Avro 的一些突出特点 –
-
Avro 是一种语言中立的数据序列化系统。
-
它可以被多种语言处理(目前是 C、C++、C#、Java、Python 和 Ruby)。
-
Avro公司创建二进制结构化的格式,既压缩和裂开的。因此,它可以有效地用作 Hadoop MapReduce 作业的输入。
-
Avro 提供了丰富的数据结构。例如,您可以创建一个包含数组、枚举类型和子记录的记录。这些数据类型可以用任何语言创建,可以在 Hadoop 中处理,结果可以提供给第三种语言。
-
在JSON 中定义的Avro模式有助于在已有 JSON 库的语言中实现。
-
Avro 创建了一个名为Avro Data File的自描述文件,它在元数据部分中存储数据及其架构。
-
Avro 也用于远程过程调用 (RPC)。在 RPC 期间,客户端和服务器在连接握手中交换模式。
Avro 的一般工作
要使用 Avro,您需要遵循给定的工作流程 –
-
步骤 1 – 创建模式。在这里,您需要根据您的数据设计 Avro 模式。
-
第 2 步– 将模式读入您的程序。它通过两种方式完成 –
-
通过生成与架构对应的类– 使用 Avro 编译架构。这会生成一个对应于模式的类文件
-
通过使用解析器库– 您可以使用解析器库直接读取模式。
-
-
第 3 步– 使用为 Avro 提供的序列化 API 序列化数据,该 API 位于org.apache.avro.specific 包中。
-
第 4 步– 使用为 Avro 提供的反序列化 API 反序列化数据,该 API 位于org.apache.avro.specific 包中。
AVRO – 序列化
数据序列化有两个目标 –
-
用于持久存储
-
通过网络传输数据
什么是序列化?
序列化是将数据结构或对象状态转换为二进制或文本形式以通过网络传输数据或存储在某些持久存储上的过程。一旦数据通过网络传输或从持久存储中检索,它需要再次反序列化。序列化称为编组,反序列化称为解组。
Java中的序列化
Java 提供了一种称为对象序列化的机制,其中对象可以表示为字节序列,其中包括对象的数据以及有关对象类型和存储在对象中的数据类型的信息。
序列化对象写入文件后,可以从文件中读取并反序列化。也就是说,表示对象及其数据的类型信息和字节可用于在内存中重新创建对象。
ObjectInputStream和ObjectOutputStream类分别用于在 Java 中序列化和反序列化对象。
Hadoop 中的序列化
通常在像 Hadoop 这样的分布式系统中,序列化的概念用于进程间通信和持久存储。
进程间通信
-
为了在网络中连接的节点之间建立进程间通信,使用了 RPC 技术。
-
RPC 使用内部序列化将消息转换为二进制格式,然后通过网络将其发送到远程节点。在另一端,远程系统将二进制流反序列化为原始消息。
-
RPC 序列化格式要求如下 –
-
紧凑– 充分利用网络带宽,这是数据中心中最稀缺的资源。
-
快速– 由于节点之间的通信在分布式系统中至关重要,因此序列化和反序列化过程应该很快,产生更少的开销。
-
可扩展– 协议随着时间的推移而变化以满足新的需求,因此以受控的方式为客户端和服务器发展协议应该很简单。
-
可互操作– 消息格式应支持用不同语言编写的节点。
-
持久化存储
持久存储是一种数字存储设施,不会因断电而丢失数据。文件、文件夹、数据库是持久存储的例子。
可写接口
这是 Hadoop 中的接口,它提供了序列化和反序列化的方法。下表描述了这些方法 –
S.No. | 方法和说明 |
---|---|
1 |
void readFields(DataInput in) 此方法用于反序列化给定对象的字段。 |
2 |
void write(DataOutput out) 此方法用于序列化给定对象的字段。 |
可写的可比接口
它是Writable和Comparable接口的组合。该接口继承了Hadoop的Writable接口和Java的Comparable接口。因此它提供了数据序列化、反序列化和比较的方法。
S.No. | 方法和说明 |
---|---|
1 |
int compareTo(class obj) 此方法将当前对象与给定对象 obj 进行比较。 |
除了这些类之外,Hadoop 还支持许多实现 WritableComparable 接口的包装类。每个类都包装一个 Java 原始类型。Hadoop 序列化的类层次结构如下 –
这些类对于在 Hadoop 中序列化各种类型的数据很有用。例如,让我们考虑IntWritable类。让我们看看这个类是如何用于在 Hadoop 中序列化和反序列化数据的。
可写类
此类实现Writable、Comparable和WritableComparable接口。它在其中包装了一个整数数据类型。此类提供用于序列化和反序列化整数类型数据的方法。
构造函数
S.No. | 概括 |
---|---|
1 | 可写() |
2 | IntWritable(int值) |
方法
S.No. | 概括 |
---|---|
1 |
int get() 使用此方法,您可以获得当前对象中存在的整数值。 |
2 |
void readFields(DataInput in) 此方法用于反序列化给定DataInput对象中的数据。 |
3 |
void set(int value) 该方法用于设置当前IntWritable对象的值。 |
4 |
void write(DataOutput out) 此方法用于将当前对象中的数据序列化为给定的DataOutput对象。 |
在 Hadoop 中序列化数据
下面讨论序列化整数类型数据的过程。
-
通过在其中包装一个整数值来实例化IntWritable类。
-
实例化ByteArrayOutputStream类。
-
实例化DataOutputStream类并将ByteArrayOutputStream类的对象传递给它。
-
使用write()方法序列化 IntWritable 对象中的整数值。该方法需要一个 DataOutputStream 类的对象。
-
序列化的数据将存储在字节数组对象中,该对象在实例化时作为参数传递给DataOutputStream类。将对象中的数据转换为字节数组。
例子
以下示例显示了如何在 Hadoop 中序列化整数类型的数据 –
import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.IOException; import org.apache.hadoop.io.IntWritable; public class Serialization { public byte[] serialize() throws IOException{ //Instantiating the IntWritable object IntWritable intwritable = new IntWritable(12); //Instantiating ByteArrayOutputStream object ByteArrayOutputStream byteoutputStream = new ByteArrayOutputStream(); //Instantiating DataOutputStream object DataOutputStream dataOutputStream = new DataOutputStream(byteoutputStream); //Serializing the data intwritable.write(dataOutputStream); //storing the serialized object in bytearray byte[] byteArray = byteoutputStream.toByteArray(); //Closing the OutputStream dataOutputStream.close(); return(byteArray); } public static void main(String args[]) throws IOException{ Serialization serialization= new Serialization(); serialization.serialize(); System.out.println(); } }
在 Hadoop 中反序列化数据
下面讨论了反序列化整数类型数据的过程 –
-
通过在其中包装一个整数值来实例化IntWritable类。
-
实例化ByteArrayOutputStream类。
-
实例化DataOutputStream类并将ByteArrayOutputStream类的对象传递给它。
-
使用IntWritable 类的readFields()方法反序列化DataInputStream对象中的数据。
-
反序列化的数据将存储在 IntWritable 类的对象中。您可以使用此类的get()方法检索此数据。
例子
以下示例显示了如何在 Hadoop 中反序列化整数类型的数据 –
import java.io.ByteArrayInputStream; import java.io.DataInputStream; import org.apache.hadoop.io.IntWritable; public class Deserialization { public void deserialize(byte[]byteArray) throws Exception{ //Instantiating the IntWritable class IntWritable intwritable =new IntWritable(); //Instantiating ByteArrayInputStream object ByteArrayInputStream InputStream = new ByteArrayInputStream(byteArray); //Instantiating DataInputStream object DataInputStream datainputstream=new DataInputStream(InputStream); //deserializing the data in DataInputStream intwritable.readFields(datainputstream); //printing the serialized data System.out.println((intwritable).get()); } public static void main(String args[]) throws Exception { Deserialization dese = new Deserialization(); dese.deserialize(new Serialization().serialize()); } }
Hadoop 相对于 Java 序列化的优势
Hadoop 的基于 Writable 的序列化能够通过重用 Writable 对象来减少对象创建开销,这是 Java 的本机序列化框架无法实现的。
Hadoop序列化的缺点
要序列化 Hadoop 数据,有两种方法 –
-
您可以使用Hadoop 的本机库提供的Writable类。
-
您还可以使用以二进制格式存储数据的序列文件。
这两种机制的主要缺点是Writables和SequenceFiles只有一个 Java API,不能用任何其他语言编写或读取它们。
因此,在Hadoop中使用上述两种机制创建的任何文件都无法被任何其他第三方语言读取,这使得Hadoop成为一个有限的盒子。为了解决这个缺点,Doug Cutting 创建了Avro,这是一种独立于语言的数据结构。
AVRO – 环境设置
Apache 软件基金会为 Avro 提供了各种版本。您可以从 Apache 镜像下载所需的版本。让我们看看,如何设置环境与 Avro 一起工作 –
下载 Avro
要下载 Apache Avro,请继续执行以下操作 –
-
打开网页Apache.org。您将看到 Apache Avro 的主页,如下所示 –
-
点击项目→发布。您将获得发布列表。
-
选择最新版本,它会引导您进入下载链接。
-
mirror.nexcess是链接之一,您可以在其中找到 Avro 支持的所有不同语言库的列表,如下所示 –
您可以选择并下载所提供的任何语言的库。在本教程中,我们使用 Java。因此下载 jar 文件avro-1.7.7.jar和avro-tools-1.7.7.jar。
带 Eclipse 的 Avro
要在 Eclipse 环境中使用 Avro,您需要按照以下步骤操作 –
-
步骤 1.打开 eclipse。
-
步骤 2.创建一个项目。
-
步骤 3.右键单击项目名称。您将获得一个快捷菜单。
-
步骤 4.单击构建路径。它会引导您进入另一个快捷菜单。
-
步骤 5.单击配置构建路径…您可以看到项目的属性窗口,如下所示 –
-
步骤 6.在库选项卡下,单击添加外部 JAR…按钮。
-
步骤 7.选择您下载的 jar 文件avro-1.77.jar。
-
步骤 8.单击确定。
Avro 与 Maven
您还可以使用 Maven 将 Avro 库添加到您的项目中。下面给出的是 Avro 的 pom.xml 文件。
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi=" http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>Test</groupId> <artifactId>Test</artifactId> <version>0.0.1-SNAPSHOT</version> <build> <sourceDirectory>src</sourceDirectory> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> <configuration> <source>1.7</source> <target>1.7</target> </configuration> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>org.apache.avro</groupId> <artifactId>avro</artifactId> <version>1.7.7</version> </dependency> <dependency> <groupId>org.apache.avro</groupId> <artifactId>avro-tools</artifactId> <version>1.7.7</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>2.0-beta9</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.0-beta9</version> </dependency> </dependencies> </project>
设置类路径
要在 Linux 环境中使用 Avro,请下载以下 jar 文件 –
- avro-1.77.jar
- avro-tools-1.77.jar
- log4j-api-2.0-beta9.jar
- og4j-core-2.0.beta9.jar。
将这些文件复制到一个文件夹中,并将类路径设置为该文件夹,在 . /bashrc文件,如下所示。
#class path for Avro export CLASSPATH=$CLASSPATH://home/Hadoop/Avro_Work/jars/*
AVRO – 模式
Avro 是一个基于模式的序列化实用程序,接受模式作为输入。尽管有各种模式可用,但 Avro 遵循自己的模式定义标准。这些模式描述了以下细节 –
- 文件类型(默认记录)
- 记录位置
- 记录名称
- 记录中的字段及其对应的数据类型
使用这些模式,您可以使用更少的空间以二进制格式存储序列化值。这些值在没有任何元数据的情况下存储。
创建 Avro 架构
Avro 架构以 JavaScript 对象表示法 (JSON) 文档格式创建,这是一种基于文本的轻量级数据交换格式。它是通过以下方式之一创建的 –
- 一个 JSON 字符串
- 一个 JSON 对象
- 一个 JSON 数组
示例– 以下示例显示了一个模式,它在名称空间 Tutorialspoint 下定义了一个文档,名称为 Employee,具有字段名称和年龄。
{ "type" : "record", "namespace" : "Tutorialspoint", "name" : "Employee", "fields" : [ { "name" : "Name" , "type" : "string" }, { "name" : "Age" , "type" : "int" } ] }
在此示例中,您可以观察到每条记录有四个字段 –
-
type – 此字段位于文档下以及名为字段的字段下。
-
在文档的情况下,它显示文档的类型,通常是一条记录,因为有多个字段。
-
当它是字段时,类型描述数据类型。
-
-
namespace – 该字段描述了对象所在的命名空间的名称。
-
name – 此字段位于文档下以及名为字段的字段下。
-
在文档的情况下,它描述模式名称。此架构名称与命名空间一起,唯一标识存储中的架构 ( Namespace.schema name )。在上面的示例中,模式的全名将是 Tutorialspoint.Employee。
-
在字段的情况下,它描述字段的名称。
-
Avro 的原始数据类型
Avro 模式具有原始数据类型和复杂数据类型。下表描述了Avro的原始数据类型–
Data type | 描述 |
---|---|
null | Null 是一种没有值的类型。 |
int | 32 位有符号整数。 |
long | 64 位有符号整数。 |
float | 单精度(32 位)IEEE 754 浮点数。 |
double | 双精度(64 位)IEEE 754 浮点数。 |
bytes | 8 位无符号字节序列。 |
string | Unicode 字符序列。 |
Avro 的复杂数据类型
除了原始数据类型,Avro 还提供了六种复杂的数据类型,即记录、枚举、数组、映射、联合和固定。
记录
Avro 中的记录数据类型是多个属性的集合。它支持以下属性 –
-
name – 此字段的值包含记录的名称。
-
namespace – 此字段的值包含存储对象的命名空间的名称。
-
type – 此属性的值包含文档(记录)的类型或模式中字段的数据类型。
-
fields – 该字段包含一个 JSON 数组,其中包含架构中所有字段的列表,每个字段都有名称和类型属性。
例子
下面给出了一个记录的例子。
{ " type " : "record", " namespace " : "Tutorialspoint", " name " : "Employee", " fields " : [ { "name" : " Name" , "type" : "string" }, { "name" : "age" , "type" : "int" } ] }
枚举
枚举是集合中的项目列表,Avro 枚举支持以下属性 –
-
name – 此字段的值包含枚举的名称。
-
namespace – 此字段的值包含限定枚举名称的字符串。
-
符号– 此字段的值将枚举的符号保存为名称数组。
例子
下面给出了一个枚举的例子。
{ "type" : "enum", "name" : "Numbers", "namespace": "data", "symbols" : [ "ONE", "TWO", "THREE", "FOUR" ] }
数组
这种数据类型定义了一个具有单个属性项的数组字段。此项目属性指定数组中项目的类型。
例子
{ " type " : " array ", " items " : " int " }
地图
map 数据类型是一个键值对数组,它将数据组织为键值对。Avro 映射的键必须是字符串。地图的值保存地图内容的数据类型。
例子
{"type" : "map", "values" : "int"}
工会
只要字段具有一种或多种数据类型,就使用联合数据类型。它们表示为 JSON 数组。例如,如果字段可以是 int 或 null,则联合表示为 [“int”, “null”]。
例子
下面给出的是使用联合的示例文档 –
{ "type" : "record", "namespace" : "tutorialspoint", "name" : "empdetails ", "fields" : [ { "name" : "experience", "type": ["int", "null"] }, { "name" : "age", "type": "int" } ] }
固定的
此数据类型用于声明可用于存储二进制数据的固定大小字段。它具有字段名称和数据作为属性。Name 保存字段的名称, size 保存字段的大小。
例子
{ "type" : "fixed" , "name" : "bdata", "size" : 1048576}
AVRO – 参考 API
在上一章中,我们描述了 Avro 的输入类型,即 Avro schemas。在本章中,我们将解释 Avro 模式的序列化和反序列化中使用的类和方法。
特定数据写入器类
此类属于包org.apache.avro.specific。它实现了DatumWriter接口,该接口将 Java 对象转换为内存中的序列化格式。
构造函数
S.No. | 描述 |
---|---|
1 | 特定数据写入器(架构模式) |
方法
S.No. | 描述 |
---|---|
1 |
SpecificData getSpecificData() 返回此编写器使用的特定数据实现。 |
特定数据读取器类
此类属于包org.apache.avro.specific。它实现了DatumReader接口,该接口读取模式的数据并确定内存中的数据表示。SpecificDatumReader是支持生成的 java 类的类。
构造函数
S.No. | 描述 |
---|---|
1 |
SpecificDatumReader(Schema schema) 构造作者和读者的模式相同的地方。 |
方法
S.No. | 描述 |
---|---|
1 |
SpecificData getSpecificData() 返回包含的特定数据。 |
2 |
void setSchema(Schema actual) 此方法用于设置作者的模式。 |
数据文件写入器
为emp类实例化DataFileWrite。此类将符合模式的数据序列化记录与文件中的模式一起写入序列。
构造函数
S.No. | 描述 |
---|---|
1 | DataFileWriter(DatumWriter<D> dout) |
方法
S.No | 描述 |
---|---|
1 |
void append(D datum) 将数据附加到文件。 |
2 |
DataFileWriter<D> appendTo(File file) 此方法用于打开附加到现有文件的编写器。 |
数据文件阅读器
此类提供对使用DataFileWriter编写的文件的随机访问。它继承了类DataFileStream。
构造函数
S.No. | 描述 |
---|---|
1 | DataFileReader(文件文件, DatumReader<D> reader)) |
方法
S.No. | 描述 |
---|---|
1 |
next() 读取文件中的下一个数据。 |
2 |
Boolean hasNext() 如果此文件中还有更多条目,则返回 true。 |
类 Schema.parser
此类是 JSON 格式模式的解析器。它包含解析模式的方法。它属于org.apache.avro包。
构造函数
S.No. | 描述 |
---|---|
1 | Schema.Parser() |
方法
S.No. | 描述 |
---|---|
1 |
parse (File file) 解析给定文件中提供的模式。 |
2 |
parse (InputStream in) 解析给定InputStream 中提供的模式。 |
3 |
parse (String s) 解析给定String 中提供的架构。 |
接口通用记录
此接口提供按名称和索引访问字段的方法。
方法
S.No. | 描述 |
---|---|
1 |
Object get(String key) 返回给定字段的值。 |
2 |
void put(String key, Object v) 根据名称设置字段的值。 |
类 GenericData.Record
构造函数
S.No. | 描述 |
---|---|
1 | GenericData.Record(架构模式) |
方法
S.No. | 描述 |
---|---|
1 |
Object get(String key) 返回给定名称的字段的值。 |
2 |
Schema getSchema() 返回此实例的架构。 |
3 |
void put(int i, Object v) 给定字段在模式中的位置,设置字段的值。 |
4 |
void put(String key, Object value) 根据名称设置字段的值。 |
AVRO – 通过生成类进行序列化
可以通过生成与模式对应的类或使用解析器库将 Avro 模式读入程序。本章介绍如何通过生成类和使用 Avr序列化数据来读取模式。
通过生成类进行序列化
要使用 Avro 序列化数据,请按照以下步骤操作 –
-
编写一个 Avro 模式。
-
使用 Avro 实用程序编译架构。您将获得与该模式对应的 Java 代码。
-
用数据填充架构。
-
使用 Avro 库对其进行序列化。
定义架构
假设您想要一个具有以下详细信息的架构 –
Field | 名称 | ID | 年龄 | 薪水 | 地址 |
type | 细绳 | 整数 | 整数 | 整数 | 细绳 |
创建一个 Avro 架构,如下所示。
将其另存为emp.avsc。
{ "namespace": "tutorialspoint.com", "type": "record", "name": "emp", "fields": [ {"name": "name", "type": "string"}, {"name": "id", "type": "int"}, {"name": "salary", "type": "int"}, {"name": "age", "type": "int"}, {"name": "address", "type": "string"} ] }
编译架构
创建 Avro 模式后,您需要使用 Avro 工具编译创建的模式。
avro-tools-1.7.7.jar是包含工具的 jar。
编译 Avro 架构的语法
java -jar <path/to/avro-tools-1.7.7.jar> compile schema <path/to/schema-file> <destination-folder>
在主文件夹中打开终端。
创建一个新目录以使用 Avro,如下所示 –
$ mkdir Avro_Work
在新创建的目录中,创建三个子目录 –
-
首先命名架构,以放置架构。
-
第二个命名为with_code_gen,用来放置生成的代码。
-
第三个命名为jars,用来放置jar文件。
$ mkdir schema $ mkdir with_code_gen $ mkdir jars
以下屏幕截图显示了创建所有目录后Avro_work文件夹的外观。
-
现在/home/Hadoop/Avro_work/jars/avro-tools-1.7.7.jar是您下载 avro-tools-1.7.7.jar 文件的目录的路径。
-
/home/Hadoop/Avro_work/schema/是存储架构文件 emp.avsc 的目录的路径。
-
/home/Hadoop/Avro_work/with_code_gen是您希望存储生成的类文件的目录。
现在编译模式如下所示 –
$ java -jar /home/Hadoop/Avro_work/jars/avro-tools-1.7.7.jar compile schema /home/Hadoop/Avro_work/schema/emp.avsc /home/Hadoop/Avro/with_code_gen
编译完成后,会在目标目录中根据schema的命名空间创建一个包。在这个包中,创建了带有模式名称的 Java 源代码。这个生成的源代码是给定模式的 Java 代码,可以直接在应用程序中使用。
例如,在本例中,创建了一个名为tutorialspoint的包/文件夹,其中包含另一个名为 com 的文件夹(因为名称空间是 tutorialspoint.com),您可以在其中观察生成的文件emp.java。以下快照显示emp.java –
这个类对于根据模式创建数据很有用。
生成的类包含 –
- 默认构造函数和参数化构造函数,它们接受模式的所有变量。
- 模式中所有变量的 setter 和 getter 方法。
- Get() 方法返回模式。
- 构建器方法。
创建和序列化数据
首先,将生成的本项目使用的java文件拷贝到当前目录下或者从所在位置导入。
现在我们可以编写一个新的 Java 文件并实例化生成的文件 ( emp ) 中的类,以将员工数据添加到模式中。
让我们看看使用 apache Avro 根据模式创建数据的过程。
步骤1
实例化生成的emp类。
emp e1=new emp( );
第2步
使用 setter 方法,插入第一个员工的数据。例如,我们创建了名为 Omar 的员工的详细信息。
e1.setName("omar"); e1.setAge(21); e1.setSalary(30000); e1.setAddress("Hyderabad"); e1.setId(001);
同样,使用 setter 方法填写所有员工详细信息。
第 3 步
使用SpecificDatumWriter类创建DatumWriter接口的对象。这会将 Java 对象转换为内存中的序列化格式。以下示例为emp类实例化SpecificDatumWriter类对象。
DatumWriter<emp> empDatumWriter = new SpecificDatumWriter<emp>(emp.class);
第四步
为emp类实例化DataFileWriter。此类将符合模式的数据的序列序列化记录以及模式本身写入文件中。此类需要DatumWriter对象作为构造函数的参数。
DataFileWriter<emp> empFileWriter = new DataFileWriter<emp>(empDatumWriter);
第 5 步
使用create()方法打开一个新文件以存储与给定模式匹配的数据。此方法需要架构和要存储数据的文件的路径作为参数。
在以下示例中,使用getSchema()方法传递架构,数据文件存储在路径 – /home/Hadoop/Avro/serialized_file/emp.avro 中。
empFileWriter.create(e1.getSchema(),new File("/home/Hadoop/Avro/serialized_file/emp.avro"));
第 6 步
使用append()方法将所有创建的记录添加到文件中,如下所示 –
empFileWriter.append(e1); empFileWriter.append(e2); empFileWriter.append(e3);
示例 – 通过生成类进行序列化
以下完整程序显示了如何使用 Apache Avro 将数据序列化为文件 –
import java.io.File; import java.io.IOException; import org.apache.avro.file.DataFileWriter; import org.apache.avro.io.DatumWriter; import org.apache.avro.specific.SpecificDatumWriter; public class Serialize { public static void main(String args[]) throws IOException{ //Instantiating generated emp class emp e1=new emp(); //Creating values according the schema e1.setName("omar"); e1.setAge(21); e1.setSalary(30000); e1.setAddress("Hyderabad"); e1.setId(001); emp e2=new emp(); e2.setName("ram"); e2.setAge(30); e2.setSalary(40000); e2.setAddress("Hyderabad"); e2.setId(002); emp e3=new emp(); e3.setName("robbin"); e3.setAge(25); e3.setSalary(35000); e3.setAddress("Hyderabad"); e3.setId(003); //Instantiate DatumWriter class DatumWriter<emp> empDatumWriter = new SpecificDatumWriter<emp>(emp.class); DataFileWriter<emp> empFileWriter = new DataFileWriter<emp>(empDatumWriter); empFileWriter.create(e1.getSchema(), new File("/home/Hadoop/Avro_Work/with_code_gen/emp.avro")); empFileWriter.append(e1); empFileWriter.append(e2); empFileWriter.append(e3); empFileWriter.close(); System.out.println("data successfully serialized"); } }
浏览放置生成代码的目录。在这种情况下,在home/Hadoop/Avro_work/with_code_gen。
在终端 –
$ cd home/Hadoop/Avro_work/with_code_gen/
在 GUI 中 –
现在将上述程序复制并保存在名为Serialize.java的文件中
编译并执行它,如下所示 –
$ javac Serialize.java $ java Serialize
输出
data successfully serialized
如果验证程序中给出的路径,可以找到生成的序列化文件,如下所示。
AVRO – 通过生成类反序列化
如前所述,可以通过生成与模式对应的类或使用解析器库将 Avro 模式读入程序。本章介绍如何通过生成类来读取模式并使用 Avro反序列化数据。
通过生成类进行反序列化
序列化的数据存储在文件emp.avro 中。您可以使用 Avro 反序列化和读取它。
按照下面给出的过程反序列化文件中的序列化数据。
步骤1
使用SpecificDatumReader类创建DatumReader接口的对象。
DatumReader<emp>empDatumReader = new SpecificDatumReader<emp>(emp.class);
第2步
为emp类实例化DataFileReader。此类从文件中读取序列化数据。它需要Dataumeader对象和序列化数据所在文件的路径,作为构造函数的参数。
DataFileReader<emp> dataFileReader = new DataFileReader(new File("/path/to/emp.avro"), empDatumReader);
第 3 步
使用DataFileReader的方法打印反序列化的数据。
-
的hasNext()如果在读取器的任何元件方法将返回一个布尔值。
-
DataFileReader的next()方法返回 Reader 中的数据。
while(dataFileReader.hasNext()){ em=dataFileReader.next(em); System.out.println(em); }
示例 – 通过生成类进行反序列化
以下完整程序展示了如何使用 Avro 反序列化文件中的数据。
import java.io.File; import java.io.IOException; import org.apache.avro.file.DataFileReader; import org.apache.avro.io.DatumReader; import org.apache.avro.specific.SpecificDatumReader; public class Deserialize { public static void main(String args[]) throws IOException{ //DeSerializing the objects DatumReader<emp> empDatumReader = new SpecificDatumReader<emp>(emp.class); //Instantiating DataFileReader DataFileReader<emp> dataFileReader = new DataFileReader<emp>(new File("/home/Hadoop/Avro_Work/with_code_genfile/emp.avro"), empDatumReader); emp em=null; while(dataFileReader.hasNext()){ em=dataFileReader.next(em); System.out.println(em); } } }
浏览到放置生成的代码的目录。在这种情况下,在home/Hadoop/Avro_work/with_code_gen。
$ cd home/Hadoop/Avro_work/with_code_gen/
现在,将上述程序复制并保存在名为DeSerialize.java的文件中。编译并执行它,如下所示 –
$ javac Deserialize.java $ java Deserialize
输出
{"name": "omar", "id": 1, "salary": 30000, "age": 21, "address": "Hyderabad"} {"name": "ram", "id": 2, "salary": 40000, "age": 30, "address": "Hyderabad"} {"name": "robbin", "id": 3, "salary": 35000, "age": 25, "address": "Hyderabad"}
AVRO – 使用解析器序列化
通过生成与模式对应的类或使用解析器库,可以将 Avro 模式读入程序。在 Avro 中,数据始终与其对应的架构一起存储。因此,我们始终可以在不生成代码的情况下读取模式。
本章介绍如何使用解析器库读取模式并使用 Avro序列化数据。
使用解析器库进行序列化
要序列化数据,我们需要读取模式,根据模式创建数据,并使用 Avro API 序列化模式。以下过程序列化数据而不生成任何代码 –
步骤1
首先,从文件中读取模式。为此,请使用Schema.Parser类。此类提供了以不同格式解析模式的方法。
通过传递存储架构的文件路径来实例化Schema.Parser类。
Schema schema = new Schema.Parser().parse(new File("/path/to/emp.avsc"));
第2步
创建GenericRecord接口的对象,通过实例化GenericData.Record类,如下所示。将上面创建的架构对象传递给它的构造函数。
GenericRecord e1 = new GenericData.Record(schema);
第 3 步
使用GenericData类的put()方法在模式中插入值。
e1.put("name", "ramu"); e1.put("id", 001); e1.put("salary",30000); e1.put("age", 25); e1.put("address", "chennai");
第四步
使用SpecificDatumWriter类创建DatumWriter接口的对象。它将 Java 对象转换为内存中的序列化格式。以下示例为emp类实例化SpecificDatumWriter类对象–
DatumWriter<emp> empDatumWriter = new SpecificDatumWriter<emp>(emp.class);
第 5 步
为emp类实例化DataFileWriter。此类将符合模式的数据的序列化记录以及模式本身写入文件中。此类需要DatumWriter对象作为构造函数的参数。
DataFileWriter<emp> dataFileWriter = new DataFileWriter<emp>(empDatumWriter);
第 6 步
使用create()方法打开一个新文件以存储与给定模式匹配的数据。此方法需要架构和要存储数据的文件的路径作为参数。
在下面给出的示例中,使用getSchema()方法传递架构,并将数据文件存储在路径中
/home/Hadoop/Avro/serialized_file/emp.avro。
empFileWriter.create(e1.getSchema(), new File("/home/Hadoop/Avro/serialized_file/emp.avro"));
第 7 步
使用append( )方法将所有创建的记录添加到文件中,如下所示。
empFileWriter.append(e1); empFileWriter.append(e2); empFileWriter.append(e3);
示例 – 使用解析器进行序列化
以下完整程序显示了如何使用解析器序列化数据 –
import java.io.File; import java.io.IOException; import org.apache.avro.Schema; import org.apache.avro.file.DataFileWriter; import org.apache.avro.generic.GenericData; import org.apache.avro.generic.GenericDatumWriter; import org.apache.avro.generic.GenericRecord; import org.apache.avro.io.DatumWriter; public class Seriali { public static void main(String args[]) throws IOException{ //Instantiating the Schema.Parser class. Schema schema = new Schema.Parser().parse(new File("/home/Hadoop/Avro/schema/emp.avsc")); //Instantiating the GenericRecord class. GenericRecord e1 = new GenericData.Record(schema); //Insert data according to schema e1.put("name", "ramu"); e1.put("id", 001); e1.put("salary",30000); e1.put("age", 25); e1.put("address", "chenni"); GenericRecord e2 = new GenericData.Record(schema); e2.put("name", "rahman"); e2.put("id", 002); e2.put("salary", 35000); e2.put("age", 30); e2.put("address", "Delhi"); DatumWriter<GenericRecord> datumWriter = new GenericDatumWriter<GenericRecord>(schema); DataFileWriter<GenericRecord> dataFileWriter = new DataFileWriter<GenericRecord>(datumWriter); dataFileWriter.create(schema, new File("/home/Hadoop/Avro_work/without_code_gen/mydata.txt")); dataFileWriter.append(e1); dataFileWriter.append(e2); dataFileWriter.close(); System.out.println(“data successfully serialized”); } }
浏览到放置生成的代码的目录。在这种情况下,在home/Hadoop/Avro_work/without_code_gen。
$ cd home/Hadoop/Avro_work/without_code_gen/
现在将上述程序复制并保存在名为Serialize.java的文件中。编译并执行它,如下所示 –
$ javac Serialize.java $ java Serialize
输出
data successfully serialized
如果验证程序中给出的路径,可以找到生成的序列化文件,如下所示。
AVRO – 使用解析器进行反序列化
如前所述,可以通过生成与模式对应的类或使用解析器库将 Avro 模式读入程序。在 Avro 中,数据始终与其对应的架构一起存储。因此,我们始终可以在不生成代码的情况下读取序列化项。
本章介绍如何使用解析器库读取模式和使用 Avro反序列化数据。
使用解析器库进行反序列化
序列化的数据存储在文件mydata.txt 中。您可以使用 Avro 反序列化和读取它。
按照下面给出的过程反序列化文件中的序列化数据。
步骤1
首先,从文件中读取模式。为此,请使用Schema.Parser类。此类提供了以不同格式解析模式的方法。
通过传递存储架构的文件路径来实例化Schema.Parser类。
Schema schema = new Schema.Parser().parse(new File("/path/to/emp.avsc"));
第2步
使用SpecificDatumReader类创建DatumReader接口的对象。
DatumReader<emp>empDatumReader = new SpecificDatumReader<emp>(emp.class);
第 3 步
实例化DataFileReader类。此类从文件中读取序列化数据。它需要DatumReader对象和序列化数据所在文件的路径,作为构造函数的参数。
DataFileReader<GenericRecord> dataFileReader = new DataFileReader<GenericRecord>(new File("/path/to/mydata.txt"), datumReader);
第四步
使用DataFileReader的方法打印反序列化的数据。
-
的hasNext()如果在读取器的任何元件方法返回一个布尔值。
-
DataFileReader的next()方法返回 Reader 中的数据。
while(dataFileReader.hasNext()){ em=dataFileReader.next(em); System.out.println(em); }
示例 – 使用解析器库进行反序列化
以下完整程序显示了如何使用 Parsers 库反序列化序列化数据 –
public class Deserialize { public static void main(String args[]) throws Exception{ //Instantiating the Schema.Parser class. Schema schema = new Schema.Parser().parse(new File("/home/Hadoop/Avro/schema/emp.avsc")); DatumReader<GenericRecord> datumReader = new GenericDatumReader<GenericRecord>(schema); DataFileReader<GenericRecord> dataFileReader = new DataFileReader<GenericRecord>(new File("/home/Hadoop/Avro_Work/without_code_gen/mydata.txt"), datumReader); GenericRecord emp = null; while (dataFileReader.hasNext()) { emp = dataFileReader.next(emp); System.out.println(emp); } System.out.println("hello"); } }
浏览到放置生成的代码的目录。在这种情况下,它位于home/Hadoop/Avro_work/without_code_gen。
$ cd home/Hadoop/Avro_work/without_code_gen/
现在将上述程序复制并保存在名为DeSerialize.java的文件中。编译并执行它,如下所示 –
$ javac Deserialize.java $ java Deserialize
输出
{"name": "ramu", "id": 1, "salary": 30000, "age": 25, "address": "chennai"} {"name": "rahman", "id": 2, "salary": 35000, "age": 30, "address": "Delhi"}