天天看點

MapReduce輸入輸出格式常用輸入格式常用輸出格式

常用輸入格式

輸入格式 特點 使用的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
MapReduce輸入輸出格式常用輸入格式常用輸出格式

常用輸出格式

1. OutputFormat接口

  OutputFormat為輸出格式接口,主要用于描述輸出資料的格式,它能将輸出的鍵值對寫入特定格式的檔案中。輸出格式的層次結構如下

MapReduce輸入輸出格式常用輸入格式常用輸出格式

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等資料庫。如果資料量較大請考慮其他方法将輸出資料導入或轉存到資料庫中。

繼續閱讀