《十小時入門大數據》學習筆記之Hadoop核心組件MapReduce

目錄
    1. MapReduce概述
    1. MapReduce編程模型
      2.1 案例分析:WordCount => 詞頻統計
      2.2 執行步驟
    1. MapReduce架構
      3.1 MapReduce1.x的架構
      3.2 MapReduce2.x架構
    1. MapReduce編程
      4.1 核心概念
      4.2 編程實現WordCount
      4.2.1 WC開發的流程
      4.2.2 在Hadoop上運行自己編寫的WC代碼
      4.2.3 存在的問題
      4.2.4 解決辦法
      4.3 MapReduce編程之Combiner
      4.4 MapReduce編程之Partitioner
    1. JobHistory配置與啓動停止
      5.1 文件配置
      5.2 啓動與停止
    1. 基礎代碼

1. MapReduce概述

  • 源於Google的MapReduce論文,論文發表於2004年12月
  • Hadoop MapReduce是Google MapReduce的克隆版本
  • MapReduce優點:適合海量數據離線處理&易開發&易運行(但與Spark相比,MapReduce並沒有 易開發易運行的優點)
  • MapReduce缺點:不能進行實時流式計算
  • 官網的概述:Hadoop MapReduce is a software framework for easily writing applications which process vast amounts of data (multi-terabyte data-sets) in-parallel on large clusters (thousands of nodes) of commodity hardware in a reliable, fault-tolerant manner.

2. MapReduce編程模型

2.1 案例分析:WordCount => 詞頻統計

(統計文件中每個單詞出現的次數,工作場景中的很多開發都是在WordCount的基礎上進行改造的,因此深入理解該案例很重要.)

  • MapReduce主要的計算過程是採用 分而治之 的思想,將一個作業分爲Map階段和Reduce階段。
    在Map和Reduce階段
  • 將一個作業拆分成Map階段和Reduce階段
  • Map階段:對應多個Map Tasks
  • Reduce階段:對應多個Reduce Tasks
2.2 執行步驟
  • 官網的描述:The MapReduce framework operates exclusively on <key, value>pairs, that is, the framework views the input to the job as a set of<key, value>pairs and produces a set of <key, value>pairs as the output of the job, conceivably of different types.
    The key and valueclasses have to be serializable by the framework and hence need to implement the Writable interface. Additionally, the key classes have to implement the WritableComparable interface to facilitate sorting by the framework.

  • Input and Output types of a MapReduce job:
    (input) <k1, v1> -->map -> <k2, v2> -> combine -> <k2, v2> -> reduce -> <k3, v3> (output)

  • 整個MapReduce過程的數據格式都是鍵值對(<k1, v1>),針對WordCount案例:
    <k1, v1> :k1就是文件的偏移量,v1就是行的字符串內容;
    <k2, v2>:K2就是每個單詞,v2是該單詞k2出現的次數;
    <k3, v3>:k3和k2一樣,v3是同一個k2對應的多個v2累加的結果。

  • 作業處理過程:


3. MapReduce架構

3.1 MapReduce1.x的架構

1) JobTracker:JT (管理者)

  • 作業的管理者;將作業分解成一堆的任務:Task(MapTask和ReduceTask);
  • 將作業分派給TaskTracker運行;
  • 作業的監控、容錯處理(task作業掛了,重啓task機制);
  • 在一定的時間間隔內,JT沒有收到TT的心跳信息,TT可能是掛了,TT運行的任務會被指派到其他TT上去執行.
    2)TaskTracker:TT (執行者)
  • 任務的執行者 ;
  • 在TT上執行Task(MapTask和ReduceTask);
  • 與JT進行交互:執行啓動停止作業,發送心跳信息給JT
    3)MapTask:MT
  • 將自己開發的map任務交由Task處理;
  • 解析每條記錄的數據,交給自己的map方法處理;
  • 將map的輸出結果寫到本地磁盤(有些作業僅有map沒有reduce==>HDFS).
    4) ReduceTask: RT
  • 將Map Task輸出的數據進行讀取;
  • 安裝數據進行分析傳給自己編寫的reduce方法處理;
  • 輸出結果到HDFS.
3.2 MapReduce2.x架構

MapReduce2.x架構在 《十小時入門大數據》學習筆記之Hadoop核心組件YARN有詳細的介紹,這裏就不再贅述。

4. MapReduce編程

4.1 核心概念
  • Split:交由MapReduce作業來處理的數據塊,是MapReduce中最小的計算單元
  • blocksize : 是HDFS的最小的存儲單元, 爲128M
    默認情況下:Split和blocksize的大小是一一對應的,也可以手工設置他們之間的關係(但不建議這麼做).
  • InputFormat:將輸入的數據進行分片(split);
  • TextInputFormat:處理文本格式的數據;
4.2 編程實現WordCount
4.2.1 WC開發的流程

一共分爲三步:
1)Map:讀取輸入的文件
2)Reduce:進行歸併
3)Main:定義Driver,封裝了MapReduce作業的所有信息

4.2.2 在Hadoop上運行自己編寫的WC代碼

1)利用maven進行編譯打包:進入到項目的路徑下,在終端輸入下面代碼

mvn clean package -DskipTests

出現HUILD SUCCES表示編譯成功

2)上傳到服務器:同樣在終端輸入下面命令

scp target/hadoop-train-1.0.jar  hadoop@dell:~/data

3)運行:在服務器終端輸入下面命令,其中hdfs://localhost:8020/hello.txt是文件的輸入路徑,hdfs://localhost:8020/output/wc是輸出路徑。

hadoop jar /home/hadoop/data/hadoop-train-1.0.jar com.lyh.hadoop.mapreduce.WordCountApp hdfs://localhost:8020/hello.txt hdfs://localhost:8020/output/wc

打開瀏覽器:http://localhost:8088 ,能夠看到有一個我們的wordcount任務正在運行

運行結束後,查看hdfs的/output/wc/目錄,我們能夠看到多出兩個文件 查看part-r-00000文件,可以看到我們的計算結果

4.2.3 存在的問題
  • 相同的代碼和腳本再次執行,會報錯

  • 在MR中,輸出文件是不能事先存在的

4.2.4 解決辦法
  • 1)先手工通過shell的方式將輸出文件先刪除,創建一個shell腳本文件: hadoop@Dell:~/data$ vim wc_mr.sh
    把下面的代碼輸入到wc_mr.sh文件中
hadoop fs -rm -r /output/wc
hadoop jar /home/hadoop/data/hadoop-train-1.0.jar com.lyh.hadoop.mapreduce.WordCountApp hdfs://localhost:8020/hello.txt hdfs://localhost:8020/output/wc

保存,給wc_mr.sh添加執行權限:chmod u+x wc_mr.sh

執行腳本: ./wc_mr.sh 可以看到輸出的日誌中有刪除文件夾的操作
  • 2)在代碼中完成自動刪除功能(推薦使用這種方法)
    在main中添加以下代碼即可
// 準備清理已存在的輸出目錄
        Path outputPath = new Path(args[1]);
        FileSystem fileSystem = FileSystem.get(configuration);
        if(fileSystem.exists(outputPath)){
            fileSystem.delete(outputPath, true);
            System.out.println("output file exists, but is has deleted");
        }
4.3 MapReduce編程之Combiner
  • 相當於本地的reducer
  • 減少Map Task輸出的數據量及數據網絡傳輸量


  • 開發案例
    對於WC案例,只需要在原來的基礎上添加一句代碼即可
 //通過job設置combiner處理類,其實邏輯上和我們的reduce是一模一樣的
        job.setCombinerClass(MyReducer.class);

適用場景:求和 次數等
不適用的場景:求平均數

4.4 MapReduce編程之Partitioner
  • Partitioner決定Map Task 輸出的數據交由哪個Reduce Task處理
  • 默認實現:分發的key的hash值對Reduce Task個數取模
  • 開發案例
    需求:有一份手機銷售量數據,如下:
xiaomi 100
huawei 600
iphone 200
xiaomi 700
xiaomi 200
huawei 800

要求統計各類手機的總銷售量,分別存儲在不同的文件中

  • 實現代碼
    略(見代碼中的ParititonerApp類)

5 JobHistory配置與啓動停止

  • 記錄已經運行完的MapReduce信息到指定的HDFS目錄下
  • 默認沒有開啓的
5.1 文件配置

1)在yarn-site.xml中添加

<!-- 開啓日誌聚合 -->
<property>
<name>yarn.log-aggregation-enable</name>
<value>true</value>
</property>

2)在mapred-site.xml中添加

<!-- 設置jobhistoryserver 沒有配置的話 history入口不可用 --> 
<property> 
  <name>mapreduce.jobhistory.address</name> 
  <value>localhost:10020</value> 
</property> 
<!-- 配置web端口 --> 
<property>                                                          <name>mapreduce.jobhistory.webapp.address</name> 
  <value>localhost:19888</value> 
</property> 
<!-- 配置正在運行中的日誌在hdfs上的存放路徑 --> 
<property> 
    <name>mapreduce.jobhistory.intermediate-done-dir</name>
   <value>/history/done_intermediate</value> 
</property> 
<!-- 配置運行過的日誌存放在hdfs上的存放路徑 --> 
<property> 
   <name>mapreduce.jobhistory.done-dir</name> 
   <value>/history/done</value> 
</property>
5.2 啓動與停止

1)啓動: 在hadoop/sbin/目錄下執行

./mr-jobhistory-daemon.sh start historyserver

2)停止:在hadoop/sbin/目錄下執行

./mr-jobhistory-daemon.sh stop historyserver
6.基礎代碼

完整的項目見:https://download.csdn.net/download/qq_29557137/10862010

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
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;

import java.io.IOException;

/**
 * 使用MapReduce開發WordCount應用程序
 */
public class WordCountApp {
    /**
     * Map:讀取輸入的文件,注意這裏的Mapper<LongWritable, Text, Text, LongWritable>類型需要自己定義,因爲我們的第一個<k1,v1>是文件的偏移量和字符串,因此k1的類型設置爲LongWritable,Text,輸出的是單詞和單詞出現的次數,因此<k2,v2>的類型設置爲Text 和 LongWritable
     */
    public static class MyMapper extends Mapper<LongWritable, Text, Text, LongWritable>{

        LongWritable one = new LongWritable(1);

        @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) {
                // 通過上下文把map的處理結果輸出
                context.write(new Text(word), one);
            }

        }
    }

    /**
     * Reduce:歸併操作
     */
    public static class MyReducer extends Reducer<Text, LongWritable, Text, LongWritable> {

        @Override
        protected void reduce(Text key, Iterable<LongWritable> values, Context context) throws IOException, InterruptedException {

            long sum = 0;
            for(LongWritable value : values) {
                // 求key出現的次數總和
                sum += value.get();
            }
            // 最終統計結果的輸出
            context.write(key, new LongWritable(sum));
        }
    }

    /**
     * 定義Driver:封裝了MapReduce作業的所有信息
     */
    public static void main(String[] args) throws Exception{

        //創建Configuration
        Configuration configuration = new Configuration();

        //創建Job
        Job job = Job.getInstance(configuration, "wordcount");

        //設置job的處理類
        job.setJarByClass(WordCountApp.class);

        //設置作業處理的輸入路徑
        FileInputFormat.setInputPaths(job, new Path(args[0]));

        //設置map相關參數
        job.setMapperClass(MyMapper.class);
        job.setMapOutputKeyClass(Text.class);
        job.setMapOutputValueClass(LongWritable.class);

        //設置reduce相關參數
        job.setReducerClass(MyReducer.class);
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(LongWritable.class);

        //設置作業處理的輸出路徑
        FileOutputFormat.setOutputPath(job, new Path(args[1]));

        System.exit(job.waitForCompletion(true) ? 0 : 1);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章