1.1、MapReduce定义
(1)、MapReduce是一个分布式运算程序的编程框架,是用户开发“基于Hadoop的数据分析应用”的核心框架。
(2)、MapReduce核心功能是将用户编写的业务逻辑代码和自带默认组件整合成一个完整的分布式运算程序,并发运行在一个Hadoop集群上。
1.2、MapReduce优缺点
1.2.1 优点
(1)易于编程
它简单的实现一些接口,就可以完成一个分布式程序,用户只需要根据自己业务逻辑写出代码,结合自身默认代码即可。
(2)良好的拓展性
可动态增加服务器来扩展它的计算能力,解决计算资源不足的问题
(3)高容错性
MapReduce能够部署在廉价的机器上,一台机器挂了,他可以把上面的计算任务转移到另外一个节点上运行,保证任务正常运行。这个过程不需要人工参与,而完全由Hadoop内部完成。
(4)适合PB级以上的以上的海量数据的离线处理
可以实现上千台服务器集群并发工作,提供数据处理能力
1.2.2 缺点
(1)、不擅长实时计算(MySQL擅长)
MapReduce无法像MySQL一样,在毫秒或者秒级内返回结果
(2)、不擅长流式计算(flink擅长)
流式计算输入数据是动态的,而MapReduce的输入数据集是静态的,不能动态变化,这是因为MapReduce自身的设计特点决定了数据源必须是静态的
(3)、不擅长DAG(有向无环图)计算(spark擅长)
多个应用程序存在依赖关系,后一个应用程序的输入为前一个的输出。在这种情况下,MapReduce并不是不能做,而是使用后,每个MapReduce作业的输出结果都会写入到磁盘,会造成大量的磁盘IO,到最后性能非常的低下。
1.3、MapReduce核心编程思想
1.图解
(1)分布式的运算程序往往需要分成至少 2 个阶段。
(2)第一个阶段的 MapTask 并发实例,完全并行运行,互不相干。
(3)第二个阶段的 ReduceTask 并发实例互不相干,但是他们的数据依赖于上一个阶段的所有 MapTask 并发实例的输出。
(4)MapReduce 编程模型只能包含一个 Map 阶段和一个 Reduce 阶段,如果用户的业务逻辑非常复杂,那就只能多个 MapReduce 程序,串行运行。
1.4、MapReduce 进程
(1) MrAppMaster:负责整个程序的过程调度及状态协调。(是YARN中AppMaster的子进程)
(2) MapTask:负责 Map 阶段的整个数据处理流程。
(3) ReduceTask:负责 Reduce 阶段的整个数据处理流程
1.5、官方 WordCount 源码
采用反编译工具(jd-gui)反编译源码,发现 WordCount 案例有 Map 类、Reduce 类和驱动类。且数据的类型是 Hadoop 自身封装的序列化类型。
展开jar包,找到自己需要的案例,我们分析wordcount这个案例源码:
打开如下:
1.driver类(1驱动代码):是主方法,也是程序的入口
2.reducer类:
3.mapper类:
这三个类似固定写法
1.6、常用数据序列化类型
Java 类型 | Hadoop Writable 类型 |
---|---|
Boolean | BooleanWritable |
Byte | ByteWritable |
Int | IntWritable |
Float | FloatWritable |
Long | LongWritable |
Double | DoubleWritable |
String | Text |
Map | MapWritable |
Array | ArrayWritable |
Null | NullWritable |
1.7、MapReduce 编程规范
用户编写的程序分成三个部分:Mapper、Reducer 和 Driver
1.7.1 Mapper阶段
(1)用户自定义的Mapper要继承自己的父类
(2)Mapper的输入数据是KV对(K,V)的形式(KV的类型可自定义)
K:是一行的偏移量
V:这一行的内容
(3)Mapper中的业务逻辑写在map()方法中
(4)Mapper的输出数据是KV对的形式(KV的类型可自定义)
(5)map()方法(MapTask进程)对每一个<K,V>调用一次
- 输入数据每一行内容都会进入map()方法一次,有多少行数据,就会调用多少次<k,v>(比如有5行数据,就调用5次map()方法,5次kv对)
1.7.2 Reducer阶段
(1)用户自定义的Reducer要继承自己的父类
(2) Reducer的输入数据类型对应Mapper的输出数据类型,也是KV(Mapper阶段结束后,把数据给Reducer,所以Mapper输出的KV就相当于Reducer输入的KV )
(3) Reducer的业务逻辑写在reduce()方法中
(4) ReduceTask进程对每一组相同k的<k,v>组调用一次reduce()方法
1.7.3 Driver阶段
相当于YARN集群的客户端,用于提交我们整个程序到YARN集群,提交的是 封装了MapReduce程序相关运行参数的job对象
将MR程序提交到YARN进行运行
1.8 WordCount 案例实操
1.8.1 本地测试
1)需求
在给定的文本文件中统计输出每一个单词出现的总次数
(1)新建txt文本文件,输入数据:
pcz pcz
love
study
fighting
fighting
for for
you
(2)期望输出数据
for 2
fighting 2
love 1
pcz 2
study 1
you 1
2)需求分析
按照 MapReduce 编程规范,分别编写 Mapper,Reducer,Driver。
3)环境准备
(1)使用IDEA创建 maven 工程,MapReduceDemo
(2)在 pom.xml 文件中的<project> <project>
之间添加如下依赖
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
<version>3.1.4</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-hdfs</artifactId>
<version>3.1.4</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-hdfs-client</artifactId>
<version>3.1.4</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.30</version>
</dependency>
</dependencies>
(3)在项目的 src/main/resources 目录下,新建一个文件,命名为“log4j.properties”,在文件中填入
log4j.rootLogger=INFO, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n
log4j.appender.logfile=org.apache.log4j.FileAppender
log4j.appender.logfile.File=target/spring.log
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n
(4)、在创好的工程的java目录下新建包,包名:com.pcz.mapreduce.wordcount
(5)、新建三个类:
4)编写程序
mapper–>mapshuffle(排序和规约)–>reduceshuffle(排序和分组)–>reducer
—>driver
(1)、编写Mapper类
package com.pcz.mapreduce.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;
/*
KEYIN,map阶段输入的key的类型,LongWritable
VALUE,map阶段输入value类型:Text
KEYOUT,map阶段输出key类型:Text
VALUEOUT,map阶段输出的value类型:IntWritable/LongWritable
*/
public class WordCountMapper extends Mapper<LongWritable,Text,Text,IntWritable> {
private Text outK = new Text(); //本来放在单词转换那里,移动到这可跳过循环,提高效率
private IntWritable outV=new IntWritable(1);
@Override
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
//1.获取txt文本的一行
//pcz pcz
String line = value.toString();
//2.切割
/*
读出来的数据为:
pcz
pcz
*/
String[] words = line.split(" ");
//3.循环写出
for (String word : words) { //循环每一行
//封装outK
outK.set(word);
//写出
/*
<pcz,1>
<pcz,1>
....
*/
context.write(outK,outV);
}
}
}
(2)、编写 Reducer 类
package com.pcz.mapreduce.wordcount;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;
import java.io.IOException;
/*
KEYIN,reducer阶段输入的key的类型,Text
VALUE,reducer阶段输入value类型:IntWritable
KEYOUT,reducer阶段输出key类型:Text
VALUEOUT,reducer阶段输出的value类型:IntWritable/LongWritable
*/
public class WordCountReducer extends Reducer<Text, IntWritable,Text,IntWritable> {
private IntWritable outV = new IntWritable();
@Override
protected void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
/*
mapper阶段后,通过shuffle阶段(内部执行,不需要人为操作,按字母排序)传进来的数据:
pcz <1,1>
love <1>
study <1>
fighting <1,1>
for <1,1>
you <1>
*/
int sum = 0;
//累加v的值
for (IntWritable value : values) {
sum += value.get();
}
//封装outV
outV.set(sum);
//写出
//context是一个上下文对象,连接着mapper和reducer以及跟系统的一些信息交互传递
context.write(key, outV);
}
}
(3)编写 Driver 驱动类
package com.pcz.mapreduce.wordcount;
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.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import java.io.IOException;
public class WordCountDriver {
public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
//1.获取job
Configuration conf = new Configuration();
Job job = Job.getInstance(conf);
//2.设置jar包路径
job.setJarByClass(WordCountDriver.class);
//3.关联mapper和reducer
job.setMapperClass(WordCountMapper.class);
job.setReducerClass(WordCountReducer.class);
//4.设置map输出的KV类型
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(IntWritable.class);
//5.设置最终输出的KV类型
job.setOutputKeyClass(Text.class);
job.setOutputKeyClass(IntWritable.class);
//6.设置输入路径和输出路径
FileInputFormat.setInputPaths(job,new Path("P:\\hadoop maven test\\input\\inputword"));
FileOutputFormat.setOutputPath(job,new Path("P:\\hadoop maven test\\output"));
//7.提交job
boolean result = job.waitForCompletion(true);
System.exit(result ? 0 : 1);
}
}
Eclipse下操作:
[实训六 自行编写单词记数案例 .docx](…/…/_resources/实训六 自行编写单词记数案例.docx)
eclipse自行计数案例文档
5)本地测试(只是在本地运行,并没有在hadoop集群里面运行)
(1)需要首先配置好 HADOOP_HOME 变量以及 Windows 运行依赖
(2)在 IDEA/Eclipse 上运行程序
5.1)Debug调试(此过程可熟悉MapReduce一个job的执行过程)
1.打断点
(1)、WordCountMapper中
(2)、Mapper中(选中Mapper,然后按Ctrl+B)
(3)、WordCountReducer中
(4)、Reducer中(选中Reducer,按Ctrl+B)
2.调试按钮讲解
3.开始调试
4.调试过程
在补充里面,需查看
1.8.2 提交到集群测试
集群上测试
(1)用 maven 打 jar 包,需要添加的打包插件依赖到pom.xml
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
注意:如果工程上显示红叉。在项目上右键->maven->Reimport 刷新即可
(2)将程序打成 jar 包
( 3 ) 修改不带依赖的 jar 包名称为iwordcount01.jar, 并拷贝该 jar 包到 Hadoop 集群的/opt/test/idea路径。
(4)启动 Hadoop 集群
pczhd start
(5)在hdfs中新建一个input文件夹 ,把需要计数的文件放在input里面
[root@master data]# hadoop fs -mkdir /input
[root@master data]# hadoop fs -put pcztest.txt /input
(6)执行 WordCount 程序
方式一(无依赖的jar):
hadoop jar iwordcount01.jar com.pcz.mapreduce.wordcount02hdfs.WordCountDriver /input /output07
方式二(无依赖的jar):
hadoop jar iwordcount01.jar com.pcz.mapreduce.wordcount02hdfs/WordCountDriver /input/pcztest.txt /output/output01
方式三(有依赖的jar)
可参考eclipse文件单词计数案例
[实训五 eclipse运行WordCount单词记数案例.docx](…/…/_resources/实训五 eclipse运行WordCount单词记数案例.docx)
运行成功:
查看:集群master:9870->Utilities->Browser the file system,点击查看
补充:类的全类名查看方法: