http://www.iteblog.com/archives/1008
Avro有C, C++, C#, Java, PHP, Python, and Ruby等语言的实现,本文只简单介绍如何在Java中使用Avro进行数据的序列化(data serialization)。本文使用的是Avro 1.7.4,这是写这篇文章时最新版的Avro。读完本文,你将会学到如何使用Avro编译模式、如果用Avro序列化和反序列化数据。
一、准备项目需要的jar包
文本的例子需要用到的Jar包有这四个:avro-1.7.1.jar、avro-tools-1.7.4.jar、 jackson-core-asl-1.8.8.jar、jackson-mapper-asl-1.8.8.jar,请先将这几个jar包下载好,并存放在一个地方(本文是存放在$HIVE_HOME/lib目录中)。如果你是用Maven,你可以在你项目的pom.xml文件中加入以下依赖:
02 | <groupId>org.apache.avro</groupId> |
03 | <artifactId>avro</artifactId> |
04 | <version> 1.7 . 4 </version> |
08 | <groupId>org.apache.avro</groupId> |
09 | <artifactId>avro-maven-plugin</artifactId> |
10 | <version> 1.7 . 4 </version> |
13 | <phase>generate-sources</phase> |
18 | <sourceDirectory>${project.basedir}/src/main/avro/</sourceDirectory> |
19 | <outputDirectory>${project.basedir}/src/main/java/</outputDirectory> |
25 | <groupId>org.apache.maven.plugins</groupId> |
26 | <artifactId>maven-compiler-plugin</artifactId> |
当然,如果你需要,你也可以在Avro源码中进行编译,获取avro-1.7.1.jar和avro-tools-1.7.4.jar。关于如何编译avro已经超出本文的范围。
二、定义模式(Schema)
在avro中,它是用Json格式来定义模式的。模式可以由基础类型(null, boolean, int, long, float, double, bytes, and string)和复制类型(record, enum, array, map, union, and fixed)的数据组成。本文只是定义了一个简单的模式user.avsc:
02 | "namespace" : "example.avro" , |
11 | "name" : "favorite_number" , |
18 | "name" : "favorite_color" , |
上面的模式是定义了一个用户的记录,在模式定义中,必须包含它的类型("type": "record")、一个名字("name": "User")以及fields。在本例中fields包括了name, favorite_number和favorite_color,上面的模式我们还定义了一个命名空间 ("namespace": "example.avro"),namespace可以名字一起使用,从而组成模式的全名(本例为example.avro.User)。
三、编译模式
Avro可以允许我们根据模式的定义而生成相应的类,一旦我们定义好相关的类,我们程序中就不需要直接使用模式了。可以用avro-tools jar包来生成代码,语法如下:
1 | java -jar $HIVE_HOME/lib/avro-tools- 1.7 . 4 .jar |
3 | <schema file> <destination> |
所以,在本例中我们可以这样来使用
1 | java -jar $HIVE_HOME/lib/avro-tools- 1.7 . 4 .jar compile schema user.avsc . |
这时候,在当前目录下会生成example/avro/User.java类,细心的读者可能会发现example/avro不就是模式定义中的namespace么?的确是的。
如果你直接用Avro Maven plugin,那么你就不需要手动的编译模式,因为Avro Maven plugin会自动给你编译好。
现在我们已经生成好了一个User.java类,我们就可以用代码生成User,并用avro将它序列化存放到本地文件中,最后我们再将其反序列化。
四、如何使用
我们可以用下面的代码生成几个User:
01 | User user1 = new User(); |
02 | user1.setName( "Alyssa" ); |
03 | user1.setFavoriteNumber( 256 ); |
07 | User user2 = new User( "Ben" , 7 , "red" ); |
10 | User user3 = User.newBuilder() |
12 | .setFavoriteColor( "blue" ) |
13 | .setFavoriteNumber( null ) |
从上面的列子中,我们可以看出,我们可以调用User的构造函数或者是builder来获取一个User实例。下面对上述的几个User进行序列化操作,并将序列化的数据存放到users.avro文件中:
2 | File file = new File( "users.avro" ); |
3 | DatumWriter<User> userDatumWriter = new SpecificDatumWriter<User>(User. class ); |
4 | DataFileWriter<User> dataFileWriter = new DataFileWriter<User>(userDatumWriter); |
5 | dataFileWriter.create(user1.getSchema(), new File( "users.avro" )); |
6 | dataFileWriter.append(user1); |
7 | dataFileWriter.append(user2); |
8 | dataFileWriter.append(user3); |
9 | dataFileWriter.close(); |
运行完这个代码之后,将会在磁盘产生users.avro文件,里面是用avro序列化user的数据。我们可以对其进行反序列化,获取到原来的数据:
02 | DatumReader<User> userDatumReader = new SpecificDatumReader<User>(User. class ); |
03 | DataFileReader<User> dataFileReader = |
04 | new DataFileReader<User>(file, userDatumReader); |
06 | while (dataFileReader.hasNext()) { |
10 | user = dataFileReader.next(user); |
11 | System.out.println(user); |
这段代码将会产生成以下的结果:
1 | { "name" : "Alyssa" , "favorite_number" : 256 , "favorite_color" : null } |
2 | { "name" : "Ben" , "favorite_number" : 7 , "favorite_color" : "red" } |
3 | { "name" : "Charlie" , "favorite_number" : null , "favorite_color" : "blue" } |
五、一个完整的例子
03 | import org.apache.avro.io.DatumWriter; |
04 | import org.apache.avro.io.DatumReader; |
05 | import org.apache.avro.specific.SpecificDatumWriter; |
06 | import org.apache.avro.specific.SpecificDatumReader; |
07 | import org.apache.avro.file.DataFileWriter; |
08 | import org.apache.avro.file.DataFileReader; |
09 | import example.avro.User; |
12 | public static void main(String args[]) { |
13 | User user1 = new User(); |
14 | user1.setName( "Alyssa" ); |
15 | user1.setFavoriteNumber( 256 ); |
19 | User user2 = new User( "Ben" , 7 , "red" ); |
22 | User user3 = User.newBuilder() |
24 | .setFavoriteColor( "blue" ) |
25 | .setFavoriteNumber( null ) |
28 | File file = new File( "users.avro" ); |
29 | DatumWriter<User> userDatumWriter = |
30 | new SpecificDatumWriter<User>(User. class ); |
31 | DataFileWriter<User> dataFileWriter = |
32 | new DataFileWriter<User>(userDatumWriter); |
34 | dataFileWriter.create(user1.getSchema(), new File( "users.avro" )); |
35 | dataFileWriter.append(user1); |
36 | dataFileWriter.append(user2); |
37 | dataFileWriter.append(user3); |
38 | dataFileWriter.close(); |
39 | } catch (IOException e) { |
42 | DatumReader<User> userDatumReader = |
43 | new SpecificDatumReader<User>(User. class ); |
44 | DataFileReader<User> dataFileReader = null ; |
46 | dataFileReader = new DataFileReader<User>(file, userDatumReader); |
47 | } catch (IOException e) { |
51 | while (dataFileReader.hasNext()) { |
55 | user = dataFileReader.next(user); |
56 | System.out.println(user); |
58 | } catch (IOException e) { |
编译上述代码:
1 | javac -classpath /home/q/hive- 0.11 . 0 /lib/avro- 1.7 . 1 .jar |
2 | :/home/q/hive- 0.11 . 0 /lib/avro-tools- 1.7 . 4 .jar |
3 | :/home/q/hive- 0.11 . 0 /lib/jackson-core-asl- 1.8 . 8 .jar |
4 | :/home/q/hive- 0.11 . 0 /lib/jackson-mapper-asl- 1.8 . 8 .jar |
5 | example/avro/User.java Test.java |
运行上述代码:
1 | java -classpath /home/q/hive- 0.11 . 0 /lib/avro- 1.7 . 1 .jar |
2 | :/home/q/hive- 0.11 . 0 /lib/avro-tools- 1.7 . 4 .jar |
3 | :/home/q/hive- 0.11 . 0 /lib/jackson-core-asl- 1.8 . 8 .jar |
4 | :/home/q/hive- 0.11 . 0 /lib/jackson-mapper-asl- 1.8 . 8 .jar:User.jar:. |
本博客文章除特别声明,全部都是原创!
尊重原创,转载请注明: 转载自过往记忆(http://www.iteblog.com/)
本文链接地址: 《Apache Avro使用入门指南》(http://www.iteblog.com/archives/1008)