具體問題見StackOverFlow上的描述:
http://stackoverflow.com/questions/36326068/a-strange-output-in-mapreduce-of-hadoop
簡而言之,就是在修改了TeraInputFormat.java之後,執行TeraSort所得到的輸出資料不同程度的翻倍,剛開始並沒有什麼頭緒,並且把取樣的執行緒和Map的讀入<key, value>搞混了,邏輯不清晰,導致很多時間都在無關緊要的地方反覆除錯.
其實應該可以想到一種辦法,就是在MapTask裡設斷點觀察,但不知道是自己懶還是因為對隱藏在深處的MapTask有一種畏懼心裡,起初我並沒有仔細進去看,後來在MapTask裡RecordReader部分的nextKeyValue()方法裡設定變數計數並輸出,來觀察每次split所獲取的記錄條數,結果發現,我的每個split都完整的獲取了整個(注意是整個輸入檔案)而不是一個split大小的記錄,所以輸出也隨著翻倍了.
那麼關鍵點找出來了,問題出在哪裡呢?MapTask部分是Hadoop預設繫結的,TeraSort並沒有重寫,所以這部分不可能出錯;TeraInputFormat的前半部分是取樣部分,問題不可能出在這裡;後半部分的RecordReader的initialize部分和修改前基本無變化,那錯誤的部分一定是在nextKeyValue()部分了,於是一行一行分析,最終鎖定了這一句:
newSize = in.readLine(record);
很普通的讀取一行記錄,那有沒有可能是readLine()這個方法對長度沒有限定呢?雖然nextKeyValue()方法是split物件呼叫的,但會不會readLine()並不理會你每個split塊的大小而是一股氣往下讀取直到讀到檔案末尾呢?
為了驗證這個可能,我新增了全域性變數:
long recordLen;
//將下面這句加在nextKeyValue()中
recordLen += newSize;
來記錄讀取記錄的總長度,,並設定當
if(recordLen >= split.getLength){
return false;
}
修改後打jar包放到節點上執行,結果正確!!!