使用Apache Avro序列化、反序列化數據

本文通過兩個示例介紹如何使用avro序列化,反序列數據(Avro的簡介請參閱:https://blog.csdn.net/Mathieu66/article/details/105601509)。

我們知道使用Avro序列化、反序列化數據時需要使用數據的schema(schema是對數據結構的描述)。使用時,可以生成schema描述的java類,再基於生成的java類做數據處理,也可以不生成,使用Avro提供的通用數據結構GenericRecord。生成java類的方法官網提供了兩種:

1)使用avro提供的工具包手動生成(這與使用Protocol Buffer類似),這種方式略顯麻煩,這裏不做介紹。

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

2)使用maven插件,編譯後自動生成。

這裏我們先介紹不生成schema Java類的Avro列化反序列化使用方式,之後再介紹需要生成schema Java類的方式。

我們的demo很簡單,使用json描述User的基本信息,實例化User,序列化,寫出到文件,然後再反序列化將其讀出打印在控制檯。

首先,我們要定義schema信息User.avsc,位置可自定義(我的在test-avro/src/main/avro目錄下,test-avro是項目名)。

namespace是生成schema Java類時使用的。比如這裏的User.java將會生成在mvn插件定義的outputDirectory下的com.mathieu.avro路徑下。

{"namespace": "com.mathieu.avro",
 "type": "record",
 "name": "User",
 "fields": [
     {"name": "name", "type": "string"},
     {"name": "favorite_number",  "type": ["int", "null"]},
     {"name": "favorite_color", "type": ["string", "null"]}
 ]
}

兩種方式均需要引入Avro依賴包

<dependency>
  <groupId>org.apache.avro</groupId>
  <artifactId>avro</artifactId>
  <version>1.9.2</version>
</dependency>

下面開始實操:

1. 不生成schema Java類的方式

package com.mathieu.avro;

import org.apache.avro.Schema;
import org.apache.avro.file.DataFileReader;
import org.apache.avro.file.DataFileWriter;
import org.apache.avro.generic.GenericData;
import org.apache.avro.generic.GenericDatumReader;
import org.apache.avro.generic.GenericDatumWriter;
import org.apache.avro.generic.GenericRecord;
import org.apache.avro.io.DatumReader;
import org.apache.avro.io.DatumWriter;

import java.io.File;
import java.io.IOException;

/**
 * 不生成Schema代碼的Avro示例.
 */
public class AvroDemoWithoutCodeGeneration {
  public static void main(String[] args) throws IOException {
    // 讀取Schema
    Schema schema = new Schema.Parser().parse(new File("test-avro/src/main/avro/User.avsc"));

    // 使用schema創建用戶對象.
    GenericRecord user1 = new GenericData.Record(schema);
    user1.put("name", "Alyssa");
    user1.put("favorite_number", 256);

    GenericRecord user2 = new GenericData.Record(schema);
    user2.put("name", "Ben");
    user2.put("favorite_number", 7);
    user2.put("favorite_color", "red");

    // 序列化並寫出到磁盤
    File file = new File("test-avro/src/main/resources/users.avro");
    DatumWriter<GenericRecord> datumWriter = new GenericDatumWriter<GenericRecord>(schema);
    DataFileWriter<GenericRecord> dataFileWriter = new DataFileWriter<GenericRecord>(datumWriter);
    dataFileWriter.create(schema, file);
    dataFileWriter.append(user1);
    dataFileWriter.append(user2);
    dataFileWriter.close();

    // 從磁盤反序列化,打印在控制檯
    DatumReader<GenericRecord> datumReader = new GenericDatumReader<GenericRecord>(schema);
    DataFileReader<GenericRecord> dataFileReader = new DataFileReader<GenericRecord>(file, datumReader);
    GenericRecord user = null;
    while (dataFileReader.hasNext()) {
      user = dataFileReader.next(user);
      System.out.println(user);
    }
    // 運行結果:
    // {"name": "Alyssa", "favorite_number": 256, "favorite_color": null}
    // {"name": "Ben", "favorite_number": 7, "favorite_color": "red"}
  }
}

2.生成Schema Java類的方式

需要添加maven插件

      <plugin>
        <groupId>org.apache.avro</groupId>
        <artifactId>avro-maven-plugin</artifactId>
        <version>1.9.2</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.8</source>
          <target>1.8</target>
        </configuration>
      </plugin>

注意:

${project.basedir}/src/main/avro  -> User.avsc文件所在路徑

${project.basedir}/src/main/java + namespace -> User.java文件坐在路徑

在執行 mvn compile 生成User.java文件(第一種方式不會生成User.java文件)。

使用User.java進行數據序列化反序列化的代碼:

package com.mathieu.avro;

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 java.io.File;
import java.io.IOException;

/**
 * Avro示例(使用CodeGeneration).
 *
 */
public class AvroDemoWithCodeGeneration {
  public static void main(String[] args) throws IOException {
    // 使用三種不同的方式實例化三個user
    User user1 = new User();
    user1.setName("Alyssa");
    user1.setFavoriteNumber(256);

    User user2 = new User("Ben", 7, "red");

    User user3 = User.newBuilder()
        .setName("Charlie")
        .setFavoriteColor("blue")
        .setFavoriteNumber(null)
        .build();

    // 序列化user1, user2 and user3 到磁盤
    DatumWriter<User> userDatumWriter = new SpecificDatumWriter<User>(User.class);
    DataFileWriter<User> dataFileWriter = new DataFileWriter<User>(userDatumWriter);
    File file = new File("test-avro/src/main/resources/users.avro");
    dataFileWriter.create(user1.getSchema(), file);
    dataFileWriter.append(user1);
    dataFileWriter.append(user2);
    dataFileWriter.append(user3);
    dataFileWriter.close();

    // 從磁盤反序列化
    DatumReader<User> userDatumReader = new SpecificDatumReader<User>(User.class);
    DataFileReader<User> dataFileReader = new DataFileReader<User>(file, userDatumReader);
    User user = null;
    while (dataFileReader.hasNext()) {
      user = dataFileReader.next(user);
      System.out.println(user);
    }

    // 運行結果
/*  {"name": "Alyssa", "favorite_number": 256, "favorite_color": null}
    {"name": "Ben", "favorite_number": 7, "favorite_color": "red"}
    {"name": "Charlie", "favorite_number": null, "favorite_color": "blue"}*/

  }
}

源碼地址:https://gitee.com/mathieu/test-suite.git

參考:http://avro.apache.org/docs/current/gettingstartedjava.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章