定期分享源碼,總結相關知識點,哈哈哈,來關注啊
概括
Hadoop 的 HDFS 和 MapReduce 子框架主要是針對大數據文件來設計的,在小文件的處理上不但效率低下,而且十分消耗內存資源(每一個小文件佔用一個 Block,每一個 block 的元數據都存儲在 namenode 的內存裏)。解決辦法通常是選擇一個容器,將這些小文件組織起來統一存儲。HDFS 提供了兩種類型的容器,分別是 SequenceFile 和 MapFile。
關於SequenceFile
概述
SequenceFile 是 Hadoop 的一個重要數據文件類型,它提供key-value的存儲,但與傳統key-value存儲(比如hash表)不同的是,它是appendonly的,於是你不能對已存在的key進行寫操作。
解決問題
該文件格式通常被用來解決hadoop中的小文件問題,相當於一個容器,把這些小文件組織起來統一存儲。
壓縮格式
SeqeunceFile支持兩種格式的數據壓縮,分別是:record compression 和 block compression。
存儲結構
在存儲結構上,SequenceFile 主要由一個 Header 後跟多條 Record 組成。
Header 主要包含了 Key classname,Value classname,存儲壓縮算法,用戶自定義元數據等信息,此外,還包含了一些同步標識,用於快速定位到記錄的邊界。
每條 Record 以鍵值對的方式進行存儲,用來表示它的字符數組可依次解析成:記錄的長度、Key 的長度、Key 值和 Value 值,並且 Value 值的結構取決於該記錄是否被壓縮
操作方式
SequenceFile 可通過如下 API 來完成新記錄的添加操作:
fileWriter.append(key,value)
可以看到,每條記錄以鍵值對的方式進行組織,但前提是 Key 和 Value 需具備序列化和反序列化的功能
SequenceFile 讀/寫操作
1. Configuration conf=new Configuration();
2. FileSystem fs=FileSystem.get(conf);
3. Path seqFile=new Path("seqTestFile.seq");
4. //Reader 內部類用於文件的讀取操作
5. SequenceFile.Reader reader=new SequenceFile.Reader(fs,seqFile,conf);
6. //Writer 內部類用於文件的寫操作,假設 Key 和 Value 都爲 Text 類型
7. SequenceFile.Writer writer=new SequenceFile.Writer(fs,conf,seqFile,Text.class,Text.class);
8. //通過 writer 向文檔中寫入記錄
9. writer.append(new Text("key"),new Text("value"));
10. IOUtils.closeStream(writer);//關閉 write 流
11. //通過 reader 從文檔中讀取記錄
12. Text key=new Text();
13. Text value=new Text();
14. while(reader.next(key,value)){
15. System.out.println(key);
16. System.out.println(value);
17. }
18. IOUtils.closeStream(reader);//關閉 read 流
關於MapFile
介紹及組成
MapFile 是排序後的 SequenceFile,通過觀察其目錄結構可以看到 MapFile 由兩部分組成,分別是 data 和 index。
index 作爲文件的數據索引,主要記錄了每個 Record 的 key 值,以及該 Record 在文件中的偏移位置。在 MapFile 被訪問的時候,索引文件會被加載到內存,通過索引映射關係可迅速定位到指定 Record 所在文件位置,因此,相對SequenceFile 而言,MapFile 的檢索效率是高效的,缺點是會消耗一部分內存來存儲 index 數據。
與SequenceFile不同的是
MapFile 的 KeyClass 一定要實現 WritableComparable 接口,即 Key 值是可比較的。
MapFile 讀寫操作
. Configuration conf=new Configuration();
2. FileSystem fs=FileSystem.get(conf);
3. Path mapFile=new Path("mapFile.map");
4. //Reader 內部類用於文件的讀取操作
5. MapFile.Reader reader=new MapFile.Reader(fs,mapFile.toString(),conf);
6. //Writer 內部類用於文件的寫操作,假設 Key 和 Value 都爲 Text 類型
7. MapFile.Writer writer=new MapFile.Writer(conf,fs,mapFile.toString(),Text.class,Text.class);
8. //通過 writer 向文檔中寫入記錄
9. writer.append(new Text("key"),new Text("value"));
10. IOUtils.closeStream(writer);//關閉 write 流
11. //通過 reader 從文檔中讀取記錄
12. Text key=new Text();
13. Text value=new Text();
14. while(reader.next(key,value)){
15. System.out.println(key);
16. System.out.println(key);
17. }
18. IOUtils.closeStream(reader);//關閉 read 流
SequenceFile和MapFile的侷限性
1.文件不支持複寫操作,不能向已存在的 SequenceFile(MapFile)追加存儲記錄
2.當 write 流不關閉的時候,沒有辦法構造 read 流。也就是在執行文件寫操作的時候,該文件是不可讀取的
關於SquenceFile生成RDD與TextFile生成RDD的區別
因爲SequenceFile的分區和上一篇講的TextFile的分區非常類型,只有個別不一樣的地方
@Override
protected FileStatus[] listStatus(JobConf job) throws IOException {
FileStatus[] files = super.listStatus(job);
for (int i = 0; i < files.length; i++) {
FileStatus file = files[i];
if (file.isDirectory()) { // it's a MapFile
Path dataFile = new Path(file.getPath(), MapFile.DATA_FILE_NAME);
FileSystem fs = file.getPath().getFileSystem(job);
// use the data file
files[i] = fs.getFileStatus(dataFile);
}
}
return files;
}