[大牛翻譯系列]Hadoop(6)MapReduce 排序:總排序(Total order sorting)


4.2.2 總排序(Total order sorting)

有的時候需要將作業的的所有輸出進行總排序,使各個輸出之間的結果是有序的。有以下實例:

  • 如果要得到某個網站中最受歡迎的網址(URL),就需要根據某種受歡迎的指標來對網址進行排序。
  • 如果要讓最活躍的用戶能夠看到某張表,就需要根據某種標准(發表文章數)對用戶進行排序。

 

技術22 在多個reduce間對鍵進行排序

在MapReduce框架中,map的輸出會被排序,然后被發送給reduce。不過,相同reduce的輸入數據是有序的,不同reduce的輸入數據就沒有順序關系了。如果要讓不同的reduce的數據也存在順序關系,就需要使用分區器(partitioner)。MapReduce的默認分區器是HashPartitioner。它使用map的輸出鍵的哈希值進行分區。這保證了相同的map輸出鍵的所有記錄會到達同一個reduce。不過HashPartitioner並不會對所有map的全部輸出鍵進行總排序。接下來說明如何在MapReduce中對所有map的全部輸出鍵進行排序:

 

問題

需要對作業輸出的所有鍵進行總排序,但是不能增加任何一個reduce的負擔。

 

方案

這里要用到TotalOrderPartitioner類來保證所有reduce的全部輸出是有序的。這個類由Hadoop自帶。這個分類器保證了所有map的全部輸出是完全有序的。那么只要reduce的輸出鍵和輸入鍵是一樣的,作業的最終輸出就是有序的。

 

討論

TotalOrderPartitioner是Hadoop的內置分區器。它根據分區文件進行分區。分區文件是一個包括N-1個鍵的預先計算好的序列文件。(N是指reduce的個數。)分區文件中的鍵的順序是由map輸出鍵比較器決定的。每一個鍵對應着一個邏輯區間。TotalOrderPartitioner檢查每一個輸出鍵,確定它在那個區間,然后將這個鍵發送給相對應的reduce。

圖4.15中說明了這個技術的兩個部分。第一部分,創建分區文件。第二部分,將TotalOrderPartitioner加入MapReduce作業。

 

 

先用InputSampler從輸入文件中抽樣,以生成分區文件。抽樣器可以選用RandomSampler類進行隨機抽樣,也可以選用IntervalSampler類進行間距為R的等距抽樣。生成的分區文件中將包含有序的N-1個鍵。N是reduce的個數。InputSampler不是MapReduce作業。它從InputFormat讀取數據。它在被調用的過程中生成分區。

下列代碼說明了在調用InputSampler函數之前需要完成的步驟:

 

 1 int numReducers = 2;
 2 
 3 Path input = new Path(args[0]);
 4 
 5 Path partitionFile = new Path(args[1]);
 6 
 7 InputSampler.Sampler<Text, Text> sampler = new InputSampler.RandomSampler<Text,Text>(0.1, 10000, 10);
 8 
 9 JobConf job = new JobConf();
10 
11 job.setNumReduceTasks(numReducers);
12 
13 job.setInputFormat(KeyValueTextInputFormat.class);
14 
15 job.setMapOutputKeyClass(Text.class);
16 
17 job.setMapOutputValueClass(Text.class);
18 
19 TotalOrderPartitioner.setPartitionFile(job, partitionFile);
20 
21 FileInputFormat.setInputPaths(job, input);
22 
23 InputSampler.writePartitionFile(job, sampler);

 

下一步在作業中指定TotalOrderPartitioner為分區器:

 

1 job.setPartitionerClass(TotalOrderPartitioner.class);

 

這個技術並不需要修改MapReduce作業本身,也就是說,不需要修改map或reduce過程。現在就可以開始運行代碼了:

 

$ hadoop fs -put test-data/names.txt names.txt

$ bin/run.sh com.manning.hip.ch4.sort.total.TotalSortMapReduce \
    names.txt \
    large-names-sampled.txt \
    output
    
$ hadoop fs -ls output
/user/aholmes/output/part-00000
/user/aholmes/output/part-00001

$ hadoop fs -cat output/part-00000 | head
AABERG
AABY
AADLAND

$ hadoop fs -cat output/part-00000 | tail
LANCZ
LAND
LANDA

$ hadoop fs -cat output/part-00001 | head
LANDACRE
LANDAKER
LANDAN

$ hadoop fs -cat output/part-00001 | tail
ZYSK
ZYSKOWSKI
ZYWIEC

 

從MapReduce作業的結果中可以看到,在各個輸出文件之間,map的輸出鍵是有序的。

 

小結

這個技術中使用InputSampler來創建分區文件。TotalOrderPartitioner使用這個分區文件來分區map的輸出鍵。

MapReduce也可以生成分區文件,但效率不高。另一個有效的的方法就是用自定義的InputFormat類來執行抽樣,並將抽樣后的鍵發送給一個reduce,由其創建分區文件。這也就是這一章下一個部分講到的抽樣。

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM