AVRO - 快速指南


AVRO - 概述

要通过网络传输数据或用于持久存储,您需要对数据进行序列化。在Java 和 Hadoop 提供的序列化 API之前,我们有一个特殊的实用程序,称为Avro,它是一种基于模式的序列化技术。

本教程教您如何使用 Avro 序列化和反序列化数据。Avro 提供各种编程语言的库。在本教程中,我们将使用 Java 库演示示例。

什么是阿夫罗?

Apache Avro 是一个与语言无关的数据序列化系统。它是由 Hadoop 之父 Doug Cutting 开发的。由于 Hadoop 可写类缺乏语言可移植性,Avro 变得非常有用,因为它处理可由多种语言处理的数据格式。Avro 是 Hadoop 中序列化数据的首选工具。

Avro 有一个基于模式的系统。独立于语言的模式与其读写操作相关联。Avro 序列化具有内置模式的数据。Avro 将数据序列化为紧凑的二进制格式,任何应用程序都可以反序列化。

Avro 使用 JSON 格式来声明数据结构。目前,它支持 Java、C、C++、C#、Python 和 Ruby 等语言。

Avro 模式

Avro 在很大程度上依赖于它的架构。它允许在事先不了解模式的情况下写入每个数据。它序列化速度快,并且生成的序列化数据的大小较小。模式与 Avro 数据一起存储在文件中以供进一步处理。

在 RPC 中,客户端和服务器在连接期间交换模式。这种交换有助于相同命名字段、缺失字段、额外字段等之间的通信。

Avro 架构是使用 JSON 定义的,这简化了其在具有 JSON 库的语言中的实现。

与 Avro 一样,Hadoop 中还有其他序列化机制,例如序列文件、协议缓冲区Thrift

与 Thrift 和 Protocol Buffer 的比较

ThriftProtocol Buffers是 Avro 最有能力的库。Avro 与这些框架的不同之处如下:

  • Avro 根据要求支持动态和静态类型。Protocol Buffers 和 Thrift 使用接口定义语言 (IDL) 来指定模式及其类型。这些 IDL 用于生成序列化和反序列化代码。

  • Avro 构建于 Hadoop 生态系统中。Thrift 和 Protocol Buffers 不是构建在 Hadoop 生态系统中的。

与 Thrift 和 Protocol Buffer 不同,Avro 的模式定义采用 JSON 格式,而不是任何专有的 IDL 格式。

财产 阿夫罗 Thrift 和协议缓冲区
动态模式 是的
内置于 Hadoop 中 是的
JSON 中的架构 是的
无需编译 是的
无需申报ID 是的
最前沿 是的

阿夫罗的特点

下面列出了 Avro 的一些突出特点 -

  • Avro 是一个与语言无关的数据序列化系统。

  • 它可以被多种语言处理(目前是 C、C++、C#、Java、Python 和 Ruby)。

  • Avro 创建既可压缩又可拆分的二进制结构格式。因此,它可以有效地用作 Hadoop MapReduce 作业的输入。

  • Avro提供了丰富的数据结构。例如,您可以创建包含数组、枚举类型和子记录的记录。这些数据类型可以用任何语言创建,可以在 Hadoop 中处理,并且结果可以输入第三种语言。

  • JSON定义的Avro模式有助于在已有 JSON 库的语言中实现。

  • Avro 创建一个名为Avro 数据文件的自描述文件,其中将数据及其架构存储在元数据部分中。

  • Avro 还用于远程过程调用 (RPC)。在 RPC 期间,客户端和服务器在连接握手中交换模式。

Avro 的一般工作

要使用 Avro,您需要遵循给定的工作流程 -

  • 步骤 1 - 创建模式。这里你需要根据你的数据设计Avro schema。

  • 步骤 2 - 将模式读入您的程序中。它有两种方式完成 -

    • 通过生成对应于架构的类- 使用 Avro 编译架构。这会生成与模式对应的类文件

    • 通过使用解析器库- 您可以使用解析器库直接读取模式。

  • 步骤 3 - 使用为 Avro 提供的序列化 API 序列化数据,该 API 可以在包 org.apache.avro.specific中找到。

  • 步骤 4 - 使用为 Avro 提供的反序列化 API 反序列化数据,该 API 位于包 org.apache.avro.spec. 中。

AVRO - 序列化

数据序列化有两个目的 -

  • 用于持久存储

  • 通过网络传输数据

什么是序列化?

序列化是将数据结构或对象状态转换为二进制或文本形式以通过网络传输数据或存储在某些持久存储上的过程。一旦数据通过网络传输或从持久存储中检索,就需要再次反序列化。序列化称为编组,反序列化称为解组

Java 中的序列化

Java 提供了一种称为对象序列化的机制,其中对象可以表示为字节序列,其中包括对象的数据以及有关对象类型和对象中存储的数据类型的信息。

将序列化对象写入文件后,可以从文件中读取它并反序列化。也就是说,表示对象及其数据的类型信息和字节可用于在内存中重新创建对象。

Java 中的ObjectInputStreamObjectOutputStream类分别用于序列化和反序列化对象。

Hadoop 中的序列化

通常在像Hadoop这样的分布式系统中,序列化的概念用于进程间通信持久存储

进程间通信

  • 为了在网络中连接的节点之间建立进程间通信,使用了 RPC 技术。

  • RPC 使用内部序列化将消息转换为二进制格式,然后通过网络发送到远程节点。在另一端,远程系统将二进制流反序列化为原始消息。

  • RPC 序列化格式要求如下 -

    • 紧凑- 充分利用网络带宽,这是数据中心中最稀缺的资源。

    • 快速- 由于节点之间的通信在分布式系统中至关重要,因此序列化和反序列化过程应该很快,从而产生更少的开销。

    • 可扩展- 协议随着时间的推移而变化以满足新的要求,因此以受控方式为客户端和服务器发展协议应该很简单。

    • 可互操作- 消息格式应支持用不同语言编写的节点。

持久存储

持久存储是一种数字存储设施,不会因断电而丢失数据。文件、文件夹、数据库是持久存储的示例。

可写接口

这是 Hadoop 中的接口,提供序列化和反序列化的方法。下表描述了这些方法 -

编号 方法和说明
1

无效readFields(数据输入)

该方法用于反序列化给定对象的字段。

2

无效写入(数据输出)

该方法用于序列化给定对象的字段。

可写的类似接口

它是WritableComparable接口的组合。该接口继承了Hadoop的Writable接口以及Java的Comparable接口。因此它提供了数据序列化、反序列化和比较的方法。

编号 方法和说明
1

int 比较(对象类)

该方法将当前对象与给定对象 obj 进行比较。

除了这些类之外,Hadoop 还支持许多实现 WritableComparable 接口的包装类。每个类都包装一个 Java 原始类型。Hadoop 序列化的类层次结构如下 -

Hadoop 序列化层次结构

这些类对于在 Hadoop 中序列化各种类型的数据非常有用。例如,让我们考虑IntWritable类。让我们看看这个类如何用于在 Hadoop 中序列化和反序列化数据。

可写类

此类实现Writable、ComparableWritableComparable接口。它在其中包装了整数数据类型。此类提供用于序列化和反序列化整数类型数据的方法。

构造函数

编号 概括
1 可写()
2 IntWritable(整数值)

方法

编号 概括
1

int 获取()

使用此方法,您可以获得当前对象中存在的整数值。

2

无效readFields(数据输入)

此方法用于反序列化给定DataInput对象中的数据。

3

无效集(整数值)

该方法用于设置当前IntWritable对象的值。

4

无效写入(数据输出)

该方法用于将当前对象中的数据序列化到给定的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类。

  • 您还可以使用以二进制格式存储数据的序列文件。

这两种机制的主要缺点是WritablesSequenceFiles只有 Java API,不能用任何其他语言编写或读取它们。

因此,使用上述两种机制在 Hadoop 中创建的任何文件都无法被任何其他第三语言读取,这使得 Hadoop 成为一个有限的盒子。为了解决这个缺点,Doug Cutting 创建了Avro,它是一种独立于语言的数据结构

AVRO - 环境设置

Apache 软件基金会为 Avro 提供了各种版本。您可以从 Apache 镜像下载所需的版本。让我们看看如何设置与 Avro 一起工作的环境 -

下载 Avro

要下载 Apache Avro,请继续执行以下操作 -

  • 打开网页Apache.org。您将看到 Apache Avro 的主页,如下所示 -

阿夫罗主页
  • 单击项目→发布。您将获得一个版本列表。

  • 选择最新版本,您将看到下载链接。

  • mirror.nexcess是您可以找到 Avro 支持的不同语言的所有库的列表的链接之一,如下所示 -

Avro 语言支持

您可以选择并下载所提供的任何语言的库。在本教程中,我们使用 Java。因此,下载 jar 文件avro-1.7.7.jaravro-tools-1.7.7.jar

Avro 与 Eclipse

要在 Eclipse 环境中使用 Avro,您需要按照以下步骤操作 -

  • 步骤1.打开eclipse。

  • 步骤2.创建一个项目。

  • 步骤 3.右键单击​​项目名称。您将得到一个快捷菜单。

  • 步骤 4.单击“构建路径”。它会引导您进入另一个快捷菜单。

  • 步骤 5.单击“配置构建路径...”您可以看到项目的“属性”窗口,如下所示 -

Avro 的属性
  • 步骤 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,具有字段name和age。

{
   "type" : "record",
   "namespace" : "Tutorialspoint",
   "name" : "Employee",
   "fields" : [
      { "name" : "Name" , "type" : "string" },
      { "name" : "Age" , "type" : "int" }
   ]
}

在此示例中,您可以观察到每条记录有四个字段 -

  • type - 该字段位于文档下以及名为 fields 的字段下。

    • 如果是文档,它显示文档的类型,通常是一条记录,因为有多个字段。

    • 当为字段时,类型描述数据类型。

  • 命名空间- 该字段描述对象所在的命名空间的名称。

  • name - 该字段位于文档下方以及名为 fields 的字段下方。

    • 如果是文档,它描述模式名称。此模式名称与命名空间一起唯一标识存储中的模式(Namespace.schema name)。在上面的示例中,架构的全名将为Tutorialspoint.Employee。

    • 如果是字段,它描述字段的名称。

Avro 的原始数据类型

Avro 模式具有原始数据类型和复杂数据类型。下表描述了Avro 的原始数据类型-

数据类型 描述
无效的 Null 是没有值的类型。
整数 32 位有符号整数。
长的 64 位有符号整数。
漂浮 单精度(32 位)IEEE 754 浮点数。
双倍的 双精度(64 位)IEEE 754 浮点数。
字节 8 位无符号字节序列。
细绳 Unicode 字符序列。

Avro 的复杂数据类型

除了原始数据类型之外,Avro 还提供六种复杂数据类型,即记录、枚举、数组、映射、联合和固定。

记录

Avro 中的记录数据类型是多个属性的集合。它支持以下属性 -

  • name - 该字段的值保存记录的名称。

  • 命名空间- 该字段的值保存存储对象的命名空间的名称。

  • type - 该属性的值保存文档(记录)的类型或模式中字段的数据类型。

  • fields - 该字段包含一个 JSON 数组,其中包含架构中所有字段的列表,每个字段都有名称和类型属性。

例子

下面给出的是记录的示例。

{
" type " : "record",
" namespace " : "Tutorialspoint",
" name " : "Employee",
" fields " : [
 { "name" : " Name" , "type" : "string" },
 { "name" : "age" , "type" : "int" }
 ]
}

枚举

枚举是集合中的项目列表,Avro 枚举支持以下属性 -

  • name - 该字段的值保存枚举的名称。

  • 命名空间- 该字段的值包含限定枚举名称的字符串。

  • Symbols - 该字段的值将枚举的符号保存为名称数组。

例子

下面给出的是枚举的示例。

{
   "type" : "enum",
   "name" : "Numbers", 
   "namespace": "data", 
   "symbols" : [ "ONE", "TWO", "THREE", "FOUR" ]
}

数组

该数据类型定义具有单个属性项的数组字段。此 items 属性指定数组中项目的类型。

例子

{ " type " : " array ", " items " : " int " }

地图

映射数据类型是键值对数组,它将数据组织为键值对。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 模式的序列化和反序列化中使用的类和方法。

SpecificDatumWriter 类

该类属于包org.apache.avro.specific。它实现了DatumWriter接口,该接口将 Java 对象转换为内存中的序列化格式。

构造函数

编号 描述
1 SpecificDatumWriter(Schema 架构)

方法

编号 描述
1

具体数据 getSpecificData()

返回此编写器使用的 SpecificData 实现。

SpecificDatumReader 类

该类属于包org.apache.avro.specific。它实现了DatumReader接口,该接口读取模式的数据并确定内存中的数据表示。SpecificDatumReader是支持生成的 java 类的类。

构造函数

编号 描述
1

SpecificDatumReader(Schema 架构)

构建作者和读者的模式相同的地方。

方法

编号 描述
1

具体数据 getSpecificData()

返回包含的特定数据。

2

void setSchema(实际架构)

该方法用于设置作者的模式。

数据文件写入器

实例化emp类的DataFileWrite。此类写入符合模式的序列化数据记录以及文件中的模式。

构造函数

编号 描述
1 DataFileWriter(DatumWriter<D> dout)

方法

序列号 描述
1

无效追加(D 数据)

将数据附加到文件。

2

DataFileWriter<D>appendTo(文件文件)

此方法用于打开附加到现有文件的编写器。

数据文件读取器

此类提供对使用DataFileWriter写入的文件的随机访问。它继承类DataFileStream

构造函数

编号 描述
1 DataFileReader(文件文件, DatumReader<D> 阅读器))

方法

编号 描述
1

下一个()

读取文件中的下一个数据。

2

布尔值 h​​asNext()

如果此文件中还有更多条目,则返回 true。

类 Schema.parser

此类是 JSON 格式模式的解析器。它包含解析模式的方法。它属于org.apache.avro包。

构造函数

编号 描述
1 模式解析器()

方法

编号 描述
1

解析(文件文件)

解析给定文件中提供的架构。

2

解析(输入流中)

解析给定InputStream中提供的架构。

3

解析(字符串)

解析给定String中提供的架构。

通用记录接口

该接口提供了按名称和索引访问字段的方法。

方法

编号 描述
1

对象获取(字符串键)

返回给定字段的值。

2

void put(字符串键, 对象 v)

设置给定名称的字段的值。

类 GenericData.Record

构造函数

编号 描述
1 GenericData.Record(模式架构)

方法

编号 描述
1

对象获取(字符串键)

返回给定名称的字段的值。

2

架构 getSchema()

返回此实例的架构。

3

void put(int i, 对象 v)

根据给定字段在架构中的位置设置字段的值。

4

void put(字符串键,对象值)

设置给定名称的字段的值。

AVRO - 通过生成类进行序列化

人们可以通过生成与模式对应的类或使用解析器库将 Avro 模式读入程序。本章介绍如何通过生成类并使用 Avr序列化数据来读取模式。

Avro WithCode 序列化

通过生成类进行序列化

要使用 Avro 序列化数据,请按照以下步骤操作 -

  • 编写 Avro 架构。

  • 使用 Avro 实用程序编译架构。您将获得与该模式相对应的 Java 代码。

  • 用数据填充架构。

  • 使用 Avro 库对其进行序列化。

定义模式

假设您想要一个具有以下详细信息的模式 -

场地 姓名 ID 年龄 薪水 地址
类型 细绳 整数 整数 整数 细绳

创建 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 schema 后,您需要使用 Avro 工具编译创建的 schema。 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

在新创建的目录中,创建三个子目录 -

  • 首先命名schema,用于放置 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

编译完成后,会在目标目录中根据 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);

步骤4

实例化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/

在图形用户界面中 -

生成的代码

现在将上述程序复制并保存在名为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的方法打印反序列化的数据。

  • 如果 Reader 中有任何元素,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 无代码序列化

使用解析器库进行序列化

为了序列化数据,我们需要读取 schema,根据 schema 创建数据,并使用 Avro API 序列化 schema。以下过程序列化数据而不生成任何代码 -

步骤1

首先,从文件中读取架构。为此,请使用Schema.Parser类。此类提供了解析不同格式模式的方法。

通过传递存储架构的文件路径来实例化Schema.Parser类。

Schema schema = new Schema.Parser().parse(new File("/path/to/emp.avsc"));

第2步

通过实例化GenericData.Record类来创建GenericRecord接口的对象,如下所示。将上面创建的模式对象传递给其构造函数。

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");

步骤4

使用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

如果验证程序中给出的路径,可以找到生成的序列化文件,如下所示。

没有代码 Gen1

AVRO - 使用解析器进行反序列化

如前所述,可以通过生成与模式对应的类或使用解析器库将 Avro 模式读入程序中。在 Avro 中,数据始终与其相应的模式一起存储。因此,我们总是可以读取序列化的项目而无需生成代码。

本章介绍如何使用解析器库读取模式并使用 Avro反序列化数据。

使用解析器库进行反序列化

序列化数据存储在文件mydata.txt中。您可以使用 Avro 反序列化并读取它。

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);

步骤4

使用DataFileReader的方法打印反序列化的数据。

  • 如果 Reader 中有任何元素,则 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"}