Map和Reduce階段都是分離的
map階段–程序mapTask
mapTask可以運行在多個服務器上面,具體啓動的數量取決於數據的數量。將文件化分給不同的mapTask的過程叫做切片。
因爲每個文件的大小不一致,所以並不是單純的按照文件的個數進行分配。所以其實是將文件分爲一些固定大小的數據塊,並且將數據塊分配給不同的map程序。
首先是對文件的大小進行掃描,之後根絕文件的整體的大小啓動相應數量的map程序
需要給map程序提供一個接口類,map將數據直接傳給接口類,之後接口類處理完的數據內容再遞交給mapTask使用context。
reduce階段–程序ReduceTask
mapTask所處理的數據需要提供給reduce程序,能把相同Key的數據給一個程序就可以完成對於某一個單詞的統計。
shuffle程序將key相同的kv數據一定發給同一個reduce程序。
分發給reduce的過程是固定的框架完成的,但是reduce裏面需要的邏輯需要使用者提供給框架,這個也是需要實現一個接口的實現類。
reduce會得到一些數據,統計其中所有屬於同一個key的數量。
使用MapReduce完成一次wordcount的過程
reduce和map都需要通過繼承hadoop所提供的類,並且重載其中的函數。
public class WordCounter extends Mapper<KEYIN,VALUEIN,KEYOUT,VALUEOUT>{
}
Mapper還有Reducer裏面有四個模板類型需要完善
- KEYIN: 是map task讀取到的數據的key的類型,是一行的起始偏移量Long。
- VALUEIN: 是map task讀取到的數據的value的類型,是一行的內容String。
- KEYOUT:是用戶的自定義map方法要返回的結果kv數據的key的類型,在wordcount邏輯中,我們需要返回的是單詞String。
- VALUEOUT: 是用戶的自定義map方法要返回的結果。kv數據的value的類型,在wordcount邏輯中,我們需要返回的是整數Integer。
在mapreduce中,map產生的數據需要傳輸給reduce,需要進行序列化和反序列化,而jdk中的原生序列化機制產生的數據量比較冗餘,就會導致數據在mapreduce運行過程中傳輸效率低下。
所以hadoop專門設計了自己的序列化機制,那麼mapreduce中傳輸的數據類型就必須實現hadoop自己的序列化接口
hadoop爲jdk中的常用基本類型Long String Integer Float等數據類型封住了自己的實現了hadoop序列化接口的類型:LongWritable,Text,IntWritable,FloatWritable
public class WordcountMapper extends Mapper<LongWritable, Text, Text, IntWritable>{
@Override
protected void map(LongWritable key, Text value, Context context)
throws IOException, InterruptedException {
// 切單詞
String line = value.toString();
String[] words = line.split(" ");
for(String word:words){
context.write(new Text(word), new IntWritable(1));
}
}
}
public class WordcountReducer extends Reducer<Text, IntWritable, Text, IntWritable>{
@Override
protected void reduce(Text key, Iterable<IntWritable> values,Context context) throws IOException, InterruptedException {
int count = 0;
Iterator<IntWritable> iterator = values.iterator();
while(iterator.hasNext()){
IntWritable value = iterator.next();
count += value.get();
}
context.write(key, new IntWritable(count));
}
}