Hadoop2.6.4运行MapReduce程序
环境准备
- 本地jdk版本与hadoop集群的版本保持一致
- hadoop的jar包要全部导入
MapReduce代码实现
本代码演示 wordcount程序。
MapReduce代码实现并不难,这里要编写3个类,分别是WordcountMapper类、WordcountReducer类和WordcountDriver驱动类,前面两个类分别实现相应的 Map 和 Reduce 方法,后面一个则是对任务的创建进行部署。
分别创建这3个类,并放入wordcount package下,目录结构如下:
WordcountMapper.java
package cn.bigdata.mr.wcdemo;
import java.io.IOException;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;
/**
* KEYIN:默认情况下,是mr框架所读到的一行文本的起始偏移量,Long,
* 但是在hadoop中有自己的更精简的序列化接口,所以不用Long,而用LongWritable
* VALUEIN:默认情况下,是mr框架所读到的文本的内容,String,同上,用Text
* KEYOUT:是用户自定义逻辑处理完成之后输出数据中的key,在此处是单词String
* VALUEOUT:是用户自定义逻辑处理完成之后输出数据中的value,在此处是单词次数,Integer
*
* @author dapao
*
*/
public class WordcountMapper extends Mapper<LongWritable, Text, Text, IntWritable> {
/*
* map阶段的业务逻辑就卸载自定义的map()方法中
* maptask会对每一行输入数据调用一次我们自定义的map()方法
* (non-Javadoc)
* @see org.apache.hadoop.mapreduce.Mapper#map(KEYIN, VALUEIN, org.apache.hadoop.mapreduce.Mapper.Context)
*/
@Override
protected void map(LongWritable key, Text value, Context context)
throws IOException, InterruptedException {
//将maptask传给我们的文本内容先转换成String
String line = value.toString();
//根据空格将这一行切分成单词
String[] words = line.split(" ");
//将单词输出为<单词,1>
for(String word:words){
//将单词为key,将次数1作为value,以便后续的数据分发,可以根据单词分发,以便于相同单词会到相同的reduce task
context.write(new Text(word), new IntWritable(1));
}
}
}
WordcountReducer.java
package cn.bigdata.mr.wcdemo;
import java.io.IOException;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;
/*
* KEYIN,VALUEIN 对应 mapper输出的KEYOUT,VALUEOUT类型对应
*
* KEYOUT,VALUEOUT 是自定义reduce逻辑处理结果的输出了数据类型
* KEYOUT是单词
* VALUEOUT是总次数
*/
public class WordcountReducer extends Reducer<Text, IntWritable, Text, IntWritable>{
//extends Reducer<Text, IntWritable, Text, IntWritable> {
/**
*
* @param key
* 是一组相同单词kv对的key
* @param values
* @param context
* @throws java.io.IOException
* @throws InterruptedException
*/
protected void reduce(Text key, Iterable<IntWritable> values, Context context)
throws IOException, InterruptedException {
int count=0;
for (IntWritable value : values) {
count += value.get();
}
context.write(key, new IntWritable(count));
}
}
WordcountDriver.java
package cn.bigdata.mr.wcdemo;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URI;
import org.apache.hadoop.conf.Configuration;
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.mapred.WordCount;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
public class WordcountDriver {
/**
* 相当于一个yarn集群的客户端 需要在此封装我们的mr程序的相关运行参数,指定jar包 最后交给yarn
*
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
// if (args == null || args.length == 0) {
//
// args = new String[2];
// args[0] = "hdfs://master:9000/wordcount/input/NOTICE.txt";
// args[1] = "hdfs://master:9000/wordcount/output3";
// }
Configuration conf = new Configuration();
Job job = Job.getInstance();
// 指定本程序的jar包错在的本地路径
job.setJarByClass(WordcountDriver.class);
// 指定本业务job要使用的mapper业务类
job.setMapperClass(WordcountMapper.class);
job.setReducerClass(WordcountReducer.class);
// 指定mapper输出数据的kv类型
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(IntWritable.class);
// 指定最终输出的数据的kv类型
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
// 指定job的输入原始文件所在目录
FileInputFormat.setInputPaths(job, new Path(args[0]));
// 指定job的输入结果所在目录
FileOutputFormat.setOutputPath(job, new Path(args[1]));
// 将job中配置的相关参数,以及job所用的java类所在的jar包,提交给yarn去运行
// job.submit();
boolean res = job.waitForCompletion(true);
System.exit(res ? 0 : 1);
}
}
打包工程为jar包
WordCount代码完成后,并不能直接在hadoop中运行,还需要将其打包成jvm所能执行的二进制文件,即打包成.jar文件,才能被hadoop所有。
在WordCount项目上右击,选择Export(导出),在弹出的对话框中选择 JAR file,如下图所示,然后单击Next。之后会进入JAR依赖包过滤对话框,这里只选择src即可,把lib文件夹前的勾选去掉,因为lib中的依赖包本来就是复制的hadoop的源文件,在集群中已经包含了。之后选择一个保存位置,单击Finish即可。
打包成wordcount.jar
部署并运行
部署其实就把前面打包生成的wordcount.jar包放入集群中运行。hadoop一般会有多个节点,一个namenode节点和多个datanode节点,这里只需要把jar放入namenode中,并使用相应的hadoop命令即可,hadoop集群会把任务传送给需要运行任务的节点。wordcount.jar运行时需要有输入文本。
- 上传测试文件到HDFS
hadoop fs -mkdir /wordcount/input #设置输入
hadoop fs -put a.txt b.txt c.txt /wordcount/input #上传测试文本
在hadoop集群中运行WordCount
在hadoop中运行jar任务需要使用的命令:
hadoop: hadoop脚本命令,如果要直接使用,必须添加相应bin路径到环境变量PATH中。
jar: 表示要运行的是一个基于Java的任务。
jar文件位置: 提供所要运行任务的jar文件位置,如果在当前操作目录下,可直接使用文件名。
jar主类: 提供入口函数所在的类,格式为[包名.]类名
HDFS输入位置: 指定输入文件在HDFS中的位置。
HDFS输出位置: 执行输出文件在HDFS中的存储位置,该位置必须不存在,否则任务不会运行,该机制就是为了防止文件被覆盖出现意外丢失。
本例的操作命令如下:
hadoop jar wordcount.jar cn.bigdata.mr.wcdemo.WordcountDriver /wordcount/input /wordcount/output
遇到的问题
问题一:
解决方法:
-问题二:
解决方法:
有时候一个引错包,或者配置文件写错,就会调试好长时间,对此,小伙伴们要细心细心再细心