---
# System prepended metadata

title: 平行程式 NTHU-PP-Chap11-MapReduce
tags: [平行程式]

---

教材:10710周志遠教授平行程式
https://www.youtube.com/playlist?list=PLS0SUwlYe8cxqw70UHOE5n4Lm-mXFXbZT

20250917 筆記
內容可能有錯僅供參考
在這個章節開始投影片和10710周志遠教授平行程式有差異，接下來以
NTHU-PP-2021 (Chinese) 為主


[NTHU-PP-Chap11-MapReduce-Part1 and 2](https://www.youtube.com/watch?v=OE2K5R-UqnE&list=PLQTDfc8kgjhMKtgumyK0gmEelnTtqJGsp&index=25)


搭配 23A~23D Advancing Programming for MapReduce

今日大綱
1.Hadoop 運作原理與程式
2.MapReduce 程式設計模型
3.Hadoop MapReduce 的執行過程與函式
4.進階程式設計技巧

**1. MapReduce 簡介與版本差異**
*   **目的**：學習如何撰寫分散式執行的程式，儘管使用者不需要有平行程式設計的概念。
*   **作業焦點**：作業將著重於實作 MapReduce 本身，而非 MapReduce 應用。
*   **Hadoop (H)**：MapReduce 的一個開源實作，由 Yahoo! 團隊開發，主要使用 Java 語言。
*   **版本差異**：
    *   **Hadoop 1.0 與 2.0 (YARN)**：主要差異在於 2.0 增加了資源管理容器 (resource management container)，提升了執行上的資源配置優勢，但程式設計模型本身變化不大。
    *   **Hadoop 3.0**：文中提到當時仍處於 2.0 版本，但基本程式設計差異不大。
*   **現今應用**：目前 Hadoop 的使用率較少，Scala Spark 應用更為普遍。但對於解決特定分散式計算問題，Hadoop 仍是重要工具。

**2. Hadoop 運作原理與程式提交**
*   **管理集群**：Hadoop 是一個管理集群進行分散式計算的軟體。
*   **運作流程**：類似於平行程式計算集群：
    1.  使用者將程式提交給排程主控端 (schedule master)。
    2.  主控端開始產生可分散式計算的任務 (tasks)。
    3.  主控端管理這些任務，並處理執行時的錯誤回復 (fault recovery) 等問題。
*   **程式執行**：使用者執行一個程式，實際上是在提交一個工作 (job)，由 Hadoop 進行排程與執行。
*   **程式撰寫**：需要引用 Hadoop 的相關套件 (package)。

**3. Hadoop MapReduce 套件 (Package) 的區別**
*   **舊版**：`org.apache.hadoop.mapred`。
*   **新版**：`org.apache.hadoop.mapreduce`。
*   **重要提示**：在撰寫或參考範例程式碼時，切勿混用這兩個套件，否則可能產生奇怪的問題。本課程以 `mapreduce` 套件進行解釋。

**4. MapReduce 程式設計模型**
*   **Java OO 方式**：透過繼承 (inheritance) 與覆寫 (override) 類別 (class) 中的部分方法來實現。
*   **優點**：程式碼量相對較少，只需覆寫特定部分。
*   **缺點**：較不直觀，因無法看到整個程式的完整流程。使用者需要了解 Hadoop 框架中各類別的運作方式。
*   **可覆寫的函式 (functions)**：
    *   `Mapper class` 中的 `map function`。
    *   `Reducer class` 中的 `reduce function`。
    *   `Partitioner class` 中的 `getPartition function`。
*   **核心概念**：需要想像這些類別和覆寫的方法如何協同運作，以實現整個 MapReduce 程式的執行過程。

**5. 關鍵類別 (Key Classes)**
除了 Mapper、Reducer 和 Partitioner 函式之外，主要還有兩個核心類別：
*   **`Configuration` 類別**：主要用於設定集群 (cluster) 的參數，決定 MapReduce 引擎如何根據設定來執行和管理工作。
*   **`Job` 類別**：描述一個工作 (job)。一個程式 (program) 可以提交多個工作，甚至協調這些工作的運作，將其視為一個單一應用程式。
    *   程式提交工作後，可透過 API 查詢工作狀態 (`map progress`, `reduce progress`)、控制工作 (如 `kill job`, `kill task`) 或修改執行時設定。
    *   **同步 (Synchronous) 提交**：使用 `waitForCompletion()`，主程式會阻塞 (block) 直到工作完成。
    *   **非同步 (Asynchronous) 提交**：使用 `submit()`，主程式提交後可繼續執行其他任務，並透過 API 查詢工作狀態或進行控制。

**6. Hadoop MapReduce 的執行過程與函式 (Hadoop's Implementation)**
Hadoop 將 MapReduce 的執行過程分為兩個主要階段：Map Phase (M Face) 和 Reduce Phase (Reduce Face)。

**6.1. Map Phase**
由以下幾個過程和函式組成：
*   **Split (輸入切割)**：
    *   `InputFormat class`：負責處理輸入資料的切割。
    *   **`split` 函式**：讀取一塊資料 (chunk of data)，決定輸出鍵值對 (key-value pair) 的記錄。
    *   **預設切割**：通常以「一行」作為一個記錄 (record)。
    *   **Text Input Format**：預設的實作，鍵 (key) 為行號 (line number)，值 (value) 為該行所有文字。
    *   **KeyValueText Input Format**：可指定分隔符號 (separator character/byte) 來切割一行內的鍵值對。
    *   **自訂切割**：可以在 `map` 函式內部進一步細切記錄。
*   **Map 函式**：
    *   每個記錄 (record) 會被傳遞給 `map` 函式。
    *   生成零個或多個中間鍵值對 (intermediate key-value pairs)。
    *   **輸出方式**：透過 `Context object` 來輸出鍵值對。
    *   **物件生命週期**：輸出的 `Writable object` 必須在類別層級 (class level) 宣告，而非 `map` 函式內部，以避免記憶體釋放導致程式崩潰。
*   **Partitioner (分區)**：
    *   `Partitioner class` 中的 `getPartition` 函式。
    *   根據鍵 (key) 的雜湊值 (hash code) 或其他邏輯，決定將記錄發送到哪個 Reducer。
    *   **目的**：確保每個 Reducer 處理的資料量大致相同 (負載平衡, load balance)，或將特定鍵分配到同一 Reducer 進行處理。
    *   **回傳值**：Reduer ID (範圍在 0 到 Reducer 數量減一之間)。
*   **Combiner (組合器)**：
    *   **選用 (Optional)**：框架會根據資料量大小決定是否呼叫 Combiner，程式設計師無法控制。
    *   **功能**：在 Mapper 端進行類似 Reduce 的預先處理，減少傳輸到 Reducer 的資料量，優化網路頻寬。
    *   **限制**：
        *   Combiner 的輸出鍵值對資料型別必須與 Mapper 的輸出鍵值對資料型別一致，不能做型別轉換。
        *   Combiner 必須是「可重複套用」的 (idempotent)，即使多次呼叫或不呼叫，最終結果也必須正確。
        *   不適用於需要「全局視圖」的聚合操作 (如中位數計算)。
    *   **程式碼**：與 Reducer 函式非常相似。

**6.2. Shuffle and Sort Phase (洗牌與排序)**
發生在 Map Phase 和 Reduce Phase 之間。
*   **資料傳輸**：Reducer 會從各個 Mapper 任務中拉取 (copy) 其分區後的暫存資料。
*   **Shuffle (洗牌)**：
    *   在資料傳輸過程中，會使用 `Merge Sort` 演算法進行排序。
    *   根據鍵 (key) 的 `compare` 函式定義的順序，收集並排序每個 Mapper 的中間鍵值對。
    *   **可覆寫**：`Sort Comparator` 函式可用於自訂排序順序 (升序或降序)。
*   **Grouping (分組)**：
    *   排序完成後，Reducer 拿到的鍵值對已按鍵排序。
    *   使用 `Grouping Comparator` 函式，將相同鍵的數值 (values) 合併成一個列表 (list)。
    *   **可覆寫**：`Grouping Comparator` 函式決定哪些鍵被視為「相同」而分組在一起。
    *   **結果**：每個鍵會對應一個數值列表。

**6.3. Reduce Phase**
*   **Reduce 函式**：
    *   針對每個分組後的鍵和其對應的數值列表 (list of values) 進行聚合 (aggregation)。
    *   每個鍵會搭配一個值迭代器 (Iterator of values)。
*   **Output (輸出)**：
    *   `OutputFormat class`：負責將結果寫出。
    *   **`write` 函式**：將處理後的鍵值對寫入最終輸出檔案。
    *   **預設格式**：通常一個輸出鍵對應一行。
    *   **可覆寫**：可以自訂輸出格式，例如不換行、只輸出值不輸出鍵等。
    *   **Text Output Format**：預設的實作，一個鍵值對對應一行。

**7. 資料型別 (Data Types)**
*   **強型別 (Strongly Typed)**：Java 要求明確定義資料型別並進行正確的型別轉換。
*   **`Writable` 介面**：所有鍵值對的資料型別都必須實作此介面，因為這些物件將在不同類別間處理。
*   **`ComparableWritable` 介面**：鍵 (key) 的資料型別除了 `Writable` 外，還必須實作 `Comparable` 介面，以便進行排序。
    *   **實作方法**：`write()` 和 `readFields()` (用於序列化/反序列化)、`compareTo()` (用於排序)、`hashCode()` (用於 Partitioner)。
*   **可定義的型別**：
    *   `setInputFormatClass`：控制初始輸入鍵值對的型別。
    *   `setMapOutputKeyClass` / `setMapOutputValueClass`：控制 Mapper 輸出鍵值對的型別。
    *   `setOutputKeyClass` / `setOutputValueClass`：控制 Reducer 輸出鍵值對的型別 (最終輸出)。
    *   `setOutputFormatClass`：控制輸出檔案的寫入格式。
*   **範例型別**：`IntWritable` (對應 Java int)、`Text` (對應 Java String)，這些都實作了 `Writable` 及 `Comparable` 介面。
*   **自訂資料型別**：
    *   透過實作 `Writable` 和 `ComparableWritable` 介面，可以自訂複雜的資料型別，如 3D 座標作為鍵。
    *   避免在 `map` 函式內進行繁瑣的字串解析和組合，使程式碼更直觀。

**8. Reducer 數量的設定**
*   **Mapper 數量**：由輸入檔案的大小和切割方式決定，不可手動設定。
*   **Reducer 數量**：可透過 `setNumReduceTasks()` 函式來設定。
*   **Reducer 數量過多**：
    *   每個 Reducer 處理的工作量減少，導致啟動/停止 Reducer 的開銷 (overhead) 佔比較高。
    *   產生過多的輸出檔案，且每個檔案內的鍵可能無法有效排序。
*   **Reducer 數量過少 (如一個)**：
    *   失去平行處理的優勢，降低平行度。
    *   **優勢**：可實現「全域排序 (global sorting)」，將所有結果排序在單一輸出檔案中。
*   **最佳數量**：通常與 `Reduce slot` 數量相關，應盡量利用硬體資源，但避免過多或過少。

**9. 進階程式設計技巧 (Advanced Programming)**
除了基本的 `map` 和 `reduce` 函式，還可以覆寫其他類別的函式，實現更複雜或高效的計算。

*   **1. 自訂資料型別 (Custom Data Types)**
    *   **目的**：定義特殊的鍵 (key) 或值 (value) 型別，如 3D 座標。
    *   **實現**：
        *   值 (value) 實作 `Writable` 介面。
        *   鍵 (key) 實作 `Comparable` 和 `Writable` 介面。
    *   **需要覆寫的方法**：
        *   `write(DataOutput out)` 和 `readFields(DataInput in)`：用於資料的序列化 (serialize) 和反序列化 (deserialize)，供 Input/Output Format 類別使用。
        *   `compareTo(Object o)`：供排序函式 (Sort Comparator) 比較物件大小。
        *   `hashCode()`：供 Partitioner 函式決定分區。

*   **2. 自訂 Partitioner (分區器)**
    *   **目的**：精確控制鍵值對分配到哪個 Reducer，實現負載平衡或特定鍵的分組。
    *   **實現**：覆寫 `Partitioner` 類別的 `getPartition` 函式。
    *   **範例**：將 A-K 開頭的鍵丟到第一個 Reducer，L-Z 開頭的鍵丟到第二個 Reducer。
    *   **進階應用**：透過資料分析 (profiling/sampling) 了解鍵的分布，進行更精確的負載平衡。

*   **3. 自訂 Comparators (比較器)**
    *   **a. Sort Comparator (排序比較器)**
        *   **目的**：在 Shuffle 階段定義鍵的排序邏輯。
        *   **實現**：覆寫 `WritableComparator` 或實作 `RawComparator` 介面。
        *   **範例**：自訂按鍵的第一個字元排序。
    *   **b. Grouping Comparator (分組比較器)**
        *   **目的**：在 Reduce 階段定義哪些鍵被視為「相同」而分組在一起，即使它們在排序上是不同的。
        *   **實現**：覆寫 `WritableComparator` 或實作 `RawComparator` 介面。
        *   **範例**：只比較鍵的第一個字元來進行分組。
        *   **注意**：分組後，Reduer 會將該組的第一個鍵作為代表鍵，並將所有對應的值作為列表處理。

*   **4. 二級排序 (Secondary Sort)**
    *   **問題**：除了按鍵排序，還希望對鍵所對應的值進行排序。例如，按年/月分組，然後按溫度排序。
    *   **傳統做法的缺點**：將所有值拉到 Reducer 端再排序效率低下。
    *   **高效實作方法 (Solution 2 - Composite Key)**：
        1.  **Composite Key (組合鍵)**：在 Mapper 輸出時，將希望進行排序的值也包含在鍵中 (例如：`年,月,溫度` 作為一個鍵)。
        2.  **自訂 Partitioner**：確保只有年和月相同的記錄被送往同一個 Reducer (Partitioner 只看組合鍵的前半部分，例如年和月)。
        3.  **自訂 Sort Comparator**：定義排序規則，先按年、月排序，如果年、月相同，再按溫度排序。
        4.  **自訂 Grouping Comparator**：定義分組規則，只按年、月進行分組，忽略溫度部分。
        5.  **Reducer 處理**：Reducer 接收到年/月相同但溫度已排序的記錄組。在 `reduce` 函式中，去除鍵中多餘的溫度部分，只輸出年/月和排序過的值列表。
    *   **優勢**：利用 MapReduce 框架自動化的排序功能，實現值內部的排序，效率高。



---
其他課程連結

[平行程式1C~2B Introduction parallel programming](https://hackmd.io/@6FOC2dvARe-Vz0kVSyajew/Syxh3H7Kxe)
[平行程式3A~3D The Latest Developments and Applications Using Parallel Programming](https://hackmd.io/@6FOC2dvARe-Vz0kVSyajew/HJh7QFVKle)
[平行程式4A~4B IO Parallel IO and Program Analysis](https://hackmd.io/@6FOC2dvARe-Vz0kVSyajew/HJLMsuHFgg)
[平行程式5A~5B The Latest Developments and Applications Using Parallel Programming](https://hackmd.io/@6FOC2dvARe-Vz0kVSyajew/SJh57hIFle)
[平行程式6A~6B Communication Routines and Parallel Function Code](https://hackmd.io/@6FOC2dvARe-Vz0kVSyajew/r1X9kX_Fle)
[平行程式 6C~6D Communication Routines and Parallel Function Code](https://hackmd.io/@6FOC2dvARe-Vz0kVSyajew/S1DPjoYFlx)
[平行程式 7A~8A Pthread:Synchronization Problem & Tools](https://hackmd.io/@6FOC2dvARe-Vz0kVSyajew/HJu-_0tKge)
[平行程式 8B~8D Synchronization Tools & Open Multi-Processing(OpenMP)](https://hackmd.io/@6FOC2dvARe-Vz0kVSyajew/H1ki4E2Fee)
[平行程式 9A~9B Synchronization Construct](https://hackmd.io/@6FOC2dvARe-Vz0kVSyajew/BJTYMrpKlx)
[平行程式 10A~10B Synchronization Tools & Open Multi-Processing Synchronization Construct](https://hackmd.io/@6FOC2dvARe-Vz0kVSyajew/B1cY6M1qee)
[平行程式 10C~10D Synchronization Tools & Open Multi-Processing Synchronization Construct](https://hackmd.io/@6FOC2dvARe-Vz0kVSyajew/BkgFaNg5gg)
[平行程式 11A~11B Parallel Work Pool and Termination / Parallel Sorting](https://hackmd.io/@6FOC2dvARe-Vz0kVSyajew/H1hfOw-5xl)
[平行程式 12A~12B Parallel Sorting and Pipelined Computations](https://hackmd.io/@6FOC2dvARe-Vz0kVSyajew/Symo-zQ9eg)
[平行程式 12C~12D Parallel Sorting and Pipelined Computations](https://hackmd.io/@6FOC2dvARe-Vz0kVSyajew/BJYNKDVceg)
[平行程式 13A-13B  Sychronous Parallelism](https://hackmd.io/@6FOC2dvARe-Vz0kVSyajew/HJ2UJ2Bqex)
[平行程式 14A~14B Heterogeneous Computing](https://hackmd.io/@6FOC2dvARe-Vz0kVSyajew/BksS4yP5eg)
[平行程式 14C~14D Heterogeneous Computing](https://hackmd.io/@6FOC2dvARe-Vz0kVSyajew/BJrfTUd9xx)
[平行程式 15A~15B Parallel Programming Model on GPU](https://hackmd.io/@6FOC2dvARe-Vz0kVSyajew/ByWnl-t5gg)
[平行程式 16A~16B What is Compute Unified Device Architecture(CUDA)?](https://hackmd.io/@6FOC2dvARe-Vz0kVSyajew/HyYpsjcqgl)
[平行程式 17A~18A 平行運算的CUDA](https://hackmd.io/@6FOC2dvARe-Vz0kVSyajew/H1dUeBT5lg)
[平行程式 18B~19A  記憶體層級 / CUDA的優化](https://hackmd.io/@JuitingChen/HyF44e1jge)
[平行程式 19B~19D 記憶體層級 / CUDA的優化 ](https://hackmd.io/@JuitingChen/ryPEu4lieg)
[平行程式 20A~20B CUDA優化全域和區域記憶體/共享記憶體](https://hackmd.io/@JuitingChen/r1X659Zoxl)
[平行程式 21A~21B Parallel Reduction / Distributed Computing Framework](https://hackmd.io/@JuitingChen/HyiOpozjxl)
[平行程式 NTHU-PP-Chap10-Big Data-Part1 ](https://hackmd.io/@JuitingChen/Hyc-e3Golx)
[平行程式 NTHU-PP-Chap10-Big Data-Part2 ](https://hackmd.io/@JuitingChen/ryC_QTXoxl)
[平行程式 NTHU-PP-Chap11-MapReduce](https://hackmd.io/@JuitingChen/HJgBXJOsge)
[平行程式 NTHU-PP-Chap12-Distributed Training-Part1](https://hackmd.io/@JuitingChen/ryh5hBtsge)
[平行程式 NTHU-PP-Chap12-Distributed Training-Part2](https://hackmd.io/@JuitingChen/rJ2G7kdjxg)
[平行程式 NTHU-PP-Chap12-Distributed Training-Part3](https://hackmd.io/@JuitingChen/HkA471dilx)
[平行程式 NTHU-PP-Chap13-UCX-Part1](https://hackmd.io/@JuitingChen/rJbq103ieg)
[平行程式 NTHU-PP-Chap13-UCX-Part2](https://hackmd.io/@JuitingChen/SJpNmk_ixl)
[平行程式 NTHU-PP-Chap13-UCX-Part3](https://hackmd.io/@JuitingChen/HkIUYa13xe)
