常用輸入格式
輸入格式 | 特點 | 使用的RecordReader | 是否使用FileInputFormat的getSplits |
TextInputFormat | 以行偏移量為key,以換行符前的字元為Value | LineRecordReader | 是 |
KeyValueTextInputFormat | 預設分割符為”\t”,根據分割符來切分行,前為key,後為value | KeyValueLineRecordReader,内部使用LineRecordReader | 是 |
NLineInputFormat | 根據屬性mapreduce.input.lineinputformat.linespermap所設定的行數為每片split的行數 | LineRecordReader | 覆寫FileInputFormat的getSplits |
SequenceFileInputFormat | 使用Hadoop特有檔案格式SequenceFile.Reader進行讀寫,讀取二進制檔案 | SequenceFileRecordReader | 是 |
DBInputFormat | 通過與資料建立連接配接,将讀取的資料根據map數進行分片 | DBRecordReader | 繼承InputFormat,實作分片和RecordReader |
常用輸出格式
1. OutputFormat接口
OutputFormat為輸出格式接口,主要用于描述輸出資料的格式,它能将輸出的鍵值對寫入特定格式的檔案中。輸出格式的層次結構如下
2. 文本輸出
Hadoop預設的輸出格式為文本輸出格式TextOutputFormat,其鍵和值可以使任意類型的,因為該輸出方式會調用toString()方法将它們轉化為字元串。每個鍵/值對由制表符進行分割,當然也可以設定 mapreduce.output.textoutputformat.separator 屬性(舊版本 API 中為 mapred.textoutputformat.separator)改變預設的分隔符。
3. 二進制輸出
二進制輸出有三種方式:SequenceFileOutputFormat,SequenceFileAsBinaryOutputFormat和MapFileOutputFormat。重點掌握第一種。
對于SequenceFileOutputFormat,顧名思義,SequenceFileOutputFormat 将它的輸出寫為一個順序檔案。如果輸出需要作為後續 MapReduce 任務的輸入,這便是一種好的輸出格式, 因為它的格式緊湊,并且很容易被壓縮。而對于SequenceFileAsBinaryOutputFormat,它将鍵/值對作為二進制格式寫到一個 SequenceFile 容器中。不同的是,MapFileOutputFormat 把 MapFile 作為輸出。MapFile 中的鍵必須順序添加,是以必須確定 reducer 輸出的鍵已經排好序。
4. 多個輸出
由于預設情況下隻有一個 Reducer,輸出隻有一個檔案。有時可能需要對輸出的檔案名進行控制或讓每個 reducer 輸出多個檔案。
當隻有一個reduce時,輸出檔案命名格式為:part-r-00000。當有兩個reduce時,輸出檔案命名格式為:part-r-00000,part-r-00001。當有多個時以此類推。實作Reducer輸出多個檔案主要有以下兩種方式:Partitioner和MultipleOutputs。
4.1 Partitioner
我們考慮這樣一個需求:按學生的年齡段,将資料輸出到不同的檔案路徑下。這裡我們分為三個年齡段:小于等于20歲、大于20歲小于等于50歲和大于50歲。
我們采用的方法是每個年齡段對應一個 reducer。為此,我們需要通過以下兩步實作。
第一步:把作業的 reducer 數設為年齡段數即為3。
job.setPartitionerClass(PCPartitioner.class);//設定Partitioner類 job.setNumReduceTasks(3);// reduce個數設定為3
第二步:寫一個 Partitioner,把同一個年齡段的資料放到同一個分區。
public static class PCPartitioner extends Partitioner< Text, Text>
{
@Override
public int getPartition(Text key, Text value, int numReduceTasks) {
// TODO Auto-generated method stub
String[] nameAgeScore = value.toString().split("\t");
String age = nameAgeScore[1];//學生年齡
int ageInt = Integer.parseInt(age);//按年齡段分區
// 預設指定分區 0
if (numReduceTasks == 0)
return 0;
//年齡小于等于20,指定分區0
if (ageInt <= 20) {
return 0;
}
// 年齡大于20,小于等于50,指定分區1
if (ageInt > 20 && ageInt <= 50) {
return 1 % numReduceTasks;
}
// 剩餘年齡,指定分區2
else
return 2 % numReduceTasks;
}
}
這種方法即實作了多檔案輸出,但也隻能滿足此種需求。很多情況下是無法實作的,因為這樣做存在兩個缺點:
1)需要在作業運作之前需要知道分區數和年齡段的個數,如果分區數很大或者未知,就無法操作。
2)一般來說,讓應用程式來嚴格限定分區數并不好,因為這樣可能導緻分區數少或分區不均。
4.2 MultipleOutputs
MultipleOutputs 類可以将資料寫到多個檔案,這些檔案的名稱源于輸出的鍵和值或者任意字元串。這允許每個 reducer(或者隻有 map 作業的 mapper)建立多個檔案。 采用name-m-nnnnn 形式的檔案名用于 map 輸出,name-r-nnnnn 形式的檔案名用于 reduce 輸出,其中 name 是由程式設定的任意名字, nnnnn 是一個指明塊号的整數(從 00000 開始)。塊号保證從不同塊(mapper 或 reducer)寫的輸出在相同名字情況下不會沖突。
執行個體将在下一篇博文(MapReduce實戰:郵箱統計及多輸出格式實作)給出!
5. 資料庫輸出
DBOutputFormat 适用于将作業輸出資料(中等規模的資料)轉存到Mysql、Oracle等資料庫。如果資料量較大請考慮其他方法将輸出資料導入或轉存到資料庫中。