Hadoop InputFormat介紹
1 概述
我們在編寫MapReduce程序的時候,在設置輸入格式的時候,會調用如下代碼:
job.setInputFormatClass(KeyVakueTextInputFormat.class)
通過上面的代碼來保證輸入的文件是按照我們想要的格式被讀取,所有的輸入格式都繼承於InputFormat,這是一個抽象類,其子類有專門用於讀取普通文件的FileInputFormatt,用於讀取數據庫文件的DBInputFromat,用於讀取HBase的TableInputFormat等等。如下圖是InputFormat的圖譜。
2 InputFormat方法
從類圖中可以看出,InputFormat抽象類僅有兩個抽象方法:
public abstract List<InputSplit> getSplits(JobContext context)
public abstract RecordReader<K,V> createRecordReader(InputSplit split,TaskAttemptContext context)
getSplits()方法是邏輯上拆分作業的輸入文件集,然後將每個InputSplit分配給一個單獨的Mapper進行處理
注意:拆分是按輸入文件的邏輯分割,而輸入文件不會被物理分割成塊。每個切片都是一個<input-file-path,start,offset>
的元組,InputFormat並創建相應的RecordReader讀取這些切片。
createRecordReader()方法是爲給定的切片創建一個記錄閱讀器。在切片被使用之前先調用RecordReader.initialize(InputSplit, TaskAttemptContext)
方法。
通過InputFormat,MapReduce框架可以做到:
1. 驗證作業輸入的正確性
2. 將輸入的文件切割成邏輯分片(InputSplit),一個InputSplit將會分配給一個獨立的MapTask
3. 提供RecordReader實現,讀取InputSplit中的Kv對供Mapper使用。
不同的InputFormat會各自實現不同的文件讀取方法以及分片方式,每個輸入分片會被單獨的MapTask作爲數據源。下面將介紹InputSplit和RecordReader。
3 InputSplit介紹
MapTask的輸入是一個輸入切片,稱爲InputSplit。InputSplit也是一個抽象類,它在邏輯上包含給處理這個InputSplit的Mapper的所有KV對。不同類型的輸入格式對應不同類型的切片,下圖是InputSplit的類圖。
3.1 InputSplit方法
// 獲取切片大小,並且根據size對切片排序
public abstract long getLength()
// 獲取存儲該分片的數據所在的節點位置,其中的數據是本地的,位置信息不需要序列號
public abstract String[] getLocations()
// 獲取有關切片在那個節點上的信息,以及它是如何存儲在每個位置的
public SplitLocationInfo[] getLocationInfo()
4 RecordReader
RecorderReader將讀入到Map的數據拆分成KV對。RecorderReader也是一個抽象類。下面是RecordReader的類圖:
接下來看一下RecordReader的源代碼:
public abstract class RecordReader<KEYIN, VALUEIN> implements Closeable {
/**
* 由一個InputSplit初始化
*/
public abstract void initialize(InputSplit split,
TaskAttemptContext context
) throws IOException, InterruptedException;
/**
* 讀取分片下一個KV
*/
public abstract
boolean nextKeyValue() throws IOException, InterruptedException;
/**
* Get the current key
*/
public abstract
KEYIN getCurrentKey() throws IOException, InterruptedException;
/**
* Get the current value.
*/
public abstract
VALUEIN getCurrentValue() throws IOException, InterruptedException;
/**
* 跟蹤讀取分片的進度
*/
public abstract float getProgress() throws IOException, InterruptedException;
/**
* Close the record reader.
*/
public abstract void close() throws IOException;
}