Apache Avro 1.8.1 入門指南(Java)

在快速入門之前,我們先來了解一下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 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();

這裏,我們是序列化user到文件users.avro

反序列化

接下來,我們對序列化後的數據進行反序列化:

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

整個創建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, 是不是很簡單?

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