Apache Avro 1.8.1 入门指南(Java)

来源:互联网 发布:touch.js api 编辑:程序博客网 时间:2024/05/29 09:15

在快速入门之前,我们先来了解一下Apache Avro到底是什么东东?能够用来做什么?

Apache Avro是一个数据序列化系统。序列化就是将对象转换成二进制流,相应的反序列化就是将二进制流再转换成对应的对象。因此,Avro就是用来在传输数据之前,将对象转换成二进制流,然后此二进制流达到目标地址后,Avro再将二进制流转换成对象。

接下来,我们看看官方网站上是怎么说的。

Apache Avro是一个数据序列化系统。

Avro提供:

  • 丰富的数据结构
  • 一个紧凑的,快速的,二进制的数据格式
  • 一个容器文件,来存储持久化数据
  • 远程过程调用(RPC)
  • 简单的动态语言集成。
  • 代码生成不需要读写数据文件,也不要使用或实现RPC协议。代码生成是作为一个可选的优化,只对静态类型的语言值得实现。

大家知道,JSON是一种轻量级的数据传输格式,对于大数据集,JSON数据会显示力不从心,因为JSON的格式是key:value型,每条记录都要附上key的名字,有的时候,光key消耗的空间甚至会超过value所占空间,这对空间的浪费十分严重,尤其是对大型数据集来说,因为它不仅不够紧凑,还要重复地加上key信息,不仅会造成存储空间上的浪费,更会增加了数据传输的压力,从而给集群增加负担,进而影响整个集群的吞吐量。而采用Avro数据序列化系统可以比较好的解决此问题,因为用Avro序列化后的文件由schema和真实内容组成,schema只是数据的元数据,相当于JSON数据的key信息,schema单独存放在一个JSON文件中,这样一来,数据的元数据只存了一次,相比JSON数据格式的文件,大大缩小了存储容量。从而使得Avro文件可以更加紧凑地组织数据。

接下来,我们开始使用Avro。

下载

以Maven为例,增加Avro的依赖,及插件,插件的好处在于,可以直接自动地为avsc文件生成类。

<dependencies>        <dependency>            <groupId>org.apache.avro</groupId>            <artifactId>avro</artifactId>            <version>1.8.1</version>        </dependency>        <dependency>            <groupId>junit</groupId>            <artifactId>junit</artifactId>            <version>4.12</version>        </dependency></dependencies>    <build>        <plugins>            <plugin>                <groupId>org.apache.avro</groupId>                <artifactId>avro-maven-plugin</artifactId>                <version>1.8.1</version>                <executions>                    <execution>                        <phase>generate-sources</phase>                        <goals>                            <goal>schema</goal>                        </goals>                        <configuration>                            <sourceDirectory>${project.basedir}/src/main/avro/</sourceDirectory>                            <outputDirectory>${project.basedir}/src/main/java/</outputDirectory>                        </configuration>                    </execution>                </executions>            </plugin>            <plugin>                <groupId>org.apache.maven.plugins</groupId>                <artifactId>maven-compiler-plugin</artifactId>                <configuration>                    <source>1.6</source>                    <target>1.6</target>                </configuration>            </plugin>        </plugins>    </build>

值得注意的是:以上pom文件配置了自动生成类的路径,即${project.basedir}/src/main/avro/${project.basedir}/src/main/java/,这样配置之后,在执行mvn命令的时候,这个插件就会自动将此目录下的avsc schema生成类文件,并放到后者这个目录下。

定义schema

使用JSON为Avro定义schema。schema由基本类型(null,boolean, int, long, float, double, bytes 和string)和复杂类型(record, enum, array, map, union, 和fixed)组成。例如,以下定义一个user的schema,在main目录下创建一个avro目录,然后在avro目录下新建文件 user.avsc :

{"namespace": "lancoo.ecbdc.pre", "type": "record", "name": "User", "fields": [     {"name": "name", "type": "string"},     {"name": "favorite_number",  "type": ["int", "null"]},     {"name": "favorite_color", "type": ["string", "null"]} ]}

这里写图片描述

用代码生成来序列化和反序列化

编译schema

在这里,因为使用avro插件,所以,直接输入以下命令,maven插件会自动帮我们生成类文件:

mvn clean install

然后在刚才配置的目录下就会生成相应的类,如下:
这里写图片描述

如果不使用插件,也可以使用avro-tools来生成:

java -jar /path/to/avro-tools-1.8.1.jar compile schema <schema file> <destination>

创建用户

在前面,类文件已经创建好了,接下来,可以使用刚才自动生成的类来创建用户了:

User user1 = new User();user1.setName("Alyssa");user1.setFavoriteNumber(256);// Leave favorite color null// Alternate constructorUser user2 = new User("Ben", 7, "red");// Construct via builderUser user3 = User.newBuilder()             .setName("Charlie")             .setFavoriteColor("blue")             .setFavoriteNumber(null)             .build();

序列化

把前面创建的用户序列化并存储到磁盘文件:

// Serialize user1, user2 and user3 to diskDatumWriter<User> userDatumWriter = new SpecificDatumWriter<User>(User.class);DataFileWriter<User> dataFileWriter = new DataFileWriter<User>(userDatumWriter);dataFileWriter.create(user1.getSchema(), new File("users.avro"));dataFileWriter.append(user1);dataFileWriter.append(user2);dataFileWriter.append(user3);dataFileWriter.close();

这里,我们是序列化user到文件users.avro

反序列化

接下来,我们对序列化后的数据进行反序列化:

// Deserialize Users from diskDatumReader<User> userDatumReader = new SpecificDatumReader<User>(User.class);DataFileReader<User> dataFileReader = new DataFileReader<User>(new File("users.avro"), userDatumReader);User user = null;while (dataFileReader.hasNext()) {// Reuse user object by passing it to next(). This saves us from// allocating and garbage collecting many objects for files with// many items.user = dataFileReader.next(user);System.out.println(user);}

整个创建avro schema,代码生成,创建用户,序列化用户对象,反序列化及最后的输出结果,完整的代码可以组织为以下(在这里,我使用的是JUNIT):

import org.apache.avro.file.DataFileReader;import org.apache.avro.file.DataFileWriter;import org.apache.avro.io.DatumReader;import org.apache.avro.io.DatumWriter;import org.apache.avro.specific.SpecificDatumReader;import org.apache.avro.specific.SpecificDatumWriter;import org.junit.Test;import java.io.File;import java.io.IOException;/** * Created by yang on 12/23/16. */public class TestUser {    @Test    public void testCreateUserClass() throws IOException {        User user1 = new User();        user1.setName("Alyssa");        user1.setFavoriteNumber(256);        // Leave favorite color null        // Alternate constructor        User user2 = new User("Ben", 7, "red");        // Construct via builder        User user3 = User.newBuilder()                .setName("Charlie")                .setFavoriteColor("blue")                .setFavoriteNumber(null)                .build();        // Serialize user1, user2 and user3 to disk        DatumWriter<User> userDatumWriter = new SpecificDatumWriter<User>(User.class);        DataFileWriter<User> dataFileWriter = new DataFileWriter<User>(userDatumWriter);        dataFileWriter.create(user1.getSchema(), new File("users.avro"));        dataFileWriter.append(user1);        dataFileWriter.append(user2);        dataFileWriter.append(user3);        dataFileWriter.close();        // Deserialize Users from disk        DatumReader<User> userDatumReader = new SpecificDatumReader<User>(User.class);        DataFileReader<User> dataFileReader = new DataFileReader<User>(new File("users.avro"), userDatumReader);        User user = null;        while (dataFileReader.hasNext()) {            // Reuse user object by passing it to next(). This saves us from            // allocating and garbage collecting many objects for files with            // many items.            user = dataFileReader.next(user);            System.out.println(user);        }    }}

代码执行之后,可以发现,创建了文件users.avro。
这里写图片描述

输出结果为:

{"name": "Alyssa", "favorite_number": 256, "favorite_color": null}{"name": "Ben", "favorite_number": 7, "favorite_color": "red"}{"name": "Charlie", "favorite_number": null, "favorite_color": "blue"}

okay, 是不是很简单?

0 0