1. 程式人生 > >Hadoop權威指南-大資料的儲存與分析第四版——學習筆記——第2章——1

Hadoop權威指南-大資料的儲存與分析第四版——學習筆記——第2章——1

MapReduce

適合處理半結構化的資料

MapReduce任務階段

Map階段+Reduce階段
Key-Value作為輸入輸出
實現兩個函式:map(),reduce()

Map階段

輸入的Key:文字中的偏移量
輸入的value:文字
輸出的k-v給reduce處理

Reduce階段

基於key對k-v對進行 排序分組
例如:
輸入資料(文字):在這裡插入圖片描述
map輸入:
在這裡插入圖片描述
map輸出:
在這裡插入圖片描述
reduce輸入(注:這裡的輸入是分組、排序後的,key為年份,value為List):
在這裡插入圖片描述
reduce輸出(找出每年裡的最高溫度/最大數值):
在這裡插入圖片描述
整個資料流程圖如下:
在這裡插入圖片描述

Java MapReduce

注: Mapper和Reducer類都是抽象類,需要實現其map,reduce抽象方法
1)需要匯入的包——org.apache.hadoop下的包,包括:
org.apache.hadoop.mapreduce.Mapper/.Reducer
org.apaceh.hadoop.io.IntWritable/.LongWritable/.Text
2)Map類需要extends Mapper<四個輸入輸出格式引數型別>,實現map(四個輸入輸出格式引數)函式,返回值為void,這裡的map函式的引數可以為 :
輸入key,輸入value,Context/Mapper<輸出key,輸出value>.Context
3)Reduce類需要extends Reduce<四個輸入輸出格式引數型別>,實現reduce(輸入key型別 key,輸入Iterable<value型別> value,Context/Reducer<輸出key,輸出value>.Context)
4) 只要實現了Iterable介面的物件都可以使用for-each迴圈
public interface Iterable {
Iterator iterator();
}
關於hadoop reduce階段遍歷Iterable的注意事項


只能遍歷一次(物件重用:輸入key和輸入value物件只有一對,反覆利用,所以要想重複遍歷這兩個物件,尤其是第二個iterable,就要clone一下;當初一直在想為什麼用iterable不用iterator呢,現在發現iterable介面的iterator() 方法返回的是一個特殊的迭代器,他原則上不允許迭代兩次及以上,若迭代兩次及以上則會返回空值,因為物件重用,reduce階段輸入的value值不一定都在記憶體內,可能還要從磁碟上讀取,所以hadoop不允許對接受到的value迭代器重複遍歷,現在大概理解到這個層面上,具體是不是因為java對於iterable的機制就是這樣我也不太清楚,之後再來加深瞭解吧。(ps:昨天查了下java的iterable和iterator,有了新的瞭解,也想到了reduce階段輸入的引數可能是hadoop定義了一個類,這個類還不知道是什麼反正是實現好了iterable和iterator的介面,然後建立這個類的物件讀取輸入的value值,並作為引數傳給reduce函式)
最後附上Stack Overflow上的解答:
The Iterator you receive from that Iterable’s iterator() method is special. The values may not all be in memory; Hadoop may be streaming them from disk. They aren’t really backed by a Collection, so it’s nontrivial to allow multiple iterations.

for(Text val : values) {
valList.add(val.toString());
textList.add(val);
}
這個部分第一次val.toString()得到的每個k-v對中不同的value值,但是第二次add(val)進去的卻一直是最後一個k-v對的值,這是因為add方法傳遞的是物件的地址,因為上文的value物件一直在被複用,所以第二次遍歷的時候,他一直指向最後一個k-v對
ps這裡如果處理更大規模的資料,會不會因為reduce階段處理時間太長而導致複用的value物件還沒用讀到最後一個k-v對,而是其他k-v對的值,然後textList中的物件地址指向的並不是最後一個k-v對?
我覺得可能會,因為shuffling階段從map節點上merge的最終輸入檔案可能因為太大而存在了磁碟上,而且預設也是存在磁碟上的,這個參照部落格 https://blog.csdn.net/mrlevo520/article/details/76781186 資料量過大導致記憶體中的value放不下,就必須讀一批value然後reduce處理一下,再釋放記憶體中的value,再從磁碟讀,再reduce處理,知道最後處理完成,這樣的話就有可能發生上述的情況。)
https://blog.csdn.net/jdbc/article/details/38850961
1、需要三個東西:map函式 reduce函式 執行作業的程式碼
Java Context類:類似於放資訊的容器
2、org.apache.hadoop.io包中提供了一套可優化網路序列化的基本型別,例如:IntWritable,LongWritable,Text
注: String類的substring(int beginIndex,int endIndex)方法,擷取子串
beginIndex:起始索引(包括),索引從0開始;
endIndex:結束索引(不包括