Mapreduce實例——WordCount

Mapreduce簡介


MapReduce採用的是“分而治之”的思想,把對大規模數據集的操作,分發給一個主節點管理下的各個從節點共同完成,然後通過整合各個節點的中間結果,得到最終結果。簡單來說,MapReduce就是”任務的分解與結果的彙總“。

MapReduce定義

MapReduce是Google公司發明的一種面向大規模海量數據處理的高性能並行計算平臺和軟件編程框架,是目前最爲成功和最易於使用的大規模海量數據並行處理技術,廣泛應用於搜索引擎(文檔倒排索引,網頁鏈接圖分析與頁面排序等)、Web日誌分析、文檔分析處理、機器學習、機器翻譯等各種大規模數據並行計算應用領域

MapReduce在三個層面上的基本構思

a.如何對付大數據:分而治之
對相互間不具有計算依賴關係的大數據,實行並行最自然的方式就是分而治之。
b.上升到抽象模型:Mapper和Reducer
MPI等並行計算方式缺少高層並行編程模型,爲了克服這一缺陷,MapReduce借鑑了Lisp函數式語言中的思想,用MapReduce兩個函數提供了高層的並行編程抽象模型。
c.上升到構架:統一構架,爲程序員隱藏系統細節
MPI等並行計算方法缺少統一的計算框架支持,程序員需要考慮數據存儲、劃分、分發、結果收集、錯誤恢復等諸多細節;爲此,MapReduce設計並提供了統一的計算框架,爲程序員隱藏了絕大多數系統層面的處理細節

MapReduce的工作原理

在分佈式計算中,MapReduce框架負責處理了並行編程裏分佈式存儲、工作調度,負載均衡、容錯處理以及網絡通信等複雜問題,現在我們把處理過程高度抽象爲Map與Reduce兩個部分來進行闡述,其中Map部分負責把任務分解成多個子任務,Reduce部分負責把分解後多個子任務的處理結果彙總起來

map部分:

map: (k1; v1)  [(k2; v2)]
輸入:鍵值對(k1; v1)表示的數據
處理:文檔數據記錄(如文本文件中的行,或數據表格中的行)將以“鍵值對”形式傳入map函數;map函數將處理這些鍵值對,並以另一種鍵值對形式輸出處理的一組鍵值對中間結果[(k2; v2)]
輸出:鍵值對[(k2; v2)]表示的一組中間數據
reduce部分:

reduce: (k2; [v2])  [(k3; v3)]
輸入: 由map輸出的一組鍵值對[(k2; v2)] 將被進行合併處理將同樣主鍵下的不同數值合併到一個列表[v2]中,故reduce的輸入爲(k2; [v2]) 
處理:對傳入的中間結果列表數據進行某種整理或進一步的處理,併產生最終的某種形式的結果輸出[(k3; v3)] 。
輸出:最終輸出結果[(k3; v3)] 

這裏寫圖片描述

這裏寫圖片描述

WordCount


實驗環境

Linux Ubuntu 14.0
jdk-7u75-linux-x64
hadoop-2.6.0-cdh5.4.5
hadoop-2.6.0-eclipse-cdh5.4.5.jar
eclipse-java-juno-SR2-linux-gtk-x86_64

實驗步驟

1.切換目錄到/apps/hadoop/sbin下,啓動hadoop。

cd /apps/hadoop/sbin  
./start-all.sh  

2.在linux上,創建一個目錄/data/mapreduce1。

mkdir -p /data/mapreduce1  

3.創建/data/mapreduce1/file,
內容爲:

China is my motherland
I love China
I am from China

4.將linux本地/data/mapreduce1/wordcount,上傳到HDFS上的/mymapreduce1/in目錄下。若HDFS目錄不存在,需提前創建。

hadoop fs -mkdir -p /mymapreduce1/in  
hadoop fs -put /data/mapreduce1/file /mymapreduce1/in 

5.打開Eclipse,File–>New–>Other–>Map/Reduce Project,項目名可以隨便取,如WordCount。導入所需的jar包(不詳述!)
這裏寫圖片描述

6.編寫代碼
(1).Mapper部分代碼:

期望的Map輸出類型爲<單詞,出現次數>
Map輸入類型爲<key,value>
Map輸入類型最終確定爲<Object,Text> //vlaue爲Text類型,指每次讀入文件的一行
Map輸出類型最終確定爲<Text,IntWritable>

    public static class doMapper extends Mapper<Object, Text, Text, IntWritable>{  
    //第一個Object表示輸入key的類型;第二個Text表示輸入value的類型;第三個Text表示表示輸出鍵的類型;第四個IntWritable表示輸出值的類型  
    public static final IntWritable one = new IntWritable(1);  
            public static Text word = new Text();  
            @Override  
            protected void map(Object key, Text value, Context context) throws IOException, InterruptedException  //拋出異常  
            {  
                StringTokenizer tokenizer = new StringTokenizer(value.toString(),"\t");  
              //StringTokenizer是Java工具包中的一個類,用於將字符串進行拆分  
               word.set(tokenizer.nextToken());  
                     //返回當前位置到下一個分隔符之間的字符串  
                    context.write(word, one);  
                     //將word存到容器中,記一個數  
              }
 }             

代碼解釋:

在map函數裏有三個參數,前面兩個Object key,Text value就是輸入的key和value,第三個參數Context context是可以記錄輸入的key和value。例如context.write(word,one);此外context還會記錄map運算的狀 態。map階段採用Hadoop的默認的作業輸入方式,把輸入的value用StringTokenizer()方法截取出的單詞設置爲key, 設置value1,然後直接輸出<key,value>。

Reducer代碼:

    public static class doReducer extends Reducer<Text, IntWritable, Text, IntWritable>{  
    //參數同Map一樣,依次表示是輸入鍵類型,輸入值類型,輸出鍵類型,輸出值類型  
    private IntWritable result = new IntWritable();  
            @Override  
            protected void reduce(Text key, Iterable<IntWritable> values, Context context)  
        throws IOException, InterruptedException {  
        int sum = 0;  
        for (IntWritable value : values) {  
        sum += value.get();  
        }  
        //for循環遍歷,將得到的values值累加  
        result.set(sum);  
        context.write(key, result);  
        }  
        } 

解釋:

map輸出的<key,value>先要經過shuffle過程把相同key值的所有 value聚集起來形成<key,values>後交給reduce端。reduce端接收到<key,values>之後,將 輸入的key直接複製給輸出的key,用for循環遍歷values並求和,求和結果就是key值代表的單詞出現的總次,將其設置爲value,直接輸 出<key,value>。

所導入包:

mport java.io.IOException;  
import java.util.StringTokenizer;  
import org.apache.hadoop.fs.Path;  
import org.apache.hadoop.io.IntWritable;  
import org.apache.hadoop.io.Text;  
import org.apache.hadoop.mapreduce.Job;  
import org.apache.hadoop.mapreduce.Mapper;  
import org.apache.hadoop.mapreduce.Reducer;  
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;  
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;  

主函數:

  public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {  
        Job job = Job.getInstance();  
        job.setJobName("WordCount");  
        job.setJarByClass(WordCount.class);  
        job.setMapperClass(doMapper.class);  
        job.setReducerClass(doReducer.class);  
        job.setOutputKeyClass(Text.class);  
        job.setOutputValueClass(IntWritable.class);  
        Path in = new Path("hdfs://localhost:9000/mymapreduce1/in/file");  
        Path out = new Path("hdfs://localhost:9000/mymapreduce1/out");  
        FileInputFormat.addInputPath(job, in);  
        FileOutputFormat.setOutputPath(job, out);  
        System.exit(job.waitForCompletion(true) ? 0 : 1);  
    }  

7.在WordCount類文件中,單擊右鍵=>Run As=>Run on Hadoop選項,將MapReduce任務提交到Hadoop中。
這裏寫圖片描述
8.待執行完畢後,打開終端或使用hadoop eclipse插件,查看hdfs上,程序輸出的實驗結果。

    hadoop fs -ls /mymapreduce1/out  
    hadoop fs -cat /mymapreduce1/out/part-r-00000  

9.執行結果爲:

I                    2
is                   1
China                3
my                   1
love                 1
am                   1
from                 1
motherland           1
發佈了128 篇原創文章 · 獲贊 51 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章