说明
1. HDFS先挖个坑,以后再补。
2. 本篇第一到第七点是对MapReduce从应用层面上进行简介,而不涉及具体的实现;
3. 第八点内容是编写WordCount的MapReduce程序,并在本机和Hadoop集群上分别启动的全部过程。
4. 如果你已经了解了MapReduce的基本内容,想要快速上手MapReduce的具体案例,那么可以只看第八点。
5. 但是如果有时间的话,还是建议先了解MapReduce的核心思想(第二、三点),以便更好地理解MapReduce的实现过程,对于以后的学习也十分重要。
6. 五、六、七点是编写MapReduce程序前需要了解的预备知识,如果想自己编写MapReduce程序,那么也应当了解一下。
声明:本篇博客是基于尚硅谷的Hadoop2.x教学系列,记录自己进行复现的过程。
教程链接:【尚硅谷】Hadoop2.x框架入门教程丨案例实战,好评如潮_哔哩哔哩_bilibili
Maven相关的内容可以通过另一篇博客快速了解:补充:Maven基础(Windows)_Slothwolf的博客-CSDN博客
目录
一、MapReduce是什么
MapReduce是一个分布式运算程序的编程框架,是用户开发“基于Hadoop的数据分析应用”的核心框架。
MapReduce的核心功能是将用户编写的业务逻辑代码和默认组件组合成一个完整的分布式运算逻辑,并发运行在一个Hadoop集群上。
二、核心思想
MapReduce程序一般分为两个阶段:Map阶段和Reduce阶段。
Map阶段的并发MapTask,完全并行,互相不相干。
Map阶段的四个步骤:
Reduce阶段的并发ReduceTask,完全互不相干,但他们的数据依赖于上一个阶段的所有MapTask并发实例的输出。
三、总览
MapReduce编程模型只能包含一个Map阶段和一个Reduce阶段,如果用户的业务逻辑非常复杂,那么就只能多个MapReduce程序串行运行。
四、需要解决的问题
五、MapReduce进程
六、Hadoop中的数据序列化类型
七、MapReduce编程规范
用户编写的程序分为三个部分:Mapper、Reducer、Driver
(1)Mapper阶段
(2)Reducer阶段
(3)Driver阶段
八、WordCount案例实操
0、安装IDEA并配置Maven
可以用Windows,也可以用Linux。
Centos7安装并使用IntelliJ IDEA_centos7安装idea_sugar_hang的博客-CSDN博客
1、新建一个Maven工程
2、在pom.xml中添加依赖
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>RELEASE</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.8.2</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-common</artifactId>
<version>2.7.6</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
<version>2.7.6</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-hdfs</artifactId>
<version>2.7.6</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、创建包
在src/main/java下创建com.wolf.mr.wordcount包,我们要写三个java类放进去,分别是WordcountMapper、WordcountReducer、WordcountDriver。
所以现在的目录应该是这样的:
5、编写WordcountMapper.java
根据需求编写Map阶段执行的任务。
package com.wolf.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;
// map stage
// <KEYIN,VALUEIN,KEYOUT,VALUEOUT>
public class WordcountMapper extends Mapper<LongWritable, Text, Text, IntWritable> {
@Override
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
// map是一行一行传入
// 假设我们传入一行 wolf wolf
Text k = new Text();
// 我们是统计单词出现的次数,出现一次统计一次,所以v = 1
IntWritable v = new IntWritable(1);
// 1. 得到一行,转为字符串类型
String line = value.toString();
// 2. 用空格进行分词,存入words
String[] words = line.split(" ");
// 3. 循环写出到k
for (String word : words) {
// k = 'wolf'
k.set(word);
// 写入context ,<wolf,1>
context.write(k, v);
}
}
}
6、编写WordcountReducer.java
根据需求编写Reduce阶段执行的任务。
package com.wolf.mr.wordcount;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;
import java.io.IOException;
// reduce stage
// <KEYIN,VALUEIN,KEYOUT,VALUEOUT>
public class WordcountReducer extends Reducer<Text, IntWritable,Text,IntWritable> {
IntWritable v = new IntWritable();
@Override
protected void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
// key = wolf ,values = 1 1
// <key,value> <wolf,1> <wolf,1>
// 1. 求和
int sum = 0;
for (IntWritable value :values){
sum += value.get();
}
v.set(sum);
// 2. 写出
context.write(key,v);
}
}
7、编写WordcountDriver.java
WordcountDriver的形式比较固定,基本都是这7个步骤:
(1)获取Job对象
这个没什么好说的,就是固定的写法。
(2)设置jar保存位置
注意要使用setJarByClass方法而不是setJar方法,参数传本身的class即可,这也是固定的。
(3)关联Map和Reduce类
把刚才写好的Mapper和Reducer类交给job,这也是固定的。
(4)设置Mapper阶段输出的数据的Key和Value的类型
这个根据任务进行设置,Mapper阶段输出的key-value的格式是<字符串,出现的次数>,所以key的类型是Text,value的类型是IntWritable。
(5)设置最终阶段输出的数据的Key和Value的类型
此任务最终输出的数据和Mapper输出的数据相同,所以设定的也相同。
(6)设置输入路径和输出路径
此处的写法是通过args传参,其他写法应该也可以。
(7)提交job
注意要用waitForCompletion方法。
package com.wolf.mr.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, InterruptedException, ClassNotFoundException {
Configuration conf = new Configuration();
// 1. get Job object
Job job = Job.getInstance(conf);
// 2. set jar storage location
job.setJarByClass(WordcountDriver.class);
// 3. link Map and Reduce class
job.setMapperClass(WordcountMapper.class);
job.setReducerClass(WordcountReducer.class);
// 4. set Mapper stage output data's type of key and value
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(IntWritable.class);
// 5. set final data's type of key and value
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
// 6. set input path and output path
FileInputFormat.setInputPaths(job, new Path(args[0]));
FileOutputFormat.setOutputPath(job, new Path(args[1]));
// 7. submit job
boolean result = job.waitForCompletion(true);
System.exit(result ? 0 : 1);
}
}
8、运行Map-Reduce程序
在main上右键,选择Modify Run Configuration:
输入两个参数,注意输出目录一定不能已经存在!否则会报错:
运行程序,如果没问题的话,输出大概如下:
在输出路径查看结果:
通过Debug我们可以得到程序执行的具体步骤大概是:
(1)不断重复Map,直到Map完毕
(2)不断重复Reduce,直到运行完毕
(3)交出最终结果
当然,以上是在本机上运行,并没有在集群上运行,我们接下来让Wordcount案例在集群上运行起来。
9、在集群上运行Wordcount案例
(1)首先启动集群
跟以前一样,还是在102上sbin/start-dfs.sh,在103上sbin/start-yarn.sh
(2)在maven的pom.xml中加入打包的依赖
注意mainClass要修改成自己的Driver路径
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</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>
<archive>
<manifest>
<mainClass>com.wolf.mr.wordcount.WordcountDriver</mainClass>
</manifest>
</archive>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
(3)打包
双击mr的Lifecycle中的install
过了一会显示Build Success
左侧的目录中就出现了两个jar文件
with dependencies就是有依赖的jar包,另一个就是没有依赖的jar包,复制这个没有依赖的到集群上,名字太长,改成wc.jar:
hadoop jar /home/wolf/wc.jar com.wolf.mr.wordcount.WordcountDriver /wolf/firstdir /output
查看一下输出
hadoop fs -cat /output/part-r-00000
可以看到,成功分布式地统计了两个文件的词频。
至此,我们成功完成了 MapReduce的WordCount案例实操,我们还需多多练习编写MapReduce程序的代码,才能完全掌握。