Avro 简明教程
AVRO - Overview
为通过网络传输数据或进行持久化存储,您需要序列化数据。在 Java 和 Hadoop 提供的 serialization APIs 之前,我们有一个特殊的实用程序,称为 Avro ,一种基于模式的序列化技术。
本教程教您如何使用 Avro 序列化和反序列化数据。Avro 为各种编程语言提供库。在本教程中,我们使用 Java 库演示了示例。
What is Avro?
Apache Avro 是一个与语言无关的数据序列化系统。它由 Hadoop 之父 Doug Cutting 开发。由于 Hadoop 可写类缺乏语言可移植性,因此 Avro 非常有用,因为它处理的数据格式可以由多重语言处理。Avro 是一个序列化 Hadoop 数据的首选工具。
Avro 有一个基于模式的系统。与语言无关的模式与其读写操作相关联。Avro 序列化具有内置模式的数据。Avro 将数据序列化成紧凑的二进制格式,它可以被任何应用程序反序列化。
Avro 使用 JSON 格式来声明数据结构。目前,它支持 Java、C、C++、C#、Python 和 Ruby 等语言。
Avro Schemas
Avro 高度依赖其 schema 。它允许每个数据在完全不知道模式的情况下编写。它快速序列化,得到的序列化数据更小。模式连同 Avro 数据一起存储在一个文件中以进行任何进一步处理。
在 RPC 中,客户端和服务器在连接期间交换模式。此交换有助于具有相同名称的字段、丢失的字段、额外的字段等之间的通信。
Avro 模式用 JSON 定义,这简化了它在具有 JSON 库的语言中的实现。
与 Avro 一样,Hadoop 中还有其他序列化机制,例如 Sequence Files, Protocol Buffers, 和 Thrift 。
Comparison with Thrift and 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 |
Avro |
Thrift & Protocol Buffer |
Dynamic schema |
Yes |
No |
Built into Hadoop |
Yes |
No |
Schema in JSON |
Yes |
No |
No need to compile |
Yes |
No |
无需声明 ID |
Yes |
No |
Bleeding edge |
Yes |
No |
Features of Avro
下面列出 Avro 的一些突出特性 −
-
Avro 是一个 language-neutral 数据序列化系统。
-
它可以用多种语言进行处理(目前可以处理 C、C++、C#、Java、Python 和 Ruby)。
-
Avro 创建二进制结构化格式,既 compressible 又 splittable 。因此,可以将它有效地用作 Hadoop MapReduce 作业的输入。
-
Avro 提供 rich data structures 。例如,你可以创建一个包含数组、枚举类型和子记录的记录。这些数据类型可以在任何语言中创建,可以在 Hadoop 中处理,结果可以提供给第三语言。
-
schemas 在 JSON 中定义的 Avro,有助于在已拥有 JSON 库的语言中实现。
-
Avro 创建一个自描述文件,名为 Avro 数据文件,其中它连同其模式一起在元数据部分存储数据。
-
Avro 也用于远程过程调用 (RPC)。在 RPC 期间,客户端和服务器在连接握手时交换模式。
General Working of Avro
要使用 Avro,你需要执行以下工作流 −
-
Step 1 − 创建模式。此处你需要根据你的数据设计 Avro 模式。
-
Step 2 − 将模式读入程序。这可通过两种方法完成 − By Generating a Class Corresponding to Schema − 使用 Avro 编译模式。这将生成一个与模式对应的类文件 By Using Parsers Library − 你可以直接使用解析器库来读取模式。
-
Step 3 − 使用为 Avro 提供的序列化 API 来序列化数据,该 API 在 package org.apache.avro.specific 中。
-
Step 4 − 使用为 Avro 提供的反序列化 API 来反序列化数据,该 API 在 package org.apache.avro.specific. 中。
AVRO - Serialization
数据序列化有以下两个目的 −
-
For persistent storage
-
通过网络传输数据
What is Serialization?
序列化是指将数据结构或对象状态转换为二进制或文本形式,以便通过网络传输数据或存储在某些持久存储中。一旦通过网络传输数据或从持久存储中检索数据,就需要再次反序列化数据。序列化称为 marshalling ,而反序列化称为 unmarshalling 。
Serialization in Java
Java 提供了一种称为 object serialization 的机制,对象可以用作一个字节序列,其中包括对象的数据以及对象类型和存储在对象中的数据类型的信息。
将序列化的对象写入文件后,可以从该文件中读取并反序列化它。也就是说,表示对象及其数据的类型信息和字节可用于在内存中重新创建对象。
ObjectInputStream 和 ObjectOutputStream 类分别用于在 Java 中序列化和反序列化对象。
Serialization in Hadoop
通常,在 Hadoop 等分布式系统中,序列化概念用于 Interprocess Communication 和 Persistent Storage 。
Interprocess Communication
-
为了在连接到网络中的节点之间建立进程间通信,采用了 RPC 技术。
-
RPC 使用内部序列化在将消息发送到远程节点之前将其转换为二进制格式。在另一端,远程系统将二进制流反序列化为原始消息。
-
对 RPC 序列化格式的要求如下 − Compact − 充分利用网络带宽,这是数据中心中最宝贵的资源。 Fast − 由于节点之间的通信在分布式系统中至关重要,因此序列化和反序列化过程应快速,产生的开销较小。 Extensible − 协议会随着时间推移而改变,以满足新要求,因此应以受控方式轻松地为客户端和服务器发展协议。 Interoperable − 消息格式应支持用不同编程语言编写的节点。
Writable Interface
这是 Hadoop 中的接口,它提供用于序列化和反序列化的多种方法。下表对这些方法进行了描述 −
S.No. |
Methods and Description |
1 |
void readFields(DataInput in) 该方法用于反序列化给定对象字段。 |
2 |
void write(DataOutput out) 该方法用于序列化给定对象字段。 |
Writable Comparable Interface
它结合了 Writable 和 Comparable 接口。该接口继承了 Hadoop 的 Writable 接口和 Java 的 Comparable 接口。所以它提供了用于数据序列化、反序列化和比较的方法。
S.No. |
Methods and Description |
1 |
int compareTo(class obj) 该方法将当前对象与给定对象 obj 进行比较。 |
除了这些类以外,Hadoop 还支持许多实现 WritableComparable 接口的包装类。每个类都包装一个 Java 原始类型。Hadoop 序列化的类层次结构如下 −
这些类有助于序列化 Hadoop 中各种类型的数据。例如,我们考虑 IntWritable 类。我们看看是如何使用此类来序列化和反序列化 Hadoop 中的数据的。
IntWritable Class
此类实现了 Writable, Comparable, 和 WritableComparable 接口。它包装了一个整数数据类型。此类提供了用于序列化和反序列化整数类型数据的的方法。
Serializing the Data in Hadoop
下面讨论序列化整数类型数据的过程。
-
通过包装一个整数值来实例化 IntWritable 类。
-
Instantiate ByteArrayOutputStream class.
-
实例化 DataOutputStream 类,并将 ByteArrayOutputStream 类的对象传递给它。
-
使用 write() 方法在 IntWritable 对象中序列化整数值。此方法需要 DataOutputStream 类的对象。
-
已序列化的数据将存储在字节数组对象中,该对象在实例化时作为参数传递给 DataOutputStream 类。将对象中的数据转换为字节数组。
Example
以下示例显示了如何在 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();
}
}
Deserializing the Data in Hadoop
下面讨论反序列化整数类型数据的过程:
-
通过包装一个整数值来实例化 IntWritable 类。
-
Instantiate ByteArrayOutputStream class.
-
实例化 DataOutputStream 类,并将 ByteArrayOutputStream 类的对象传递给它。
-
使用 IntWritable 类的 readFields() 方法反序列化 DataInputStream 对象中的数据。
-
反序列化的数据将存储在 IntWritable 类的对象中。可以使用此类的 get() 方法检索此数据。
Example
以下示例显示了如何在 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());
}
}
Advantage of Hadoop over Java Serialization
Hadoop 的基于可写对象的序列化能够通过重新使用可写对象来减少对象创建开销,而 Java 的原生序列化框架不能这么做。
Disadvantages of Hadoop Serialization
要序列化 Hadoop 数据,有两种办法:
-
可以使用 Hadoop 的原生库提供的 Writable 类。
-
您还可以使用存储二进制格式数据的 Sequence Files 。
这两种机制的主要缺点是 Writables 和 SequenceFiles 仅有一个 Java API,不能用其他任何语言编写或读入。
因此,任何使用上述两种机制在 Hadoop 中创建的文件都无法被任何其他第三方语言读取,这使得 Hadoop 成为一个限制盒子。为了解决这一缺点,Doug Cutting 创建了 Avro, ,它是一个 language independent data structure 。
AVRO - Environment Setup
Apache 软件基金会提供带有各种版本的 Avro。你可以从 Apache 镜像中下载必需版本。让我们了解如何设置环境来使用 Avro:
Downloading Avro
要下载 Apache Avro,执行以下操作:
-
打开网页 Apache.org 。你将看到 Apache Avro 的主页,如下所示:
-
点击项目 → 版本。你将获取版本列表。
-
选择可引导你到一个下载链接的最新版本。
-
mirror.nexcess 是你可以找到 Avro 支持的不同语言的所有库列表的链接之一,如下所示 −
你可以选择和下载任何提供的语言的库。在本教程中,我们使用 Java。因此下载 jar 文件 avro-1.7.7.jar 和 avro-tools-1.7.7.jar 。
Avro with Eclipse
要在 Eclipse 环境中使用 Avro,你需要按照下面给出的步骤操作 −
-
Step 1. Open eclipse.
-
Step 2. 创建一个项目。
-
Step 3. 右键单击项目名称。你会得到一个快捷菜单。
-
Step 4. 点击 Build Path 。它会引导你到另一个快捷菜单。
-
Step 5. 点击 Configure Build Path…​ 你可以看到项目属性窗口,如下所示 −
-
Step 6. 在库标签下,点击 ADD EXternal JARs…​ 按钮。
-
Step 7. 选择你下载的 avro-1.77.jar jar 文件。
-
Step 8. 点击 OK 。
Avro with 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>
AVRO - Schemas
Avro 是基于模式的序列化工具,接收模式作为输入。尽管有各种模式可用,但 Avro 遵循其定义模式的自己的标准。这些模式描述以下详细信息 −
-
文件类型(默认为记录)
-
location of record
-
name of the record
-
记录中的字段及其相应的数据类型
使用这些模式,你可以使用更少的空间将序列化值存储在二进制格式中。这些值存储没有任何元数据。
Creating Avro Schemas
Avro 模式是在 JavaScript 对象表示法 (JSON) 文档格式中创建的,这是一种轻量级的基于文本的数据交换格式。它可以用以下方式创建 −
-
A JSON string
-
A JSON object
-
A JSON array
Example - 下面的示例显示了一个模式,它在名称空间 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。在字段的情况下,它描述字段的名称。
Primitive Data Types of Avro
Avro 模式既有原始数据类型,也有复杂数据类型。下表描述了 Avro 的 primitive data types -
Data type |
Description |
null |
Null 是没有值的类型。 |
int |
32-bit signed integer. |
long |
64-bit signed integer. |
float |
单精度(32 位)IEEE 754 浮点数。 |
double |
双精度(64 位)IEEE 754 浮点数。 |
bytes |
8 位无符号字节序列。 |
string |
Unicode character sequence. |
Complex Data Types of Avro
除了原始数据类型之外,Avro 还提供六种复杂数据类型,即记录、枚举、数组、映射、联合和固定的。
Record
Avro 中的记录数据类型是多个属性的集合。它支持以下属性 -
-
name - 此字段的值保存记录的名称。
-
namespace - 此字段的值保存对象存储的名称空间的名称。
-
type - 此属性的值保存模式中文档(记录)的类型或字段的数据类型。
-
fields - 此字段保存一个 JSON 数组,其中包含模式中所有字段的列表,每个字段都有名称和类型属性。
Example
下面给出一个记录的示例。
{
" type " : "record",
" namespace " : "Tutorialspoint",
" name " : "Employee",
" fields " : [
{ "name" : " Name" , "type" : "string" },
{ "name" : "age" , "type" : "int" }
]
}
Enum
枚举是集合中项的列表,Avro 枚举支持以下属性 -
-
name - 此字段的值保存枚举的名称。
-
namespace −此字段的值包含限定枚举名称的字符串。
-
symbols −此字段的值将枚举的符号作为名称数组保存。
Example
以下是枚举的示例。
{
"type" : "enum",
"name" : "Numbers",
"namespace": "data",
"symbols" : [ "ONE", "TWO", "THREE", "FOUR" ]
}
Maps
地图数据类型是键值对的数组,它以键值对组织数据。Avro 地图的键必须是字符串。地图的值保存地图内容的数据类型。
Example
{"type" : "map", "values" : "int"}
AVRO - Reference API
在上一章,我们介绍了 Avro 的输入类型,即 Avro 模式。在本章,我们将介绍在 Avro 模式的序列化和反序列化中使用的类和方法。
SpecificDatumWriter Class
此类属于 org.apache.avro.specific 程序包。它实现了接口 DatumWriter ,该接口将 Java 对象转换为内存中的序列化格式。
SpecificDatumReader Class
此类属于程序包 org.apache.avro.specific 。它实现了接口 DatumReader ,该接口读取模式的数据并确定内存中数据表示。 SpecificDatumReader 是支持生成 Java 类别。
AVRO - Serialization By Generating Class
可以通过生成与架构图相对应的类或者使用解析器库将 Avro 架构图读入程序。本章介绍了如何使用 Avro 读取架构图 by generating a class 和 Serializing 数据。
Serialization by Generating a Class
若要使用 Avro 序列化数据,请按照以下步骤操作:
-
Write an Avro schema.
-
使用 Avro 实用程序编译架构图。您可以获得与该架构图相对应的 Java 代码。
-
使用数据填充架构图。
-
使用 Avro 库序列化它。
Defining a Schema
假设您想要一个具有以下详细信息的架构图:
Field |
Name |
id |
age |
salary |
address |
type |
String |
int |
int |
int |
string |
创建如下所示的 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"}
]
}
Compiling the Schema
在创建 Avro 架构图后,您需要使用 Avro 工具来编译所创建的架构图。 avro-tools-1.7.7.jar 是包含这些工具的 jar。
Syntax to Compile an Avro Schema
java -jar <path/to/avro-tools-1.7.7.jar> compile schema <path/to/schema-file> <destination-folder>
在 home 文件夹中打开终端。
创建一个新目录以使用 Avro,如下所示:
$ mkdir Avro_Work
在新建目录中,创建三个子目录−
-
首先命名为 schema, 以放置模式。
-
第二名为 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
编译后,根据模式的名称空间在目标目录中创建一个包。在此包中,将创建具有模式名称的 Java 源代码。此生成的源代码是给定模式的 Java 代码,可直接在应用程序中使用。
例如,在此实例中创建了一个名为 tutorialspoint 的包/文件夹,其中包含另一个名为 com 的文件夹(因为名称空间是 tutorialspoint.com),在其中,您可以看到生成的文件 emp.java 。以下快照显示 emp.java −
此类对于根据模式创建数据十分有用。
生成的类包含−
-
默认构造函数和接收模式所有变量的参数化构造函数。
-
模式中所有变量的 setter 和 getter 方法。
-
返回模式的 Get() 方法。
-
Builder methods.
Creating and Serializing the Data
首先,将此项目中使用的已生成 java 文件复制到当前目录中或从其所在位置导入该文件。
现在我们可以编写一个新的 Java 文件并实例化生成文件中 ( emp ) 的类以向模式中添加员工数据。
让我们了解使用 Apache Avro 根据模式创建数据的过程。
Step 2
使用 setter 方法,插入第一个员工的数据。例如,我们已经创建的名为 Omar 的员工的详细信息。
e1.setName("omar");
e1.setAge(21);
e1.setSalary(30000);
e1.setAddress("Hyderabad");
e1.setId(001);
同样,使用 setter 方法填写所有员工详细信息。
Step 3
使用 SpecificDatumWriter 类创建 DatumWriter 接口的对象。这会将 Java 对象转换为内存中的序列化格式。以下示例会为 emp 类实例化 SpecificDatumWriter 类对象。
DatumWriter<emp> empDatumWriter = new SpecificDatumWriter<emp>(emp.class);
Step 4
为 emp 类实例化 DataFileWriter 。该类会连同模式本身将符合模式的数据序列序列化记录写入文件。该类需要 DatumWriter 对象作为构造函数的参数。
DataFileWriter<emp> empFileWriter = new DataFileWriter<emp>(empDatumWriter);
Example – Serialization by Generating a Class
以下完整程序演示如何使用 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 中。
In Terminal −
$ cd home/Hadoop/Avro_work/with_code_gen/
In GUI −
现在将上述程序复制并保存到名为 Serialize.java 的文件中。
按如下所示进行编译并执行:
$ javac Serialize.java
$ java Serialize
AVRO - Deserialization By Generating Class
如前所述,可以通过生成与模式相对应的类或通过使用解析器库来读取 Avro 模式到一个程序中。本章介绍了如何使用 Avro 读取模式 by generating a class 和 Deserialize 数据。
Deserialization by Generating a Class
序列化数据存储在文件 emp.avro 中。你可以使用 Avro 序列化并读取它。
按照以下步骤从文件中序列化序列化数据。
Step 1
使用 SpecificDatumReader 类创建一个 DatumReader 接口对象。
DatumReader<emp>empDatumReader = new SpecificDatumReader<emp>(emp.class);
Example – Deserialization by Generating a Class
以下完整程序展示了如何使用 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
AVRO - Serialization Using Parsers
可以通过生成对应于模式的类或使用解析器库将 Avro 模式读入程序中。在 Avro 中,数据始终与相应模式一起存储。因此,我们可以始终在不生成代码的情况下读取模式。
本章介绍如何读取模式 by using parsers library 以及使用 Avro serialize 数据。
Serialization Using Parsers Library
要序列化数据,我们需要读取模式,根据模式创建数据,并使用 Avro API 序列化模式。以下过程在不生成任何代码的情况下对数据进行序列化 −
Step 1
首先,从文件中读取模式。为此,请使用 Schema.Parser 类。此类提供以不同格式解析模式的方法。
通过传递存储模式的文件路径实例化 Schema.Parser 类。
Schema schema = new Schema.Parser().parse(new File("/path/to/emp.avsc"));
Step 2
创建 GenericRecord 接口的对象,通过实例化 GenericData.Record 类,如下所示。将上述创建的模式对象传递给构造函数。
GenericRecord e1 = new GenericData.Record(schema);
Step 3
使用 GenericData 类的 put() 方法在模式中插入值。
e1.put("name", "ramu");
e1.put("id", 001);
e1.put("salary",30000);
e1.put("age", 25);
e1.put("address", "chennai");
Step 4
使用 SpecificDatumWriter 类创建 DatumWriter 接口的对象。它将 Java 对象转换为内存中序列化的格式。以下示例为 emp 类实例化 SpecificDatumWriter 类对象 −
DatumWriter<emp> empDatumWriter = new SpecificDatumWriter<emp>(emp.class);
Step 5
为 emp 类实例化 DataFileWriter 。此类将符合模式的数据的序列化记录与模式本身一起写入文件。此类需要 DatumWriter 对象作为构造函数的参数。
DataFileWriter<emp> dataFileWriter = new DataFileWriter<emp>(empDatumWriter);
Example – Serialization Using Parsers
以下完整程序显示了如何使用解析器对数据进行序列化 −
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
AVRO - Deserialization Using Parsers
如前所述,可以通过生成与模式对应的类或使用解析器库将 Avro 模式读入程序。在 Avro 中,数据总是与它对应的模式存储在一起。因此,我们始终可以在不生成代码的情况下读取一个序列化项。
本章描述了如何使用 Avro 读取模式 using parsers library 和 Deserializing 数据。
Deserialization Using Parsers Library
序列化数据存储在文件 mydata.txt 中。你可以使用 Avro 反序列化和读取它。
按照以下步骤从文件中序列化序列化数据。
Step 1
首先,从文件中读取模式。为此,请使用 Schema.Parser 类。此类提供以不同格式解析模式的方法。
通过传递存储模式的文件路径实例化 Schema.Parser 类。
Schema schema = new Schema.Parser().parse(new File("/path/to/emp.avsc"));
Step 2
使用 SpecificDatumReader 类创建一个 DatumReader 接口对象。
DatumReader<emp>empDatumReader = new SpecificDatumReader<emp>(emp.class);
Example – Deserialization Using Parsers Library
以下完整程序展示了如何使用解析器库序列化序列化数据:
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