如何在MapReduce中使用Avro資料格式?

趙鈺瑩發表於2018-09-21

本文作為《Hadoop從入門到精通》大型專題的第三章後續,主要是對前一章中所提及的Protocol Buffers概念的補充以及如何在MapReduce中使用Avro資料格式。Avro改進了Protocol Buffers,因為其程式碼生成是可選的,並且以容器檔案格式嵌入模式,允許動態發現和資料互動。Avro有一種機制來處理使用通用資料型別的模式資料,這部分將會在之後的章節中呈現(往期文章可自行檢視文末連結)。

3.3.3 Protocol Buffers

谷歌開發人員發明了Protocol Buffers ,這是一種以緊湊而有效的方式在多種語言編寫的服務之間交換資料的方式。Protocol Buffers現在是谷歌事實上的資料格式,超過12,000個谷歌.proto檔案中定義了48,000多種不同的訊息型別。

自2008年以來,MapReduce的目標一直是新增對Protocol Buffers的本機支援。因此,那時的許多開發人員一直在尋找在Hadoop中使用Protocol Buffers的方法。之前有一種可用的方法,即在SequenceFiles中編碼Protocol Buffers,或者使用Elephant Bird或Avro,它們通過將自己包裝在自定義檔案格式中支援Protocol Buffers。但是,這些都不是最好的辦法,直到MapReduce完全支援在Hadoop中使用Protocol Buffers。

現在可以通過多種方式在Hadoop中使用Protocol Buffers:

  • 可以在SequenceFiles中以二進位制形式序列化Protocol Buffers物件;

  • Elephant Bird(https://github.com/kevinweil/elephant-bird)是一個來自Twitter的開源專案,支援自定義二進位制檔案格式的Protocol Buffers;

  • Parquet是一種柱狀檔案格式(之前的章節中曾介紹過),支援Protocol Buffers物件模型,並允許有效地將Protocol Buffers寫入和讀取為柱狀形式。

在這些選項中,Parquet是使用Protocol Buffers的最優方式,不僅允許使用Protocol Buffers本地工作,而且還開發了許多資料處理工具。

Thrift是另一種資料格式,與Protocol Buffers一樣,它沒有MapReduce支援。同樣,我們必須依賴其他工具來處理Hadoop中的Thrift資料。

3.3.4 Thrift

Facebook建立了Thrift以幫助實現高效的資料表示和傳輸。Facebook將Thrift用於許多應用程式,包括搜尋,日誌記錄及其廣告平臺。使用Protocol Buffers的三個選項也適用於Thrift,其中最棒的資料序列化格式就是Avro。

3.3.5 Avro

Doug Cutting建立了一個資料序列化和RPC庫Avro,以幫助改進MapReduce中的資料交換,互操作性和版本控制。Avro使用緊湊的二進位制資料格式,你可以選擇壓縮以提高序列化時間。雖然它具有模式的概念,類似於Protocol Buffers,但Avro改進了Protocol Buffers,因為它的程式碼生成是可選的,並且以容器檔案格式嵌入模式,允許動態發現和資料互動。

Avro檔案格式如圖3.11所示。模式被序列化為標題的一部分,這使得反序列化變得簡單,並且放開了使用者必須維護和訪問與之互動的Avro資料檔案之外的模式限制。每個資料塊包含許多Avro記錄,預設情況下為16 KB。

圖3.11  Avro容器檔案格式

資料序列化支援程式碼生成、版本控制和壓縮,並且與MapReduce具有高度整合。同樣重要的是模式演化,這就是Hadoop SequenceFiles沒有吸引力的原因,其不支援模式或任何形式的資料演變。

本節,你將瞭解Avro的架構和程式碼生成功能,讀取和編寫Avro容器檔案以及Avro與MapReduce整合的各種方法。最後,我還將關注Avro對Hive和Pig的支援。

首先,讓我們來看看Avro的架構和程式碼生成。

Avro的schema和程式碼生成

Avro具有通用資料和特定資料的概念:

  • 通用資料允許以較低階別處理資料,而無需瞭解schema細節。

  • 特定資料允許使用程式碼生成的Avro原語與Avro協同工作,該原語支援使用Avro資料的簡單且型別安全的方法。

該技術著眼於如何使用Avro中的特定資料。

問題

希望定義Avro模式並生成程式碼,以便可以使用Java中的Avro記錄。

解決方案

以JSON格式編寫schema,然後使用Avro工具生成豐富的API以與資料進行互動。

討論

可以通過使用程式碼生成的類或其泛類使用Avro。在本文中,我們將使用程式碼生成的類。

在程式碼生成方法中,一切都以模式開始。第一步是建立Avro模式來表示stock資料輸入:

Avro支援模式資料和RPC訊息的程式碼生成。要為模式生成Java程式碼,請使用Avro工具JAR,如下所示:

生成的程式碼將放入hip.ch3.avro.gen包中。既然已生成程式碼,那麼如何讀取和編寫Avro容器檔案?

程式碼3.5 從MapReduce外部編寫Avro檔案

如上所示,我們可以指定應該用於壓縮資料的壓縮編解碼器。該示例使用的是Snappy,它是讀寫速度最快的編解碼器。

以下程式碼演示瞭如何從輸入檔案的行封送Stock物件。如下所示,生成的Stock類是包含一組setter(和匹配的getter)的POJO:

如何讀剛剛寫進去的檔案:

繼續執行這個編寫器和讀者對:


Avro捆綁了一些工具,可以輕鬆檢查Avro檔案的內容。要以Avon格式檢視Avro檔案內容,只需執行以下命令:

以上是假定該檔案存在於本地檔案系統中。同樣,你可以使用以下命令獲取Avro檔案的JSON表示:


我們可以在沒有任何選項的情況下執行Avro工具來檢視可以使用的所有工具:

tojson工具的一個缺點是不支援在HDFS中讀取資料。因此,我將一個實用程式與AvroDump捆綁在一起,可以在HDFS中轉儲Avro資料的文字表示,我們可以用它來檢查Avro MapReduce作業輸出:

此實用程式支援多個檔案(需要以CSV分隔)和通配,因此可以使用萬用字元。以下示例顯示如何將生成Avro輸出的MapReduce作業內容轉儲到名為mr-output-dir的目錄中:

選擇在MapReduce中使用Avro的方法

Avro支援多種方式在MapReduce中使用Avro資料。本文列舉了處理資料的不同方法,並提供了有關哪種情況需要採用哪種方法的指導。

問題  

希望在MapReduce作業中使用Avro,但不清楚應該選擇哪種可用的整合選項。

解決方案

瞭解有關每個整合選項的詳細資訊,並選擇最適合的用例。

討論

可以通過三種方式在MapReduce中使用Avro:

  • Mixed-mode - 希望將Avro資料與作業中的非Avro資料混合時使用;

  • Record-based - 當以非Key/Value方式提供資料時很有用;

  • Key/value-based - 用於當資料必須適合特定模型時。

Mixed-mode(混合模式)

此用例適用於滿足以下任一條件的情況:

  • mapper輸入資料不是Avro格式;

  • 不希望使用Avro在mapper和Reducer之間發出中間資料;

  • 作業輸出資料不是Avro形式。

在任何情況下,Avro的mapper和reducer類都無法幫助你,因為它們的設計是假設Avro資料在MapReduce作業中端到端地流動。在這種情況下,我們將需要使用常規MapReduce的mapper和reducer類,並允許使用Avro資料方式構建作業。

Record-based

Avro資料是基於記錄的,與基於key/value的MapReduce相比,會導致阻抗不匹配。為了支援Avro基於記錄的root,Avro捆綁了一個不基於KV的mapper類,而只提供具有單個記錄的派生類。

Key/value-based

如果Avro資料內部遵循KV結構,則可以使用一些Avrosupplied mapper類來轉換Avro記錄並以key/value形式將其提供給mapper。使用此方法,只能使用字面上具有“key”和“value”元素的模式。

概要

選擇與Avro正確的整合級別是輸入和輸出函式,以及希望如何處理Avro內部的資料。本文檢查了與Avro整合的三種方法,以便可以為用例選擇正確的方法。

在MapReduce中混合Avro(Mixing Avro)和非Avro(non-Avro)資料

MapReduce中此級別的Avro整合適用於具有非Avro輸入並生成Avro輸出的情況,反之亦然。在這種情況下,Avro mapper和ruducer類不適用,本文將使用Avro混合模式。

問題

希望在MapReduce作業中以混合模式使用Avro,Avro捆綁的mapper和reducer類不支援。

解決方案

使用低階方法設定作業,並使用常規Hadoop mapper和reducer類通過MapReduce作業驅動Avro資料。

討論

Avro附帶了一些mapper和reducer類,可以將它們子類化以與Avro一起使用,它們在mapper和reducer交換Avro物件的情況下非常有用。但是,如果沒有要求在map和reduce任務之間傳遞Avro物件,最好直接使用Avro輸入和輸出格式類,正如以下程式碼所示,它產生了所有stock值的平均值。

我們先來看看作業配置。本文的主要任務是使用Avro格式消耗stock資料並生成stock平均值。為此,我們需要對兩個模式進行配置,並指定Avro輸入和輸出格式類:

接下來是Map類。整個Avro記錄作為map功能的輸入key提供,因為Avro支援記錄,而不是key/value對(雖然,之後我們也可以看到,Avro確實有辦法使用key/value向map提供資料,如果Avro架構具有稱為key和value的欄位)。從實施角度來看,map功能從stock記錄中提取必要的欄位併傳送到reducer,stock symbol 和stock price作為key/value對:

此處之所以使用較舊的MapReduce API(org.apache.hadoop.mapred API)是因為此處使用的AvroInputFormat和AvroOutputFormat類僅支援舊API。

最後,reduce函式總結所有的stock prices並輸出平均價格:

可以按如下方式執行MapReduce程式碼:

MapReduce作業正在從輸入中輸出不同的Avro物件(StockAvg),可以通過編寫程式碼(未列出)來轉儲Avro物件以驗證作業是否產生了期望的輸出:

總結

如果不希望以Avro形式輸出中間map,或者有非Avro輸入或輸出,則此技術非常有用。接下來我們將看一下如何在MapReduce中用Avronative方法處理資料。

在MapReduce中使用Avro記錄

與SequenceFile不同,Avro不是本機key/value序列化格式,因此可能需要一些工具才能使其與MapReduce一起使用。本文將檢查特定於Avro的mapper和reducer類,這些類公開了可用於輸入和輸出資料的基於記錄的介面。

問題

希望在MapReduce作業中使用Avro進行端到端資料傳輸,並且以面向記錄的形式與輸入和輸出資料互動。

解決方案

擴充套件AvroMapper和AvroReducer類以實現MapReduce作業。

討論

Avro附帶了兩個類,抽象出了MapReduce的key/value特性,並且暴露record-based的API。本文將實現與之前相同任務的MapReduce作業(計算每個stock symbol的平均價格),並在整個作業中使用Avro。首先,讓我們來看看Mapper類,它將擴充套件AvroMapper:

首先要注意的是,類定義了兩種型別,而不是MapReduce中的四種型別。AvroMapper抽象出mapper輸入和輸出key/value特徵,用單一型別替換每個特徵。

如果僅map作業,則定義的型別將是輸入和輸出型別。但是,如果正在執行完整的MapReduce作業,則需要使用Pair類,以便可以定義map輸出的key/value對。Pair類要求存在用於key和value部分的Avro模式,這就是使用Utf8類而不是直接Java字串的原因。

現在讓我們來看看AvroReducer實現, 需要定義三種型別:map輸出的key,value型別以及reducer輸出型別:

現在可以在驅動程式中將它們全部連線起來,本文將定義輸入和輸出型別以及所需的輸出壓縮(如果有):

在作業完成後檢查輸出:

總結

在整個MapReduce作業中以Avro形式儲存資料的情況下,此技術非常方便且不需要輸入或輸出資料基於key/value。

但是,如果確實需要基於key/value的資料,並且仍然希望使用緊湊型序列化大小和內建壓縮等該怎麼辦?

在MapReduce中使用AvroKey/Value對

MapReduce的原生資料模型是key/value對,Avro是基於記錄的,Avro沒有對key/value資料的本機支援,但Avro中存在一些類幫助建模Key/Value資料並在MapReduce中本地使用。

問題

希望將Avro用作資料格式和容器,但希望使用Avro中的Key/Value對進行資料建模,並將它們用作MapReduce中的本機Key/Value對。

解決方案

使用AvroKeyValue,AvroKey和AvroValue類來處理AvroKey/Value資料。

討論

Avro有一個AvroKeyValue類,封裝了兩個名為key和value的通用Avro記錄。AvroKeyValue用作輔助類,可以輕鬆讀取和寫入Key/Value資料,這些記錄的型別可以自定義。在這種技術中,我們將重複進行計算stock平均價格的MapReduce作業,但這次使用Avro的Key/Value框架。首先需要為工作生成輸入資料,在這種情況下,我們將stock symbol放在key中,Stock object 放在value中:

繼續生成HDFS檔案,其中包含Key/Value格式的stock資料:

如果想知道剛生成檔案的Avro架構定義,可以使用AvroDump實用程式顯示檔案內容:

對於MapReduce程式碼一次性定義mapper,reducer和driver:

AvroKey和AvroValue包裝器用於在mapper中提供輸入資料,以及在reducer中輸出資料。巧妙之處在於,Avro非常智慧,可以支援Hadoop Writable物件並自動將其轉換為Avro物件,這就是為什麼不需要告訴Avro輸出金鑰模式型別。

可以使用以下命令執行MapReduce作業:

同樣,可以使用AvroDump工具檢視輸出:

總結

這就是在MapReduce中處理資料的三種Avro方法。每種方法都適用於特定任務,可以選擇最適合需求的方法。

控制MapReduce中的排序方式

如果決定使用Avro資料作為中間map輸出,你可能想知道對分割槽、排序和分組工作的控制方式。

問題

希望控制MapReduce如何對reducer輸入進行排序。

解決方案

修改Avro架構以更改排序行為。

討論

如果將Avro物件用作mapper中的鍵輸出,則預設情況下會發生以下情況:

  • Avro物件中的所有欄位都用於分割槽,排序和分組。

  • 欄位按模式中的序號位置排序,這意味著如果有一個包含兩個元素的模式,則模式中的第一個元素首先用於排序,然後是第二個元素。

  • 在元素內,使用特定於型別的比較進行排序。如果要比較字串,則排序將是詞典,如果正在比較數字,則使用數字比較。

某些行為可以更改,以下是Stock架構的修改版本:

可以通過使用order屬性對其進行修飾並指定應使用降序來修改欄位的排序行為。或者,通過設定要忽略的順序來排除分割槽、排序和分組中的欄位。

請注意,這些是架構範圍的設定,並且沒有簡單方法來指定基於每個作業的自定義分割槽/排序/組設定,你可以繼續編寫自己的分割槽,排序和分組函式(就像對Writable一樣),但如果Avro有輔助函式來簡化此過程,那將非常有用。

Avro和Hive

直到最近,Hive專案才有內建的Avro支援,此技術介紹瞭如何在Hive中使用Avro資料。

問題

希望在Hive中使用Avro資料。

解決方案

使用Hive的Avro Serializer/Deserializer。

討論

Hive版本0.9.1和更新版本捆綁了Avro SerDe,這是Serializer/Deserializer的縮寫,允許Hive從表中讀取資料並將其寫回到表中。需要將本文捆綁的Avro架構複製到HDFS中,並建立一個包含Avro stock記錄示例的目錄:

接下來,啟動Hive控制檯併為剛剛建立的目錄建立外部Hive表,需要在HDFS中指定Avro架構位置,用HDFS使用者名稱替換YOUR-HDFS-USERNAME:

AvroSerDe實際支援三種方式定義Avro表模式,本文選擇最有可能在生產中使用的方法。

像任何Hive表一樣,我們可以查詢Hive來描述表的模式:

執行查詢以驗證一切是否正常。以下Hive查詢語言(HiveQL)將計算每個程式碼的stock記錄數:

如果想將資料寫入Avro支援的Hive表,以下示例顯示瞭如何複製stocks表中的記錄子集並將其插入新表中。此示例還重點介紹瞭如何使用Snappy壓縮編解碼器對新表進行寫入:

Avro和Pig

就像Hive一樣,Pig也有對Avro的內建支援。

問題

使用Pig讀取和寫入Avro資料。

解決方案

在Pig的Piggy Bank庫中使用AvroStorage類。

討論

Piggy Bank是一個包含Pig實用程式的有用集合庫,其中一個是可用於在HDFS中讀取和寫入Avro資料的AvroStorage類。 此處將讀入部分stock資料,執行簡單聚合並將過濾後的資料儲存回HDFS。

開始之前,我們將一些Avro的stock資料載入到HDFS目錄中:

在Pig-land中,第一步是註冊AvroStorage工作所需的JAR,可能需要搜尋與你正在使用的Hadoop發行版捆綁在一起的JAR特定位置。以下程式碼中的位置假定Apache Hadoop和Pig安裝在/usr/local下:

接下來,將stock載入到Pig中,然後使用LOAD和DESCRIBE運算子顯示架構詳細資訊:

請注意,不必提供有關Avro架構的詳細資訊,這是因為使用Avro容器格式具有嵌入在標頭中的架構。如果檔案沒有嵌入架構,AvroStorage仍然可以支援資料,但需要將Avro架構上傳到HDFS並使用“schema_file”選項。

驗證Avro和Pig是否正在協同工作,可以執行簡單聚合並計算每個stock的記錄數:

以下示例顯示瞭如何在Pig中輸出Avro資料,該示例根據輸入資料過濾Google stock,並將它們寫入HDFS的新輸出目錄。 這也展示瞭如何使用Snappy壓縮作業輸出:

Avro資料寫入HDFS時需要指定持久儲存資料的Avro架構,以上示例使用data選項告訴AvroStorage使用嵌入在輸入目錄下的檔案中的Avro架構。

與載入檔案一樣,還有其他方法可以告訴AvroStorage架構詳細資訊,這些方法記錄在Pig的wiki上。

總結

最後幾種技術已經證明了將Avro與MapReduce,Hive和Pig一起使用是多麼容易和直接。使用Avro儲存資料可提供許多有用的免費功能,例如版本控制支援,壓縮,可拆分性和程式碼生成。Avro與MapReduce,Hive,Pig以及Impala和Flume等眾多其他工具的強大整合意味著值得作為備選資料格式。

到目前為止,我們一直專注於基於行的檔案格式,這些格式並不總是佈局資料的最佳方式。在下一節,我們將瞭解柱狀儲存的優勢並檢視Parquet(柱狀儲存)例項。

相關文章:

1、《第一章:Hadoop生態系統及執行MapReduce任務介紹!》連結:    http://blog.itpub.net/31077337/viewspace-2213549/

2、《學習Hadoop生態第一步:Yarn基本原理和資源排程解析!》連結:    http://blog.itpub.net/31077337/viewspace-2213602/

3、《MapReduce如何作為Yarn應用程式執行?》連結:    http://blog.itpub.net/31077337/viewspace-2213676/

4、《Hadoop生態系統各元件與Yarn的相容性如何?》連結:    http://blog.itpub.net/31077337/viewspace-2213960/

5、《MapReduce資料序列化讀寫概念淺析!》連結:   http://blog.itpub.net/31077337/viewspace-2214151/

6、《MapReuce中對大資料處理最合適的資料格式是什麼?》連結:  http://blog.itpub.net/31077337/viewspace-2214325/

7、《如何在MapReduce中使用SequenceFile資料格式?》連結: http://blog.itpub.net/31077337/viewspace-2214505/

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31077337/viewspace-2214709/,如需轉載,請註明出處,否則將追究法律責任。

相關文章