如何在MapReduce中使用SequenceFile數據格式?
本文作為《Hadoop從入門到精通》大型專題的第三章第三節,主要介紹如何在MapReduce中使用SequenceFile數據格式。我們在上一篇文章中提到了許多可與MapReduce大數據處理匹配的數據格式,本節將首先介紹SequenceFile數據格式。(往期文章可自行查看文末鏈接)
3.3.2 SequenceFile
因為SequenceFile是為與MapReduce一起使用而創建的,所以這種格式可以說是與MapReduce、Pig和Hive一起提供最高級別集成支持的數據格式。SequenceFile是一種可拆分的二進位文件格式,以Key/value形式存儲數據。所有SequenceFiles共享相同的頭格式,如圖3.8所示。
圖3.8 SequenceFile頭格式
SequenceFiles有三種類型,根據應用壓縮的方式而有所不同,每種類型都有自己對應的Writer類。
Uncompressed
Uncompressed SequenceFiles是使用SequenceFile.Writer類編寫的,其對比壓縮格式並沒有任何優勢,因為壓縮通常會減少存儲佔用空間,並且對讀取和寫入更有效,如圖3.9所示。
Record-compressed
Record-compressed SequenceFiles是使用SequenceFile.RecordCompressWriter類編寫的。記錄添加到SequenceFile後會立即被壓縮並寫入該文件。這種方法的缺點是與塊壓縮相比,壓縮比略有不同。該文件格式與uncompressed SequenceFiles基本相同,如圖3.9所示。
圖3.9 record-compressed和uncompressed SequenceFiles的
Block-compressed(塊壓縮)
Block-compressed SequenceFiles是使用SequenceFile.BlockCompressWriter類編寫的。默認情況下,塊大小與HDFS塊大小相同,但可以覆蓋它,這種壓縮的優勢在於壓縮程度更容易達到理想狀態。整個塊被壓縮,而不是在記錄級別壓縮。直到達到塊大小才寫入數據,此時整個塊被壓縮,從而產生良好的整體壓縮狀態。如圖3.10所示。
你只需要一個Reader類(SequenceFile.Reader)讀取所有三種類型的SequenceFiles。甚至Writer也是抽象的,因為你可以調用SequenceFile.createWriter決定首選格式,並且返回一個基類,無論如何壓縮都可以用於寫入。
圖3.10 塊壓縮的SequenceFile格式
SequenceFiles具有可插入的序列化框架,寫入的key和value必須具有相關的org.apache.hadoop.io.serializer.Serializer和Deserializer,用於編組和解組。Hadoop附帶了四個序列化程序:Avro,Java,Tether(用於TetherData類中包含的二進位數據)和Writable(默認序列化程序)。
自定義SequenceFile序列化
如果希望SequenceFile包含可序列化對象,則需要實現自己的Serializer並註冊,可以通過更新core-site.xml並將自定義序列化實現的類名追加到io.serializations屬性來註冊。
SequenceFiles是可拆分的,因為對於 record-based文件而言,每個文件大約每6 KiB(1 kibibyte = 1024位元組)就會寫入一個同步標記,並且在每個塊之前寫入基於塊的文件。
現在讓我們看一下如何在MapReduce中使用SequenceFiles。
如何使用SequenceFiles?
當必須支持複雜類型數據時,使用MapReduce中的文本會變得很棘手,這些數據可能包括nonscalar的數據類型,如列表或詞典。此外,如果MapReduce的數據位置屬性很重要,那麼大型壓縮文本文件需要一些額外的考慮,但使用SequenceFile等文件格式可以克服這些挑戰。
問題
希望在MapReduce中使用結構化文件格式,可以使用該格式模擬複雜數據結構,並且支持壓縮和可拆分輸入。
解決方案
該技術著眼於如何從獨立應用程序和MapReduce中使用SequenceFile文件格式。
討論
SequenceFile格式提供與MapReduce等工具的高度集成,還可以對複雜數據結構進行建模。我們將研究如何讀取和編寫SequenceFiles,以及如何將它們與MapReduce、Pig和Hive一起使用。
我們將使用此技術的庫存數據。與SequenceFiles一起使用的最常見序列化方法是Writable,因此需要創建一個Writable來表示stock數據。編寫複雜Writable的關鍵元素是擴展Writable類並定義序列化和反序列化方法,如下所示。
列表3.3 表示stock price的寫實現
現在有了Writable,你需要編寫一些代碼來創建SequenceFile。我們可以從本地磁碟讀取stocks文件,創建StockWritable,並使用stock price作為密鑰將其寫入SequenceFile:
如何讀並創建寫文件?
現在需要通過寫和讀文件來證明其工作原理:
我們將如何在MapReduce中處理此SequenceFile?幸運的是,SequenceFileInputFormat和SequenceFileOutputFormat都與MapReduce很好地集成。因為Writable是MapReduce中的本機數據格式,所以使用帶有MapReduce的SequenceFiles是完全透明的。以下代碼顯示了帶有mapper和reducer的MapReduce作業:
現在,你可以針對先前創建的stocks SequenceFile運行MapReduce作業:
因為我們所做的只是回顯輸出的輸入,所以應該在兩個文件中看到相同的內容,可以通過讀取作業輸出文件來確保這種情況。至於如何驗證輸出是否為SequenceFile,很簡單,SequenceFile輸出的前三個位元組是SEQ,然後是包含SequenceFile版本的第四個位元組,然後是key和value類:
現在嘗試使用之前編寫的SequenceFile讀取器代碼將其轉儲到標準輸出:
因為SequenceFiles是基於key/value的,並且SequenceFiles的默認序列化數據格式是可寫的,所以使用SequenceFiles對於map和reduce完全透明。我們通過使用MapReduce的內置map和 reduce類並使用SequenceFile作為輸入證明了這一點。 我們唯一需要做的就是告訴MapReduce使用特定於SequenceFile的輸入和輸出格式類,這些類都構建在MapReduce中。
在Pig中讀取SequenceFiles
如果自己編寫Writable,可以使用非MapReduce工具(如Pig)創建更多工作。Pig適用於Hadoop的內置scalar Writable,如Text和IntWritable,但不支持自定義Writable。 你需要編寫自己的LoadFunc來支持StockPriceWritable。這適用於MapReduce,但Pig的SequenceFileLoader不能與自定義Writable一起使用,這意味著需要編寫自己的Pig載入程序來處理文件。LoadFunc for Pig非常簡單,如下所示:
列表3.4 一個Pig載入器函數,將StockPriceWritable轉換為Pig元組
現在可以嘗試在Pig中載入和轉儲stock SequenceFile:
Hive
Hive包含對SequenceFiles的內置支持,但它有兩個限制。首先,它忽略了每條記錄的關鍵部分。其次,開箱即用只適用於可寫的SequenceFile值,通過執行toString()將值轉換為Text形式來支持。
如果有自定義Writable,則必須編寫一個Hive SerDe,它將Writable反序列化為Hive可以理解的形式。生成的DDL語句如下:
總結
SequenceFiles非常有用,因為其解決了MapReduce最具挑戰性的問題——其本身可拆分且具有內置壓縮支持,這使得它對用戶完全透明。當然,它們也可用作其他文件格式的容器,如果這些格式不能集成到MapReduce中。SequenceFiles比較棘手的是缺乏多語言支持,限制了與數據互操作的工具範圍。但是,如果數據大部分保留在HDFS中並使用MapReduce(或Hive / Pig)進行處理,那麼SequenceFiles可能是你所需要的。
SequenceFiles的另一個挑戰是在使用Writable時缺乏模式演變 - 對Writable進行更改不會向後或向前兼容,除非將其構建到實現中。這可以通過使用Protocol Buffers作為key/value類型來解決。
該技術研究了如何將SequenceFiles與Writable一起使用,SequenceFile知道如何在其文件格式內進行編碼和解碼。如何通過SequenceFiles使用Writables以外的數據?
使用SequenceFiles編碼Protocol Buffers
Writable是SequenceFiles中的一等公民,並且API具有讀取和寫入Writable實例的特定方法,這並不意味著SequenceFiles僅限於使用Writables。事實上,只要有一個插入Hadoop序列化框架的數據類型的序列化實現,就可以使用任何數據類型。
Protocol Buffers是Google開源的複雜數據格式,提供了模式演變和高效數據編碼功能。 (有關Protocol Buffers的更多詳細信息,請參見之後的第3.3.3節)。在這種技術中,我們可以實現Protocol Buffers序列化,並了解如何在MapReduce中使用本機Protocol Buffers對象。
問題
希望在MapReduce中使用Protocol Buffers數據。
解決方案
編寫Protocol Buffers序列化程序,使能夠在SequenceFiles中編碼Protocol Buffers序列化數據。
討論
出於性能考慮,Hadoop使用自己的框架來序列化和反序列化數據。此框架的一個示例用法是將map輸出作為shuffle階段的一部分寫入磁碟,所有map輸出必須具有相應的Hadoop序列化類,該類知道如何讀取和寫入數據流。Writable是MapReduce中最常用的數據類型,有一個WritableSerialization類且使用Writable介面上的readFields和writeFields方法執行序列化。
SequenceFiles使用相同的序列化框架來序列化和反序列化其key/value記錄中的數據,這就是SequenceFiles開箱即用支持Writable的原因。因此,將數據類型編碼到SequenceFile只是編寫自己的Hadoop序列化實例問題。
Protocol Buffers與SequenceFiles一起使用的第一步是編寫自己的序列化類。每個序列化類都必須支持序列化和反序列化,所以從序列化器開始,其作用是將記錄寫到輸出流。
以下代碼使用MessageLite類作為type,是所有生成的Protocol Buffers類的超類。MessageLite介面提供了將Protocol Buffers寫入輸出流並從輸入流中讀取它們的方法,如下面的代碼所示:
接下來是解串器,其作用是從輸入流填充Protocol Buffers對象。與序列化相比,Protocol Buffers對象只能通過其 builder類進行構建:
現在,我們需要配置Hadoop序列化框架以使用新的序列化程序。這是通過將新的序列化程序附加到io.serializations屬性來完成的。編寫輔助方法通常可以使客戶端變得容易。以下示例顯示了與Hadoop 2捆綁在一起的標準序列化程序,它們附加了剛剛創建的序列化類。這裡沒有顯示ProtobufSerialization的源代碼,它只是返回ProtobufSerializer和ProtobufDeserializer實例:
接下來,需要生成一個新的Protocol Buffers編碼的SequenceFile。這裡的關鍵項是在使用SequenceFile writer之前調用register方法(如前面的代碼所示):
關於MapReduce代碼,新的序列化程序的優點是map和reduce類可以直接使用Protocol Buffers對象。同樣,關鍵在於如何配置作業以使Protocol Buffers序列化程序可用。在下面的示例中,使用標識函數來演示如何在SequenceFiles中編碼:
現在,你可以編寫具有Protocol Buffers值的SequenceFile,對該數據運行標識MapReduce作業,然後轉儲作業輸出內容:
以上是本章節的所有內容,在下一章節,我們將研究可以將Protocol Buffers集成到MapReduce中的其他方法。
![](https://pic.pimg.tw/zzuyanan/1488615166-1259157397.png)
![](https://pic.pimg.tw/zzuyanan/1482887990-2595557020.jpg)
※真假路由「易混淆」 斐訊K系列「做典範」
※回顧&展望:殺毒軟體的「前世今生」
TAG:IT168企業級 |