一个典型的实现Tool的程序:
/** MyApp 需要从命令行读取参数,用户输入命令如, $bin/hadoop jar MyApp.jar -archives test.tgz arg1 arg2 -archives 为hadoop通用参数,arg1 ,arg2为job的参数 */ public class MyApp extends Configured implements Tool { //implemet Tool’s run public int run(String[] args) throws Exception { Configuration conf = getConf(); // Create a JobConf using the processed conf JobConf job = new JobConf(conf, MyApp.class); // Process custom command-line options Path in = new Path(args[1]); Path out = new Path(args[2]); // Specify various job-specific parameters job.setJobName(“my-app”); job.setInputPath(in); job.setOutputPath(out); job.setMapperClass(MyApp.MyMapper.class); job.setReducerClass(MyApp.MyReducer.class);
JobClient.runJob(job); }
public static void main(String[] args) throws Exception { // args由ToolRunner来处理 int res = ToolRunner.run(new Configuration(), new MyApp(), args); System.exit(res); } } |
说明:
使用ToolRunner让参数传递更简单,关于MapReduce运行和参数配置,你是否有下面的烦恼:
A: 将MapReduce Job配置参数写到java代码里,一旦变更意味着修改java文件源码、编译、打包、部署一连串事情。
B:当MapReduce 依赖配置文件的时候,你需要手工编写java代码使用DistributedCache将其上传到HDFS中,以便map和reduce函数可以读取。
C:当你的map或reduce 函数依赖第三方jar文件时,你在命令行中使用”-libjars”参数指定依赖jar包时,但根本没生效。
D:其实,Hadoop有个ToolRunner类,它是个好东西,简单好用。无论在《Hadoop权威指南》还是Hadoop项目源码自带的example,都推荐使用ToolRunner。
下面我们看下src/example目录下WordCount.Java文件,它的代码结构是这样的:
public class WordCount {
// 略...
public static void main(String[] args) throws Exception {
Configuration conf = new Configuration();
String[] otherArgs = new GenericOptionsParser(conf,
args).getRemainingArgs();
// 略...
Job job = new Job(conf, "word count");
// 略...
System.exit(job.waitForCompletion(true) ? 0 : 1);
}
}
WordCount.java中使用到了GenericOptionsParser这个类,它的作用是将命令行中参数自动设置到变量conf中。举个例子,比如我希望通过命令行设置reduce task数量,就这么写:bin/hadoop jar MyJob.jar com.xxx.MyJobDriver -Dmapred.reduce.tasks=5
上面这样就可以了,不需要将其硬编码到java代码中,很轻松就可以将参数与代码分离开。
其它常用的参数还有”-libjars”和-“files”,使用方法一起送上:
bin/hadoop jar MyJob.jar com.xxx.MyJobDriver -Dmapred.reduce.tasks=5\
-files ./dict.conf \
-libjars lib/commons-beanutils-1.8.3.jar,lib/commons-digester-2.1.jar
参数”-libjars”的作用是上传本地jar包到HDFS中MapReduce临时目录并将其设置到map和reduce task的classpath中;参数”-files”的作用是上传指定文件到HDFS中mapreduce临时目录,并允许map和reduce task读取到它。这两个配置参数其实都是通过DistributeCache来实现的。
至此,我们还没有说到ToolRunner,上面的代码我们使用了GenericOptionsParser帮我们解析命令行参数,编写ToolRunner的程序员更懒,它将GenericOptionsParser调用隐藏到自身run方法,被自动执行了,修改后的代码变成了这样:
public class WordCount extends Configuredimplements Tool {
@Override
public int run(String[] arg0) throws Exception {
Job job = new Job(getConf(), "word count");
// 略...
System.exit(job.waitForCompletion(true) ? 0 : 1);
return 0;
}
public static void main(String[] args) throws Exception {
int res = ToolRunner.run(new Configuration(), new WordCount(), args);
System.exit(res);
}
}
看看代码上有什么不同:
让WordCount继承Configured并实现Tool接口。
重写Tool接口的run方法,run方法不是static类型,这很好。
在WordCount中我们将通过getConf()获取Configuration对象。
最终我们得出的总结是:
1、通过使用ToolRunner.run(...)方法,可以更便利的使用hadoop命令行参数。
2、ToolRunner.run(...)通过调用Tool类中的run(String[])方法来运行hadoop程序,并默认加载core-default.xml与core-site.xml中的参数。
在程序运行时,可以通过命令行修改参数,可修改的内容如下: