- MapReduce入门
- 知识点01:昨日回顾
- 知识点02:今日目标
- 知识点03:MR的功能及应用场景
- 知识点04:MR的运行阶段:Input与Output
- 知识点05:MR的运行阶段:Map
- 知识点06:MR的运行阶段:Shuffle
- 知识点07:MR的运行阶段:Reduce
- 知识点08:WordCount的实现过程解析
- 知识点09:MR的编程规则:类与方法
- 知识点10:MR的编程规则:数据结构与类型
- 知识点11:MR的编程模板:Driver
- 知识点12:MR的编程规则:Mapper与Reducer
- 知识点13:WordCount开发:Driver
- 知识点14:WordCount开发:Mapper与Reducer
- 知识点15:WordCount开发:集群运行及本地运行
- 知识点16:MR实现二手房个数统计
- 练习:使用MR统计各个地区二手房的平均单价
- 附录一:MapReduce编程依赖
苟有恒,何必三更眠五更起;
最无益,莫过一日曝十日寒。
MapReduce入门
知识点01:昨日回顾
- 如果NN只修改内存元数据,NN一旦故障重启,内存元数据丢失?
- 通过记录操作日志的方式来解决
- 将内存中的变化写入edits文件中
- NameNode启动时候,会将fsimage与edits文件进行合并
- SecondaryNameNode的功能是什么?
- 功能:周期性将edits与fsimage文件进行合并生成最新的元数据文件
- NameNode每次启动加载最新的fsimage与最新的edits
- 如何通过Java API构建HDFS连接?如何创建目录、删除文件?如何打开文件和创建文件?
- 类
- FileSystem:文件系统类
- Configuration:配置文件管理
- 方法
- mkdir(path,recursive)
- delete
- open(path) => InputStream
- create(path) => OutputStream
- Hadoop主节点单点故障问题怎么解决?单个NameNode负载较高怎么解决?
- HA高可用机制:多个主节点,但只有一个是Active工作状态的
- 联盟机制:多个主节点,多个主节点一起工作
- 两个NameNode,如何决定谁是Active,谁是Standby,如何实现的?
- 进程:ZKFC
- 功能:监听每个NameNode的状态,实现辅助NameNode的状态向ZK进行注册或者监听
- 实现:每个ZKFC会根据NameNode状态在ZK中创建临时节点,谁创建成功,谁就是Active,Standby要监听这个临时节点
- 只有元数据一致,Active宕机或者故障,Standby才能完整的接替原来的Active,如何保证两个NameNode的内存元数据是一致的?
- 进程:JournalNode集群
- 设计:类似于ZK,可以实现大文件的存储
- 什么是脑裂问题,Hadoop如何解决的?
- 现象:出现两个Active的NameNode
- 原因:Active的ZKFC故障或者因为网络问题
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-M9HxHgJt-1619542590740)(Day07_MapReduce入门.assets/image-20210426093620426.png)] - 解决
- zkfc创建节点:临时节点file1,永久节点file2
- 如果active的zkfc1故障,file1自动删除,file2还在
- zkfc2发现file2还在,就知道NameNode1可能还是Active状态
- zkfc2会让NameNode2成为Active,通过隔离机制将NameNode1强制转换为Standby或者强制下线
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-witUqd3W-1619542590751)(Day07_MapReduce入门.assets/image-20210426094504409.png)]
- 反馈问题
- 想知道HA模式下,如果JournalNode集群出现问题或者死掉了,怎么保证所以数据的安全呢?
- 公平节点
- 每次配置maven环境的包,用的那些类有地方能查看吗?感觉缺少了API用起来有点懵
知识点02:今日目标
- MapReduce介绍
- 功能
- 应用场景
- 运行阶段【核心】
- ||
- 决定了代码的处理逻辑
- MapReduce编程规则
- 本质:一套分布式编程的API
- 类和方法
- 数据结构和数据类型
- ||
- 决定了代码的开发规范
- 案例的开发
- WordCount
- 二手房分析统计
知识点03:MR的功能及应用场景
- 目标:掌握MapReduce的功能及应用场景
- 什么是MapReduce?
- 工作中什么场景下需要使用MapReduce?
- 路径
- step1:MapReduce的功能
- step2:MapReduce的设计思想
- step3:MapReduce的应用场景
- 实施
- MapReduce的功能
- 官方:基于yarn之上的大数据并行计算的框架
- 理解:这是一套分布式编程的API,制定了分布式计算的规则,定义了程序应该怎么分布式运行
- 不用自己写分布式程序,只要调用MapReduce的API写出来的程序就是分布式程序
- 举例
- 需求:1加到9
- |
- 通过MapReduce的API实现处理逻辑:1 +…… + 9
- |
- Mapreduce自动变成分布式程序
- |
- Map阶段
- MapTask1:1+2+3
- MapTask2:4+5+6
- MapTask3:7+8+9
- Reduce阶段
- ReduceTask = MapTask1 + MapTask2 + MapTask3
- MapReduce的设计思想
- 分布式分而治之的思想
- 分:Map阶段
- 合:Reduce阶段
- MapReduce的应用场景
- 适合:离线大数据的分布式计算
- 不适合:实时的高性能的分布式计算场景
- 实际工作中:现在很少使用MapReduce了,都使用Spark来替代了MapReduce
- 哪怕用,也不是直接写代码,一般都是通过SQL自动转换为MapReduce
- 学习MapReduce核心
- 不在于整个MapReduce代码
- 在MapReduce设计思想和实现过程
- 小结
- 什么是MapReduce?
- MapReduce就是一套分布式编程的API
- 工作中什么场景下需要使用MapReduce?
- 一般不写代码,通过SQL来转换为MapReduce,重点掌握MapReduce的设计思想
知识点04:MR的运行阶段:Input与Output
- 目标:掌握MapReduce中Input与Output的功能
- MapReduce运行一共几个阶段?
- MapReduce是如何读取数据的?
- MapReduce是如何保存结果的?
- 路径
- step1:MapReduce的五大阶段
- step2:Input的功能及实现
- step3:Output的功能及实现
- 实施
- MapReduce的五大阶段
- 大的分:Map阶段、Reduce阶段
- 细的分:五大阶段
- Input:负责读取程序中的数据
- Map、Shuffle、Reduce:负责数据的处理
- Output:负责保存计算的结果
- Input的功能及实现
- 功能:负责读取整个程序的输入
- 将文件、数据库中的数据读取到程序中
- 实现:InputFormat
- step1:将读取到的数据进行分片,切分为多个Split
- step2:将每个分片中每一条数据转换为KV结构,返回每条数据
- 不同的实现类返回的KV不一样
- 默认的类:TextInputFormat extends FIleInputFormat extends InputFormat
- 功能:读文件
- 返回
- K:Long:这一行的偏移量
- V:String:这一行的内容
- Output的功能及实现
- 功能:将上一步处理的结果【Map/Reduce】进行保存输出
- 文件、数据库
- 实现:OutputFormat
- step1:调用对应输出类的方法将结果进行方法
- 默认:TextOutputFormat extends FileOutputFormat extends OutputFormat
- 功能:将K和V写入文件中,K和V在文件中用制表符分隔
- 小结
- MapReduce是如何读取数据的?
- 输入类:InputFormat
- 实现功能一:将读取到的数据进行分片
- 实现功能二:将每一条转换为键值对KV结构
- 默认:TextInputFormat
- K:行的偏移量
- V:行的内容
- MapReduce是如何保存结果的?
- 输出类:OutputFormat
- 实现功能:将上一步处理的结果KV结构进行保存
- 默认:TextOutputFormat
- 将结果的KV写入文件
- K与V用制表符分隔
知识点05:MR的运行阶段:Map
- 目标:掌握MapReduce中Map的功能
- Map的功能是什么?
- Map过程是如何实现的?
- 路径
- step1:Map的功能
- step2:Map实现的过程
- 实施
- Map的功能
- 功能:实现分布式计算的分
- Map实现的过程
- step1:根据Input阶段划分的Split,每个Split会启动一个MapTask进程来处理对应Split的数据
- MapTask处理每个分片中的KV结构的数据
- step2:每个MapTask进程会构建一个Mapper类实例,调用Mapper类中的map方法对每个分片的数据进行处理
- 处理逻辑:Mapper类的map方法决定,每一条KV会调用一次map方法
- 参数:KV
- 小结
- Map阶段的功能是什么?
- 实现分布式的分
- Map过程是如何实现的?
- 每个Split会启动一个MapTask进行处理
- 每个MapTask进程会实例化一个Mapper类的对象,代用Mapper类的map方法对分片中的每一条数据进行处理
知识点06:MR的运行阶段:Shuffle
- 目标:了解MapReduce中Shuffle的功能
- 实施
- 功能:对Map以后的数据进行分组处理,MapReduce中定死的过程
- 分区
- 排序
- 分组
- 实现目的:分布式的分组
- 前面的过程
- Input
- 读取数据,返回KV
- K1V1
- Map
- 输入:K1V1
- 输出:K2V2
- 排序:默认按照K2进行升序排序
- 排序是为了加快分组的效率
- 不排序
1
2
3
4
1
2
3
4
- 排序
1
1
2
2
3
3
4
4
- 分组:默认按照K2进行分组
- 相同K2 的所有V2在逻辑上属于同一组
- 小结
- Shuffle的功能是什么?
- 功能:分区、排序、分组
- 排序:按照K2升序排序
- 分组:按照K2分组
知识点07:MR的运行阶段:Reduce
- 目标:掌握MapReduce中Reduce的功能
- Reduce的功能是什么?
- Reduce过程是如何实现的?
- 路径
- step1:Reduce的功能
- step2:Reduce实现的过程
- 实施
- Reduce的功能
- 实现分布式的合的
- 理解:Reduce就是一个没有定义的功能的聚合函数,将所有Map的数据的进行聚合
- Reduce实现的过程
- step1:默认情况会启动1个ReduceTask进程对Shuffle逻辑分组以后的结果进行聚合
- step2:ReduceTask会实例化一个Reducer的类的对象,调用reduce方法对每一组数据进行聚合
- 聚合的逻辑:由reduce方法决定
- 小结
- Reduce的功能是什么?
- 实现分布式的合,将所有Map的数据进行聚合
- Reduce过程是如何实现的?
- 启动ReduceTask进程,默认只启动1个
- 实例化Reducer类的对象,调用reduce方法实现聚合,每一组调用一次
知识点08:WordCount的实现过程解析
- 目标:掌握MR计算WordCount的实现过程
- 实施
- HDFS输入文件:wordcount.txt
hadoop hive spark
hbase hadoop hadoop
spark hive
hbase hadoop spark
- Input
- 默认:TextInputFormat
- step1:将数据分片
- split1
hadoop hive spark
hbase hadoop hadoop
- split2
spark hive
hbase hadoop spark
- step2:转换为K1V1
- split1
K V
0 hadoop hive spark
33 hbase hadoop hadoop
- split2
K V
0 spark hive
20 hbase hadoop spark
- Map
- 读取K1V1
- 处理
- MapTask1 => Split1
- MapTask2 => Split2
- 对每条数据调用map方法
public void map(Long K1,String V1){
String[] words = V1.split(" ")
for(word:words){
output(word,1)
}
}
- 输出K2V2
- MapTask1
K2 V2
hadoop 1
hive 1
spark 1
hbase 1
hadoop 1
hadoop 1
- MapTask2
spark 1
hive 1
hbase 1
hadoop 1
spark 1
- Shuffle
- 排序:按照K2排序
hadoop 1
hadoop 1
hadoop 1
hadoop 1
hbase 1
hbase 1
hive 1
hive 1
spark 1
spark 1
spark 1
- 分组:按照K2分组,结果是按照单词分组,所以K2是单词
hadoop <1,1,1,1>
hbase <1,1>
hive <1,1>
spark <1,1,1>
- Reduce
- 读取分组的K2V2
- 聚合处理:reduce
public void reduce(String k2,Iter<V2> value){
sum = 0
for(int v : value){
sum += v
}
output(K2,sum)
}
- 输出K3V3
K3 V3
hadoop 4
hbase 2
hive 2
spark 3
- Output
- 默认:TextOutputFormat
- 将K3V3保存
- HDFS结果文件:part-r-00000
hadoop 4
hbase 2
hive 2
spark 3
- 小结
- 掌握每个过程中的每个阶段的功能与结果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aGWSAicK-1619542590759)(Day07_MapReduce入门.assets/image-20210426115158044.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pbELxF9O-1619542590762)(Day07_MapReduce入门.assets/image-20210426115313837.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-f3XM8WSe-1619542590764)(Day07_MapReduce入门.assets/image-20210426115613761.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tKhqT9xJ-1619542590766)(Day07_MapReduce入门.assets/image-20210426115710122.png)]
知识点09:MR的编程规则:类与方法
- 目标:掌握MR编程规则中的类与方法
- MapReduce的API中会用到哪些类和方法?
- 路径
- step1:Driver类
- step2:Input类
- step3:Mapper类
- step4:Reducer类
- step5:Output类
- 实施
- Driver类
- 驱动类:作为程序运行的入口类
- 规则:推荐extends Configured implement Tool
- 方法
- main:作为程序的运行入口
- run:用于构建、配置、提交MapReduce Job
- 要自己开发
- Input类
- 输入:InputFormat
- 默认:TextInputFormat,读文件,K1是行的偏移量,V1是行的内容
- 其他
- DBInputFormat:读数据库的
- TableInputFormatFormat:读Hbase
- 不用自己开发
- Mapper类
- 功能:在Map阶段,构建实例化,调用map方法对数据进行处理
- 规则:必须 extends Mapper
- 方法:重写map方法
- 要自己开发
- Reducer类
- 功能:在Reduce阶段,构建实例化,调用reduce方法对数据进行处理
- 规则:必须 extends Reducer
- 方法:重写reduce方法
- 要自己开发
- Output类
- 输出:OutputFormat
- 默认:TextOutputFormat,写文件,将K3和V3保存到文件中
- 其他
- DBOutputFormat:写数据库
- TableOutputFormat:写Hbase
- 不要自己写
- 小结
- MapReduce的API中会用到哪些类和方法?
知识点10:MR的编程规则:数据结构与类型
- 目标:掌握MR编程规则中的数据结构与数据类型
- MapReduce中的数据以什么结构存在?
- MapReduce中的数据以什么类型存储?
- 路径
- step1:MR中的数据结构
- step2:MR中的数据类型
- 实施
- MR中的数据结构
- 键值对:所有的数据都以KV形式存在
- Input:将各种数据变成K1V1
- Map:读K1V1输出K2V2
- Reduce:读K2V2输出K3V3
- Output:保存K3V3
- MR中的数据类型
- Hadoop中使用的类型不能使用Java中原生的基本类型和引用类型,因为Hadoop中的类型必须支持序列化
- 分布式计算:对象的网络传递,必须支持序列化
- Hadoop中自带了很多的序列化类型,用于提供
- Java:int、String、long、double、Boolean、null
- Hadoop
- IntWritable
- Text
- LongWritable
- DbouleWritable
- BooleanWritable
- NullWritable
- 小结
- MapReduce中的数据以什么结构存在?
- KV结构
- MapReduce中的数据以什么类型存储?
- 所有KV必须使用Hadoop中的序列化类型
知识点11:MR的编程模板:Driver
- 目标:实现MR编程模板中Driver类的开发
- 实施
package bigdata.itcast.cn.hadoop.mr.mode;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.conf.Configured;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.TextInputFormat;
import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;
import org.apache.hadoop.util.Tool;
import org.apache.hadoop.util.ToolRunner;
/**
* @ClassName MRDriverMode
* @Description TODO MapReduce编程模板,Driver类
* @Date 2021/4/26 14:31
* @Create By Frank
*/
public class MRDriverMode extends Configured implements Tool {
//构建、配置、提交Job
public int run(String[] args) throws Exception {
/**
* step1:构建Job
*/
//实例化一个MapReduce的Job对象
Job job = Job.getInstance(this.getConf(),"mode");
//指定允许jar包运行的类
job.setJarByClass(MRDriverMode.class);
/**
* step2:配置Job
*/
//Input:配置输入
//指定输入类的类型
job.setInputFormatClass(TextInputFormat.class);//可以不指定,默认就是TextInputFormat
//指定输入源
Path inputPath = new Path(args[0]);//使用第一个参数作为程序的输入
TextInputFormat.setInputPaths(job,inputPath);
//Map:配置Map
job.setMapperClass(MRMapperMode.class); //设置调用的Mapper类
job.setMapOutputKeyClass(Text.class); //设置K2的类型
job.setMapOutputValueClass(Text.class); //设置V2的类型
//Shuffle:配置Shuffle
// job.setPartitionerClass(null); //设置分区器
// job.setSortComparatorClass(null); //设置排序器
// job.setGroupingComparatorClass(null); //设置分组器
// job.setCombinerClass(null); //设置Map端聚合
//Reduce:配置Reduce
job.setReducerClass(MRReducerMode.class); //设置调用reduce的类
job.setOutputKeyClass(Text.class); //设置K3的类型
job.setOutputValueClass(Text.class); //设置V3的类型
// job.setNumReduceTasks(1); //设置ReduceTask的个数,默认为1
//Output:配置输出
//指定输出类的类型
job.setOutputFormatClass(TextOutputFormat.class);//默认就是TextOutputFormat
//设置输出的路径
Path outputPath = new Path(args[1]);
//判断输出是否存在,存在就删除
FileSystem fs = FileSystem.get(this.getConf());
if(fs.exists(outputPath)){
fs.delete(outputPath,true);
}
TextOutputFormat.setOutputPath(job,outputPath);
/**
* step3:提交Job
*/
return job.waitForCompletion(true) ? 0 : -1;
}
//程序的入口方法
public static void main(String[] args) throws Exception {
//构建配置管理对象
Configuration conf = new Configuration();
//通过工具类的run方法调用当前类的实例的run方法
int status = ToolRunner.run(conf, new MRDriverMode(), args);
//退出程序
System.exit(status);
}
}
- 小结
- Driver类的开发规则是什么?
- 继承Configured
- 实现Tool
- 需要实现哪些方法?
- main:程序入口,调用run方法
- run:构建、配置、提交Job
知识点12:MR的编程规则:Mapper与Reducer
- 目标:实现MR编程模板中Mapper类和Reducer类的开发
- 实施
- Mapper类
package bigdata.itcast.cn.hadoop.mr.mode;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;
import java.io.IOException;
/**
* @ClassName MRMapperMode
* @Description TODO MapReduce模板 - Mapper类
* Mapper<KEYIN, VALUEIN, KEYOUT, VALUEOUT>
* 输入的KV类型:由输入类的类型决定
* KEYIN
* VALUEIN
* 输出的KV类型:由map方法
* KEYOUT
* VALUEOUT
* @Date 2021/4/26 15:08
* @Create By Frank
*/
public class MRMapperMode extends Mapper<LongWritable, Text,Text,Text> {
/**
* 每一条K1V1会调用一次map方法,实现处理,得到K2V2
* @param key:K1
* @param value:V1
* @param context:上下文对象,负责管理整个程序的数据传递等等
* @throws IOException
* @throws InterruptedException
*/
@Override
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
//处理的逻辑由实际的需求决定
}
}
- Reduce类
package bigdata.itcast.cn.hadoop.mr.mode;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;
import java.io.IOException;
/**
* @ClassName MRMapperMode
* @Description TODO MapReduce模板 - Mapper类
* Mapper<KEYIN, VALUEIN, KEYOUT, VALUEOUT>
* 输入的KV类型:由输入类的类型决定
* KEYIN
* VALUEIN
* 输出的KV类型:由map方法
* KEYOUT
* VALUEOUT
* @Date 2021/4/26 15:08
* @Create By Frank
*/
public class MRMapperMode extends Mapper<LongWritable, Text,Text,Text> {
/**
* 每一条K1V1会调用一次map方法,实现处理,得到K2V2
* @param key:K1
* @param value:V1
* @param context:上下文对象,负责管理整个程序的数据传递等等
* @throws IOException
* @throws InterruptedException
*/
@Override
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
//处理的逻辑由实际的需求决定
}
}
- 小结
- Mapper类的规则是什么以及要实现什么方法?
- 继承Mapper类,重写map(k1,v1,context)方法
- Reducer类的规则是什么以及要实现什么方法?
- 继承Reduce类,重写reduce(k2,Iter,context)方法
知识点13:WordCount开发:Driver
- 目标:实现WordCount程序中Driver类的开发
- 实施
package bigdata.itcast.cn.hadoop.mr.wordcount;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.conf.Configured;
import org.apache.hadoop.fs.FileSystem;
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.lib.input.TextInputFormat;
import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;
import org.apache.hadoop.util.Tool;
import org.apache.hadoop.util.ToolRunner;
/**
* @ClassName WordCountDriver
* @Description TODO 自定义开发程序实现Wordcount词频统计
* @Date 2021/4/26 15:33
* @Create By Frank
*/
public class WordCountDriver extends Configured implements Tool {
public int run(String[] args) throws Exception {
//构建
Job job = Job.getInstance(this.getConf(),"userwc");
job.setJarByClass(WordCountDriver.class);
//配置
job.setInputFormatClass(TextInputFormat.class);
//使用程序的第一个参数作为输入
TextInputFormat.setInputPaths(job,new Path(args[0]));
job.setMapperClass(WordCountMapper.class);
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(IntWritable.class);
job.setReducerClass(WordCountReducer.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
job.setOutputFormatClass(TextOutputFormat.class);
//使用程序的第二个参数作为输出路径
Path outputPath = new Path(args[1]);
FileSystem fs = FileSystem.get(this.getConf());
if(fs.exists(outputPath)){
fs.delete(outputPath,true);
}
TextOutputFormat.setOutputPath(job,outputPath);
//提交
return job.waitForCompletion(true) ? 0 : -1;
}
public static void main(String[] args) throws Exception {
Configuration conf = new Configuration();
int status = ToolRunner.run(conf, new WordCountDriver(), args);
System.exit(status);
}
}
- 小结
- 参考代码实现即可
知识点14:WordCount开发:Mapper与Reducer
- 目标:实现WordCount程序中Mapper类和Reducer类的开发
- 实施
- Mapper类
package bigdata.itcast.cn.hadoop.mr.wordcount;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;
import java.io.IOException;
/**
* @ClassName WordCountMapper
* @Description TODO Wordcount Mapper类
* @Date 2021/4/26 15:44
* @Create By Frank
*/
public class WordCountMapper extends Mapper<LongWritable, Text,Text, IntWritable> {
//输出的K2
Text outputKey = new Text();
//输出的V2
IntWritable outputValue = new IntWritable(1);
/**
* 每条KV调用一次map
* @param key:行的偏移量
* @param value:行的内容
* @param context
* @throws IOException
* @throws InterruptedException
*/
@Override
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
//将每行的内容分割得到每个单词
String[] words = value.toString().split("\\s+");
//迭代取出每个单词作为K2
for (String word : words) {
//将当前的单词作为K2
this.outputKey.set(word);
//将K2和V2传递到下一步
context.write(outputKey,outputValue);
}
}
}
- Reducer类
package bigdata.itcast.cn.hadoop.mr.wordcount;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;
import java.io.IOException;
/**
* @ClassName WordCountReducer
* @Description TODO 自定义开发WordCount -Reducer
* @Date 2021/4/26 15:52
* @Create By Frank
*/
public class WordCountReducer extends Reducer<Text, IntWritable,Text, IntWritable> {
//输出K3
// Text outputKey = new Text();
//输出V3
IntWritable outputValue = new IntWritable();
/**
* 每一组调用一次
* @param key:单词
* @param values:所有相同单词对应的1
* @param context
* @throws IOException
* @throws InterruptedException
*/
@Override
protected void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
int sum = 0;
for (IntWritable value : values) {
//取出当前单词所有 1,进行累加
sum += value.get();
}
//给V3赋值
this.outputValue.set(sum);
//传递到下一步
context.write(key,this.outputValue);
}
}
- 小结
- 参考代码实现即可
知识点15:WordCount开发:集群运行及本地运行
- 目标:实现WordCount程序的集群运行及本地环境测试运行
- 开发好的程序如何运行?
- 开发过程中如何做测试运行?
- 路径
- step1:集群模式分布式运行
- step2:本地模式测试运行
- 实施
- 集群模式分布式运行
- 打成jar包
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-P8IeWIJC-1619542590768)(Day07_MapReduce入门.assets/image-20210426160112092.png)] - 上传到Linux中
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Jh9ADcRl-1619542590769)(Day07_MapReduce入门.assets/image-20210426160144284.png)] - 使用yarn的客户端来提交运行
- yarn语法
yarn jar 运行jar包的位置 你要运行的类 【类的参数】
- 实现
yarn jar /export/data/wordcount.jar bigdata.itcast.cn.hadoop.mr.wordcount.WordCountDriver /wordcount/input/wordcount.txt /wordcount/output4
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kk4fSHQN-1619542590770)(Day07_MapReduce入门.assets/image-20210426160533159.png)]
- 本地模式测试运行
- step1:先配置本地环境:参考HDFS环境配置
- step2:直接右键单击运行
- 注意:如果将三个类放在一个文件中定义,Mapper和Reducer必须申明为static【硬性规定】
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Wvi3s7wx-1619542590771)(Day07_MapReduce入门.assets/image-20210426161436569.png)]
- 小结
- 开发好的程序如何运行?
- 打成jar包集群分布式运行
- 开发过程中如何做测试运行?
- 先本地测试
- 再打包集群运行测试
知识点16:MR实现二手房个数统计
- 目标:基于Mr实现各地区二手房个数的统计
- 路径
- step1:分析需求
- step2:代码实现
- 实施
- 分析需求
- 基于Mr实现各地区二手房个数的统计
- step1:结果长什么样?
地区 个数
杨浦 300
虹口 400
……
- step2:K2是谁
- 经过shuffle:只有K2才会被分区
- K2:地区
- step3:V2是谁
- 标记为1,表示这个地区出现一套二手房
- 代码实现
package bigdata.itcast.cn.hadoop.mr.secondhouse;
import bigdata.itcast.cn.hadoop.mr.mode.MRMapperMode;
import bigdata.itcast.cn.hadoop.mr.mode.MRReducerMode;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.conf.Configured;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
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.TextInputFormat;
import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;
import org.apache.hadoop.util.Tool;
import org.apache.hadoop.util.ToolRunner;
import java.io.IOException;
/**
* @ClassName MRDriverMode
* @Description TODO 各个地区二手房个数统计
* @Date 2021/4/26 14:31
* @Create By Frank
*/
public class SecondHouseCount extends Configured implements Tool {
//构建、配置、提交Job
public int run(String[] args) throws Exception {
/**
* step1:构建Job
*/
//实例化一个MapReduce的Job对象
Job job = Job.getInstance(this.getConf(),"second house numb");
//指定允许jar包运行的类
job.setJarByClass(SecondHouseCount.class);
/**
* step2:配置Job
*/
//Input:配置输入
//指定输入类的类型
job.setInputFormatClass(TextInputFormat.class);//可以不指定,默认就是TextInputFormat
//指定输入源
Path inputPath = new Path("datas/lianjia/secondhouse.csv");//使用第一个参数作为程序的输入
TextInputFormat.setInputPaths(job,inputPath);
//Map:配置Map
job.setMapperClass(SecondMapper.class); //设置调用的Mapper类
job.setMapOutputKeyClass(Text.class); //设置K2的类型
job.setMapOutputValueClass(IntWritable.class); //设置V2的类型
//Shuffle:配置Shuffle
// job.setPartitionerClass(null); //设置分区器
// job.setSortComparatorClass(null); //设置排序器
// job.setGroupingComparatorClass(null); //设置分组器
// job.setCombinerClass(null); //设置Map端聚合
//Reduce:配置Reduce
job.setReducerClass(SecondReducer.class); //设置调用reduce的类
job.setOutputKeyClass(Text.class); //设置K3的类型
job.setOutputValueClass(IntWritable.class); //设置V3的类型
// job.setNumReduceTasks(1); //设置ReduceTask的个数,默认为1
//Output:配置输出
//指定输出类的类型
job.setOutputFormatClass(TextOutputFormat.class);//默认就是TextOutputFormat
//设置输出的路径
Path outputPath = new Path("datas/output/second/output1");
//判断输出是否存在,存在就删除
FileSystem fs = FileSystem.get(this.getConf());
if(fs.exists(outputPath)){
fs.delete(outputPath,true);
}
TextOutputFormat.setOutputPath(job,outputPath);
/**
* step3:提交Job
*/
return job.waitForCompletion(true) ? 0 : -1;
}
//程序的入口方法
public static void main(String[] args) throws Exception {
//构建配置管理对象
Configuration conf = new Configuration();
//通过工具类的run方法调用当前类的实例的run方法
int status = ToolRunner.run(conf, new SecondHouseCount(), args);
//退出程序
System.exit(status);
}
public static class SecondMapper extends Mapper<LongWritable,Text,Text,IntWritable>{
//K2
Text outputKey = new Text();
//V2
IntWritable outputValue = new IntWritable(1);
//梅园六街坊,2室0厅,47.72,浦东,低区/6层,朝南,500,104777,1992年建
@Override
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
//取出地区
String region = value.toString().split(",")[3];
//地区作为K2
this.outputKey.set(region);
//输出
context.write(this.outputKey,this.outputValue);
}
}
public static class SecondReducer extends Reducer<Text,IntWritable,Text,IntWritable>{
//V3
IntWritable outputValue = 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();
}
this.outputValue.set(sum);
context.write(key,this.outputValue);
}
}
}
- 小结
- 核心掌握MapReduce的五大阶段的功能
练习:使用MR统计各个地区二手房的平均单价
附录一:MapReduce编程依赖
<dependencies>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-common</artifactId>
<version>2.7.5</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
<version>2.7.5</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-hdfs</artifactId>
<version>2.7.5</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-mapreduce-client-core</artifactId>
<version>2.7.5</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
</dependency>
</dependencies>