基于Java實現Avro文件讀寫功能

      網友投稿 1049 2022-05-28

      Apache Avro是一個數據序列化系統。具有如下基本特性:

      豐富的數據結構。

      一種緊湊、快速的二進制數據格式。

      一個容器文件,用于存儲持久數據。

      遠程過程調用 (RPC)。

      與動態語言的簡單集成。 代碼生成不需要讀取或寫入數據文件,也不需要使用或實現 RPC 協議。 代碼生成作為一種可選的優化,只值得為靜態類型語言實現。

      模式(schema)

      Avro 依賴于模式。 讀取 Avro 數據時,寫入時使用的模式始終存在。 這允許在沒有每個值開銷的情況下寫入每個數據,從而使序列化既快速又小。 這也便于使用動態腳本語言,因為數據及其模式是完全自描述的。

      當 Avro 數據存儲在文件中時,它的模式也隨之存儲,以便以后任何程序都可以處理文件。 如果讀取數據的程序需要不同的模式,這很容易解決,因為兩種模式都存在。

      在 RPC 中使用 Avro 時,客戶端和服務器在連接握手中交換模式。 (這可以優化,使得對于大多數調用,實際上不傳輸模式。)由于客戶端和服務器都具有對方的完整模式,因此可以輕松解決相同命名字段之間的對應關系,如缺少字段,額外字段等 .

      基于Java實現Avro文件讀寫功能

      Avro 模式是用 JSON 定義的。 這有助于在已經具有 JSON 庫的語言中實現。

      與其他系統的比較

      Avro 提供類似于 Thrift、Protocol Buffers 等系統的功能。Avro 在以下基本方面與這些系統不同。

      動態類型:Avro 不需要生成代碼。 數據總是伴隨著一個模式,該模式允許在沒有代碼生成、靜態數據類型等的情況下完全處理該數據。這有助于構建通用數據處理系統和語言。

      未標記數據:由于在讀取數據時存在模式,因此需要用數據編碼的類型信息要少得多,從而導致更小的序列化大小。

      沒有手動分配的字段 ID:當架構更改時,處理數據時始終存在舊架構和新架構,因此可以使用字段名稱象征性地解決差異。

      Java客戶端實現

      以下代碼基于maven項目實現Java讀寫Avro

      首先在maven項目中添加下述依賴:

      org.apache.avro avro 1.11.0

      以及下述插件

      org.apache.avro avro-maven-plugin 1.11.0 generate-sources schema ${project.basedir}/src/main/avro/ ${project.basedir}/src/main/java/ org.apache.maven.plugins maven-compiler-plugin 1.8 1.8

      定義一個schema

      Avro 模式是使用 JSON 定義的。 模式由基本類型(null、boolean、int、long、float、double、bytes 和 string)和復雜類型(record、enum、array、map、union 和 fixed)組成。 您可以從規范中了解有關 Avro 模式和類型的更多信息,但現在讓我們從一個簡單的模式示例 user.avsc 開始:

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

      此模式定義了代表假設用戶的記錄。 (請注意,模式文件只能包含單個模式定義。)記錄定義至少必須包括其類型(“type”:“record”)、名稱(“name”:“User”)和字段, 在本例中為 name、favorite_number 和 favorite_color。 我們還定義了一個命名空間(“namespace”:“com.bigdatatoai.avro.generate”),它與 name 屬性一起定義了模式的“全名”(在本例中為 com.bigdatatoai.avro.User)。

      字段是通過對象數組定義的,每個對象都定義了一個名稱和類型(其他屬性是可選的,有關詳細信息,請參閱記錄規范)。 字段的類型屬性是另一個模式對象,它可以是基本類型或復雜類型。 例如,我們的 User 模式的 name 字段是原始類型字符串,而 favorite_number 和 favorite_color 字段都是聯合,由 JSON 數組表示。 unions 是一種復雜類型,可以是數組中列出的任何類型; 例如, favorite_number 可以是 int 或 null,本質上使它成為一個可選字段。

      使用Java代碼生成插件生成的User類進行序列化和反序列化

      已知我們在maven項目中添加了avro插件,那么我們便可以使用compile命令生成User類。

      下述以IDEA為例

      現在我們已經完成了代碼生成,讓我們創建一些用戶,將它們序列化為磁盤上的數據文件,然后讀回文件并反序列化用戶對象。

      創建User用戶

      // 新建user三種方式 // 方式1 User user1 = new User(); user1.setName("Alyssa"); user1.setFavoriteNumber(256); // 方式2 User user2 = new User("Ben", 7, "red"); // 方式3 User user3 = User.newBuilder() .setName("Charlie") .setFavoriteColor("blue") .setFavoriteNumber(null) .build();

      如本例所示,可以通過直接調用構造函數或使用構建器來創建 Avro 對象。 與構造函數不同,生成器將自動設置模式中指定的任何默認值。 此外,構建器會按設置驗證數據,而直接構造的對象在對象被序列化之前不會導致錯誤。 但是,直接使用構造函數通常會提供更好的性能,因為構造函數會在寫入數據結構之前創建數據結構的副本。

      請注意,我們沒有設置 user1 最喜歡的顏色。 由于該記錄的類型為 [“string”, “null”],我們可以將其設置為字符串或將其保留為 null; 它本質上是可選的。 同樣,我們將 user3 最喜歡的數字設置為 null(使用構建器需要設置所有字段,即使它們為 null)。

      將上述新建的User用戶序列化并保存到磁盤

      // 持久化數據到磁盤 DatumWriter userDatumWriter = new SpecificDatumWriter(User.class); DataFileWriter dataFileWriter = new DataFileWriter(userDatumWriter); dataFileWriter.create(user1.getSchema(), new File("users.avro")); dataFileWriter.append(user1); dataFileWriter.append(user2); dataFileWriter.append(user3); dataFileWriter.close();

      從磁盤讀取users.avro并反序列化輸出

      // 從User反序列化數據 DatumReader userDatumReader = new SpecificDatumReader(User.class); DataFileReader dataFileReader = new DataFileReader(new File("users.avro"), userDatumReader); User user = null; while (dataFileReader.hasNext()) { user = dataFileReader.next(user); System.out.println(user); }

      在不生成User類的情況下直接進行序列化和反序列化操作

      Avro 中的數據始終與其對應的模式一起存儲,這意味著無論我們是否提前知道模式,我們都可以隨時讀取序列化項目。 這允許我們在不生成代碼的情況下執行序列化和反序列化。

      讓我們回顧與上一節相同的示例,但不使用代碼生成:我們將創建一些用戶,將它們序列化為磁盤上的數據文件,然后讀回文件并反序列化用戶對象。

      使用user.avsc文件創建User用戶

      Schema schema = new Schema.Parser().parse(new File("java-example/src/main/avro/com/bigdatatoai/avro/user.avsc")); 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");

      由于我們不使用代碼生成,我們使用 GenericRecords 來表示用戶。 GenericRecord 使用模式來驗證我們是否只指定了有效字段。 如果我們嘗試設置一個不存在的字段(例如,user1.put(“favorite_animal”, “cat”)),我們將在運行程序時收到 AvroRuntimeException。

      請注意,我們沒有設置 user1 最喜歡的顏色。 由于該記錄的類型為 [“string”, “null”],我們可以將其設置為字符串或將其保留為 null; 它本質上是可選的。

      將上述新建的User持久化到磁盤

      File file = new File("users2.avro"); DatumWriter datumWriter = new GenericDatumWriter(schema); DataFileWriter dataFileWriter = new DataFileWriter(datumWriter); dataFileWriter.create(schema, file); dataFileWriter.append(user1); dataFileWriter.append(user2); dataFileWriter.close();

      從磁盤讀取users.avro并反序列化輸出

      DatumReader datumReader = new GenericDatumReader(schema); DataFileReader dataFileReader = new DataFileReader(file, datumReader); GenericRecord user = null; while (dataFileReader.hasNext()) { user = dataFileReader.next(user); System.out.println(user); }

      Java

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:【嵌入式Linux基礎入門】番外篇:Linux新系統快速配置指南
      下一篇:【90 天挑戰 HCIE Cloud】第 3 天 編輯器之神 VI
      相關文章
      亚洲精品国产首次亮相| 亚洲w码欧洲s码免费| 亚洲第一成年网站视频 | 亚洲精品国产福利片| 久久久久亚洲AV成人无码 | 国产AV旡码专区亚洲AV苍井空| 亚洲春黄在线观看| 亚洲国色天香视频| 亚洲激情视频图片| 亚洲午夜福利在线视频| 亚洲欧美成人一区二区三区| 亚洲精品无码你懂的| 亚洲精品蜜夜内射| www国产亚洲精品久久久日本| 国产精品亚洲综合一区在线观看| 日韩亚洲翔田千里在线| 亚洲国产精品日韩专区AV| 亚洲日本在线观看视频| 国产亚洲精品免费视频播放| 国产日产亚洲系列| 亚洲国产成人一区二区三区| 亚洲丁香色婷婷综合欲色啪| 久久丫精品国产亚洲av不卡| 亚洲欧洲久久精品| 中文字幕在线日亚洲9| 亚洲AV无码一区二区一二区| 亚洲av无码成人精品区在线播放 | 亚洲电影免费在线观看| 亚洲精品午夜视频| 国产成人亚洲综合网站不卡| 亚洲国产成人精品无码区二本 | 亚洲色图校园春色| 久久亚洲国产成人影院| 亚洲av无码有乱码在线观看| 亚洲熟伦熟女新五十路熟妇| 亚洲码国产精品高潮在线| 亚洲国产精品不卡在线电影| 亚洲国产电影在线观看| 亚洲乱色伦图片区小说| 亚洲国产高清在线一区二区三区| 国产aⅴ无码专区亚洲av麻豆 |