### 5.1 實驗目的
基于MapReduce思想,編寫WordCount程序。
### 5.2 實驗要求
1. 理解MapReduce編程思想;
2. 會編寫MapReduce版本WordCount;
3. 會執行該程序;
4. 自行分析執行過程。
### 5.3 實驗原理
MapReduce是一種計算模型,簡單的說就是將大批量的工作(數據)分解(MAP)執行,然后再將結果合并成最終結果(REDUCE)。這樣做的好處是可以在任務被分解后,可以通過大量機器進行并行計算,減少整個操作的時間。
適用范圍:數據量大,但是數據種類小可以放入內存。
基本原理及要點:將數據交給不同的機器去處理,數據劃分,結果歸約。
理解MapReduce和Yarn:在新版Hadoop中,Yarn作為一個資源管理調度框架,是Hadoop下MapReduce程序運行的生存環境。其實MapRuduce除了可以運行Yarn框架下,也可以運行在諸如Mesos,Corona之類的調度框架上,使用不同的調度框架,需要針對Hadoop做不同的適配。
一個完成的MapReduce程序在Yarn中執行過程如下:
(1)ResourcManager JobClient向ResourcManager提交一個job。
(2)ResourcManager向Scheduler請求一個供MRAppMaster運行的container,然后啟動它。
(3)MRAppMaster啟動起來后向ResourcManager注冊。
(4)ResourcManagerJobClient向ResourcManager獲取到MRAppMaster相關的信息,然后直接與MRAppMaster進行通信。
(5)MRAppMaster算splits并為所有的map構造資源請求。
(6)MRAppMaster做一些必要的MR OutputCommitter的準備工作。
(7)MRAppMaster向RM(Scheduler)發起資源請求,得到一組供map/reduce task運行的container,然后與NodeManager一起對每一個container執行一些必要的任務,包括資源本地化等。
(8)MRAppMaster 監視運行著的task 直到完成,當task失敗時,申請新的container運行失敗的task。
(9)當每個map/reduce task完成后,MRAppMaster運行MR OutputCommitter的cleanup 代碼,也就是進行一些收尾工作。
(10)當所有的map/reduce完成后,MRAppMaster運行OutputCommitter的必要的job commit或者abort APIs。
(11)MRAppMaster退出。
#### 5.3.1 MapReduce編程
編寫在Hadoop中依賴Yarn框架執行的MapReduce程序,并不需要自己開發MRAppMaster和YARNRunner,因為Hadoop已經默認提供通用的YARNRunner和MRAppMaster程序, 大部分情況下只需要編寫相應的Map處理和Reduce處理過程的業務程序即可。
編寫一個MapReduce程序并不復雜,關鍵點在于掌握分布式的編程思想和方法,主要將計算過程分為以下五個步驟:
(1)迭代。遍歷輸入數據,并將之解析成key/value對。
(2)將輸入key/value對映射(map)成另外一些key/value對。
(3)依據key對中間數據進行分組(grouping)。
(4)以組為單位對數據進行歸約(reduce)。
(5)迭代。將最終產生的key/value對保存到輸出文件中。
#### 5.3.2 Java API解析
(1)InputFormat:用于描述輸入數據的格式,常用的為TextInputFormat提供如下兩個功能:
數據切分: 按照某個策略將輸入數據切分成若干個split,以便確定Map Task個數以及對應的split。
為Mapper提供數據:給定某個split,能將其解析成一個個key/value對。
(2)OutputFormat:用于描述輸出數據的格式,它能夠將用戶提供的key/value對寫入特定格式的文件中。
(3)Mapper/Reducer: Mapper/Reducer中封裝了應用程序的數據處理邏輯。
(4)Writable:Hadoop自定義的序列化接口。實現該類的接口可以用作MapReduce過程中的value數據使用。
(5)WritableComparable:在Writable基礎上繼承了Comparable接口,實現該類的接口可以用作MapReduce過程中的key數據使用。(因為key包含了比較排序的操作)。
### 5.4 實驗步驟
本實驗主要分為,確認前期準備,編寫MapReduce程序,打包提交代碼。查看運行結果這幾個步驟,詳細如下:
#### 5.4.1 啟動Hadoop
執行命令啟動前面實驗部署好的Hadoop系統。
~~~
[root@master ~]# cd /usr/cstor/hadoop/
[root@master hadoop]# sbin/start-all.sh
~~~
#### 5.4.2 驗證HDFS上沒有wordcount的文件夾
~~~
[root@client ~]# cd /usr/cstor/hadoop/
[root@client hadoop]# bin/hadoop fs -ls / #查看HDFS上根目錄文件 /
~~~
此時HDFS上應該是沒有wordcount文件夾。
#### 5.4.3 上傳數據文件到HDFS
~~~
[root@client ~]# cd /usr/cstor/hadoop/
[root@client hadoop]# bin/hadoop fs -put /root/data/5/word /
~~~
#### 5.4.4 編寫MapReduce程序
主要編寫Map和Reduce類,其中Map過程需要繼承org.apache.hadoop.mapreduce包中Mapper類,并重寫其map方法;Reduce過程需要繼承org.apache.hadoop.mapreduce包中Reduce類,并重寫其reduce方法。
~~~
import org.apache.hadoop.conf.Configuration;
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.TextInputFormat;
import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;
import org.apache.hadoop.mapreduce.lib.partition.HashPartitioner;
import java.io.IOException;
import java.util.StringTokenizer;
public class WordCount {
public static class TokenizerMapper extends Mapper<Object, Text, Text, IntWritable> {
private final static IntWritable one = new IntWritable(1);
private Text word = new Text();
//map方法,劃分一行文本,讀一個單詞寫出一個<單詞,1>
public void map(Object key, Text value, Context context)throws IOException, InterruptedException {
StringTokenizer itr = new StringTokenizer(value.toString());
while (itr.hasMoreTokens()) {
word.set(itr.nextToken());
context.write(word, one);//寫出<單詞,1>
}}}
//定義reduce類,對相同的單詞,把它們<K,VList>中的VList值全部相加
public static class IntSumReducer extends Reducer<Text, IntWritable, Text, IntWritable> {
private IntWritable result = new IntWritable();
public void reduce(Text key, Iterable<IntWritable> values,Context context)
throws IOException, InterruptedException {
int sum = 0;
for (IntWritable val : values) {
sum += val.get();//相當于<Hello,1><Hello,1>,將兩個1相加
}
result.set(sum);
context.write(key, result);//寫出這個單詞,和這個單詞出現次數<單詞,單詞出現次數>
}}
public static void main(String[] args) throws Exception {//主方法,函數入口
Configuration conf = new Configuration(); //實例化配置文件類
Job job = new Job(conf, "WordCount"); //實例化Job類
job.setInputFormatClass(TextInputFormat.class); //指定使用默認輸入格式類
TextInputFormat.setInputPaths(job, args[0]); //設置待處理文件的位置
job.setJarByClass(WordCount.class); //設置主類名
job.setMapperClass(TokenizerMapper.class); //指定使用上述自定義Map類
job.setCombinerClass(IntSumReducer.class); //指定開啟Combiner函數
job.setMapOutputKeyClass(Text.class); //指定Map類輸出的<K,V>,K類型
job.setMapOutputValueClass(IntWritable.class); //指定Map類輸出的<K,V>,V類型
job.setPartitionerClass(HashPartitioner.class); //指定使用默認的HashPartitioner類
job.setReducerClass(IntSumReducer.class); //指定使用上述自定義Reduce類
job.setNumReduceTasks(Integer.parseInt(args[2])); //指定Reduce個數
job.setOutputKeyClass(Text.class); //指定Reduce類輸出的<K,V>,K類型
job.setOutputValueClass(Text.class); //指定Reduce類輸出的<K,V>,V類型
job.setOutputFormatClass(TextOutputFormat.class); //指定使用默認輸出格式類
TextOutputFormat.setOutputPath(job, new Path(args[1])); //設置輸出結果文件位置
System.exit(job.waitForCompletion(true) ? 0 : 1); //提交任務并監控任務狀態
}
}
~~~
#### 5.3.5 使用Eclipse開發工具將該代碼打包
假定打包后的文件名為hdpAction.jar,主類WordCount位于包njupt下,則可使用如下命令向YARN集群提交本應用。
~~~
[root@client ~]# ./yarn jar hdpAction.jar njupt.WordCount /word /wordcount 1
~~~
其中“yarn”為命令,“jar”為命令參數,后面緊跟打包后的代碼地址,“njupt”為包名,“WordCount”為主類名,“/word”為輸入文件在HDFS中的位置,/wordcount為輸出文件在HDFS中的位置。
### 5.5 實驗結果
#### 5.5.1 程序運行成功控制臺上的顯示內容
如圖5-1所示:

圖5-1 提交wordcount
#### 5.5.2 在HDFS上查看結果
如圖5-2所示:

- GitHub-資源收集
- 【GitHub/Gitee】收錄總榜單
- 【Office & Markdown & PDF】資源收集
- 【前端】資源收集
- 【開源項目】資源收集
- 【代碼備份】資源收集
- 【代碼加密】資源收集
- 【好文章推薦】資源收集
- Java大數據實踐
- 基礎實驗操作
- 【一】基礎操作實驗
- HDFS
- 【二】部署HDFS
- 【三】讀寫HDFS文件
- YARN
- 【四】部署YARN集群
- MapReduce
- 【五】單詞計數
- Hive
- 【十】部署Hive
- 【十一】新建Hive表
- 【十二】Hive分區
- ZooKeeper
- 【二十】部署ZooKeeper
- 【二十一】進程協作
- HBase
- 【二十二】部署HBase
- 【二十三】新建HBase表
- Storm
- 【二十四】部署Storm
- 【二十五】實時WordCountTopology
- Kafka
- 【二十七】Kafka訂閱推送示例
- Redis
- 【二十九】Redis部署與簡單使用
- 【三十】MapReduce與Spark讀寫Redis
- MongoDB
- 【三十一】讀寫MongoDB
- PHP實踐
- 環境搭建
- PHP安裝
- macOS搭建PHP開發環境
- laravel
- 【Laravel-admin】實踐方案
- 技術選型
- 技術選型結果
- PHP開發流程
- Laravel自帶異常
- 技術選型問題 & 解決方法
- 修改(Admin)文件夾路徑
- 兩個用戶表合并
- 創建Token,獲取接口數據
- CreateFreshApiToken中間件使用
- Generator從表生成文件,不包括遷移文件
- 添加用戶的同時生產令牌
- 其它參考文章
- Laravel-admin常見問題
- form(),show()獲取對象數據
- Form右上角按鈕重寫
- form回調中的錯誤提醒,回調傳參
- 【小工具類】實踐方案
- 字符串
- 數組
- 無限級分類遞歸
- 時間
- 正則表達式
- 文件
- 經緯度、時區
- DataEdit快捷操作類庫
- 數據庫表結構管理
- 【Guzzle】實踐方案---工具類
- 【隊列---Laravel-Horizon 】實踐方案
- 【laravel-snappy】實踐方案
- 【開發規范】實踐方案
- PHP深入學習
- 緩存在高并發場景下的常見問題
- 一、緩存一致性問題
- 二、緩存并發問題
- 三、緩存穿透問題
- 四、緩存顛簸問題
- 五、緩存的雪崩現象
- 六、緩存無底洞現象
- Laravel源碼解析(知識點)
- 閉包、IOC容器服務綁定延遲加載
- 延遲靜態綁定基類
- 反射,依賴注入
- __callStatic 魔術方法,Facade 工作原理
- array_reduce,中間件解析
- Eloquent核心
- 線程、進程、協程
- Linux進程、線程、協程
- poll、epoll
- epoll原理
- Liunx線程調度算法
- 紅黑樹
- 同步/異步、阻塞/非阻塞
- PHP-FPM
- Nginx
- Git-PHPStorm-Composer工具使用
- git常用命令
- .gitignore忽略規則
- PHPStorm第一次使用
- PHPStorm關聯gitlab
- 在Docker中使用Xdebug
- PHPStorm中使用Xdebug調試
- PHP Xdebug 遠程調試
- Composer修改鏡像源
- Swoole
- Go
- 驚群問題
- 線程模型比較
- 并發模型比較
- Lua
- OpenResty
- 數據一致性
- 悲觀鎖--VS--樂觀鎖
- 事務--mysql VS redis
- 事務嵌套--Doctrine VS Laravel
- 單體應用中執行順序問題
- 數據一致性問題描述
- 分布式理論
- 數據一致性---接口冪等性
- 分布式事務---2PC VS 3PC
- 分布式事務---TCC
- 分布式事務---基于消息
- 接口安全性
- Nginx
- 優化常識
- nginx常用優化
- nginx解決本地開發時調用遠程AIP跨域問題
- Nginx反向代理實現均衡負載
- 大型網站架構演變
- Keepalived+Nginx 高可用集群(主從模式)
- MySQL
- 關于最重要的參數選項調整建議
- 索引,Explain優化工具
- 事務級別
- sql好的書寫習慣
- limit(分頁)
- 趕集網Mysql36條軍規
- 分庫分表技術演進&最佳實踐
- MariaDB 和 MySQL 全面對比
- 永遠不要在 MySQL 中使用“utf8”
- 看云--推薦的Mysql優化
- 完整、詳細的MySQL規范
- 慢查詢日志
- pt-query-digest結果分析
- Oracle
- Oracle數據庫備份/導出(exp/expd)、導入(imp/impd)
- [Oracle]EXPDP和IMPDP數據泵進行導出導入的方法
- 使用PLSQL進行Oracle數據導入導出
- Redis
- 看云-推薦的redis學習
- Memcache和Redis不同
- 阿里云Redis開發規范
- Centos7
- 虛擬機配置網絡
- 硬盤掛載、分區、文件大小
- 防火墻(firewalld、firewalld-cmd、systemctl、iptables)
- 兩個機器互相拷貝文件
- 查進程、查端口
- 壓縮、解壓
- 查看物理CPU個數、CPU內核數、線程數
- apt-get源--阿里
- Docker
- Dockerfile制作常用命令
- registry私有倉庫
- PHP_7.2
- Dockerfile
- php.ini
- 使用說明
- Nginx_1.15
- Dockerfile
- nginx.conf
- prod_nginx.conf
- 使用說明
- MySql_5.7
- Dockerfile
- my.cnf
- 使用說明
- redmine_3.4
- Dockerfile
- 使用說明
- gitlab-ce_11.9.6-ce.0
- 使用說明
- Redis_5.0
- Dockerfile
- redis.conf
- 使用說明
- Jenkins
- Dockerfile
- 使用說明
- webssh--python3.7
- Dockerfile
- 使用說明
- 進階使用
- 高階使用
- minio
- 使用說明
- aws_cloud9_ide
- 使用說明-aws
- VNC
- 使用說明
- jdk1.8——yum安裝
- tomcat9——安裝
- guacamole——0.9.13
- libreoffice
- Dockerfile
- 使用說明
- Kubernetes
- kubectl常用命令
- 環境搭建(1.9.6)
- kubernetes1.9.6墻內離線部署
- kubernetes1.9.6單機器部署
- helm安裝
- helm常用命令
- Laradock
- Swoole
- 環境的搭建
- swoole的簡單實例
- 服務端的cli方式運行
- 客戶端的運行方式
- 定時任務的入門
- 刪除定時任務
- 初始化定時任務
- 日志管理
- 具體任務的異常捕獲
- 手動重啟shell腳本
- Elasticsearch
- Elasticsearch檢索實踐
- 讀后感
- 【讀書】登天的感覺——岳曉東
- 【讀書】為何家會傷人——武志紅
- 【讀書】思考與致富——拿破侖-希爾
- 【感受】做事講方法
- 【感受】未來暢想
- 【素材】智力問答
- 【百家】曾國藩家訓
- 【百家】正說和珅
- 【感受】談判小技巧
- 【讀書】股票作手回憶錄——利弗莫爾
- 【感受】最幸福的人——工匠
- 【收藏】土味情話大合集
- 【讀書】解憂雜貨店——東野圭吾
- 【讀書】把時間當作朋友——李笑來
- 【感受】輿論和八卦
- 【讀書】老人與海——海明威
- 【讀書】必然——凱文凱利
- 【經典】逍遙游——莊周
- 大模型AI
- OpenAI接入實戰
- DeepSeek接入實戰
- 豆包AI接入實戰
- 百度文心一言接入實戰
- DeepSeek本地化模型部署實戰