参考: JeffreyZhou的博客园
- 《Hadoop权威指南》第四版
0
一个MR作业,包括三点:
- 输入数据
- MR程序
- Job配置信息
前面两篇学习了数据格式和MR过程(map函数和reduce函数),那么今天再讲一下配置信息,是怎么把 数据 和 程序结合起来的。
3.1 代码
Job对象指定作业执行规范,我们可以用它来控制整个作业的运行。打算对照代码来讲解,这样可能要有逻辑一点,不至于讲到最后都不知道自己的线索在哪。先贴上WordCount中的Job任务代码:
public static void main(String[] args) throws Exception {
Configuration conf = new Configuration(); // 配置文件
// System.out.println("url:" + conf.get("fs.default.name")); // deprecated
// System.out.println("url:" + conf.get("fs.defaultFS"));
// 获取一个作业
// Job job = new Job(conf, "word count"); // deprecated
Job job = Job.getInstance(conf,"wordcount"); // 用job的静态方法
// 设置job所用的那些类(class)文件在哪个jar包
job.setJarByClass(WordCount.class);
// 设置所用的map reduce类
job.setMapperClass(TokenizerMapper.class);
job.setCombinerClass(IntSumReducer.class); // 对每个节点的map输出进行combine
job.setReducerClass(IntSumReducer.class); // 对所有节点的输出进行reduce
// 设置数据输出类型
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
// 指定要处理的输入、输出路径,
//此处输入/出为固定文件目录
FileInputFormat.addInputPath(job, "input");
FileOutputFormat.setOutputPath(job, "output");
//此处为参数
// FileInputFormat.addInputPath(job, new Path(otherArgs[0]));
// FileOutputFormat.setOutputPath(job, new Path(otherArgs[1]));
// 将job提交给集群运行
System.exit(job.waitForCompletion(true) ? 0 : 1);
那么,现在对照上面的代码来分析作业提交到执行的整个过程吧。
3.2 创建Job
任务创建比较容易,其实就是new
一个实例,先创建一个配置文件的对象,然后将配置文件,以及作业名称作为参数,构造一个Job对象就行了
Configuration conf = new Configuration(); // 配置文件
Job job = Job.getInstance(conf,"wordcount"); // 用job的静态方法
3.3 打包作业
我们在Hadoop集群上运行这个作业时,要把代码打包成一个JAR文件(Hadoop在集群上发布这个文件),关于打包JAR,大概意思就是把程序运行所需要的包啊类啊啥的,全部形成一个压缩包,但这个工作不用我们自己去一个个找,只要在Job对象的setJarByClass()
方法中传递一个类即可,Hadoop会利用这个类来查找包含它的JAR文件,进而找到相关的JAR文件。
// 将job所用的那些类(class)文件,打成jar包
job.setJarByClass(WordCount.class);
3.4 设置各个环节的函数
这个很好理解,上一篇博文分析了MR过程中的各个环节,这些环节都是可以自定义的,就是在Job里面设置,将自定义的函数和具体作业联系起来。
job.setMapperClass(TokenizerMapper.class);
job.setCombinerClass(IntSumReducer.class); // 对每个节点的map输出进行combine
job.setPartitionerClass(MyPartitioner.class); // 对每个节点的map输出进行partition
job.setReducerClass(IntSumReducer.class); // 对所有节点的输出进行reduce
3.5 设置输入输出数据类型
job.setInputFormatClass(MyInputFormat.class);
job.setOutputFormatClass(TextOutputFormat.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
3.6 设置输入输出文件目录
在设置输入输出文件目录时,可以选择使用绝对目录,就是直接在语句中写入目录;也可以使用参数输入,即在运行程序时,再在控制台输入目录。
// 指定要处理的输入、输出路径,
//此处输入/出为固定文件目录
FileInputFormat.addInputPath(job, "input");
FileOutputFormat.setOutputPath(job, "output");
//此处为参数
// FileInputFormat.addInputPath(job, new Path(otherArgs[0]));
// FileOutputFormat.setOutputPath(job, new Path(otherArgs[1]));
3.7 提交并运行作业
单个任务的执行
可以直接使用语句:
job.waitForCompletion(true)
waitForCompletion()方法提交作业并等待执行完成,该方法唯一的参数是一个标识,指示是否已生成详细输出,当标识为
true
(成功)时,作业会把其进度写到控制台。
–《Hadoop权威指南》第四版,28页
多个任务执行
多个任务的话,就有多种组织形式,例如串行、并行、无关、组合。如下图:
图中,Job2和Job3将会等Job1执行完了再执行,且可以同时开始,而Job4必须等Job2和Job3同时结束后才结束。
这个组合,就可以采用这样的代码来实现:
Configuration conf = new Configuration();
Job job1 = new Job(conf, "job1"); //.. config Job1
Job job2 = new Job(conf, "job2"); //.. config Job2
Job job3 = new Job(conf, "job3"); //.. config Job3
Job job4 = new Job(conf, "job4"); //.. config Job4
//添加依赖关系
job2.addDependingJob(job1);
job3.addDependingJob(job1);
job4.addDependingJob(job2);
job4.addDependingJob(job3);
JobControl jc = new JobControl("jbo name");
jc.addJob(job1);
jc.addJob(job2);
jc.addJob(job3);
jc.addJob(job4);
jc.run();
3.x 后记
这里讲的其实偏向于作业的编程方面,但是在程序中把这些都设置好了,提交给集群后,又是怎样的运行机制呢?这个就是关于application master
、map task
等方面的分析了。