在上一节
中,我们发现,一个需求得出解,需要有两个MapReduce程序,那么如果碰到类似的需要运行多个有依赖关系的Job时,我们可以使用JobControl这个工具类,来管理多个具有依赖关系的job的运行, 所以上一MapReduce案例,我做了如下改写:
请看具体的代码实现:
package com.ghgj.mazh.mapreduce.jobControl;
import java.io.IOException;
import java.util.Arrays;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.jobcontrol.ControlledJob;
import org.apache.hadoop.mapreduce.lib.jobcontrol.JobControl;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
/**
* 作者: 马中华:http://blog.csdn.net/zhongqi2513
* 日期: 2017年10月25日下午7:45:14
*
* 描述:求共同好友 -- 因为需要运行多个Job,所以使用JobControl对象来管理这多个具有依赖关系的任务的运行。
*/
public class CommonFirendsMR {
public static void main(String[] args) throws Exception {
Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(conf);
/**
* 第一个job信息
*/
Job job = Job.getInstance(conf);
job.setJarByClass(CommonFirendsMR.class);
job.setMapperClass(CommonFriends1MRMapper.class);
job.setReducerClass(CommonFriends1MRReducer.class);
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(Text.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(Text.class);
Path p1 = new Path("D:\\bigdata\\commonfriends\\input");
Path p2 = new Path("D:\\bigdata\\commonfriends\\step1_output");
if(fs.exists(p2)){
fs.delete(p2, true);
}
FileInputFormat.setInputPaths(job, p1);
FileOutputFormat.setOutputPath(job, p2);
/**
* 第二个job信息
*/
Job job2 = Job.getInstance(conf);
job2.setJarByClass(CommonFirendsMR.class);
job2.setMapperClass(CommonFriends2MRMapper.class);
job2.setReducerClass(CommonFriends2MRReducer.class);
job2.setMapOutputKeyClass(Text.class);
job2.setMapOutputValueClass(Text.class);
job2.setOutputKeyClass(Text.class);
job2.setOutputValueClass(Text.class);
Path inpath2 = new Path("D:\\bigdata\\commonfriends\\step1_output");
Path outPath2 = new Path("D:\\bigdata\\commonfriends\\step2_output");
if (fs.exists(outPath2)) {
fs.delete(outPath2, true);
}
FileInputFormat.setInputPaths(job2, inpath2);
FileOutputFormat.setOutputPath(job2, outPath2);
ControlledJob step1Job = new ControlledJob(job.getConfiguration());
ControlledJob step2Job = new ControlledJob(job.getConfiguration());
step1Job.setJob(job);
step2Job.setJob(job2);
/**
* 添加job和job之间的依赖关系,在此题中:step2Job是依赖于step1Job的计算结果的。所以必须要等到step1Job执行完成后,才能执行step2Job的任务的计算
*/
step2Job.addDependingJob(step1Job);
/**
* 通过JobControl这个工具类,可以让多个MapReduce Job可以被有条理的组织起来,进行有先后顺序的运行
* 其实JobControl就是一个线程类。
*/
JobControl jc = new JobControl("CommonFriends");
jc.addJob(step1Job);
jc.addJob(step2Job);
/**
* 启动目标线程,开启任务的执行
*/
Thread jobThread = new Thread(jc);
jobThread.start();
/**
* 每隔一段时间来判断一下该jc线程的任务是否执行完成
*/
while(!jc.allFinished()){
Thread.sleep(500);
}
/**
* 当主线程程序退出了上面的while循环,证明任务已经全部执行成功。这主线程也可以正常退出了。
*/
System.exit(0);
}
/**
* 作者: 马中华:http://blog.csdn.net/zhongqi2513
* 日期: 2017年10月25日下午7:36:33
*
* 描述:第一个MapReduce程序的Mapper
*/
public static class CommonFriends1MRMapper extends Mapper<LongWritable, Text, Text, Text> {
/**
* key : 读取文件内容时的每行的起始偏移量
* value : 读取到的一行文本
* 格式:A:B,C,D,F,E,O
*/
@Override
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
String line = value.toString();
String[] tokens = line.split(":");
String person = tokens[0];
String[] friends = tokens[1].split(",");
for (String f : friends) {
/**
* 输出数据格式:
* B A
* C A
* D A
* F A
* E A
* O A
*/
context.write(new Text(f), new Text(person));
}
}
}
/**
* 作者: 马中华:http://blog.csdn.net/zhongqi2513
* 日期: 2017年10月25日下午7:36:55
*
* 描述:第一个MapReduce程序的Reducer
*/
public static class CommonFriends1MRReducer extends Reducer<Text, Text, Text, Text> {
@Override
protected void reduce(Text friend, Iterable<Text> persons, Context context) throws IOException, InterruptedException {
StringBuffer sb = new StringBuffer();
for (Text p : persons) {
sb.append(p).append("-");
}
/**
* 输出数据格式:
* A I-K-C-B-G-F-H-O-D-
*/
context.write(friend, new Text(sb.toString()));
}
}
/**
* 作者: 马中华:http://blog.csdn.net/zhongqi2513
* 日期: 2017年10月25日下午7:37:07
*
* 描述:第二个MapReduce程序的Mapper
*/
public static class CommonFriends2MRMapper extends Mapper<LongWritable, Text, Text, Text> {
/**
* A I-K-C-B-G-F-H-O-D-
* B A-F-J-E-
* C A-E-B-H-F-G-K-
*/
@Override
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
String line = value.toString();
String[] tokens = line.split("\t");
String friend = tokens[0];
String[] persons = tokens[1].split("-");
Arrays.sort(persons);
for (int i = 0; i < persons.length - 1; i++) {
for (int j = i + 1; j < persons.length; j++) {
/**
* 输出数据格式:
* I-K A
* I-C A
* ....
*/
context.write(new Text(persons[i] + "-" + persons[j]), new Text(friend));
}
}
}
}
/**
* 作者: 马中华:http://blog.csdn.net/zhongqi2513
* 日期: 2017年10月25日下午7:37:19
*
* 描述:第二个MapReduce程序的Reducer
*/
public static class CommonFriends2MRReducer extends Reducer<Text, Text, Text, Text> {
@Override
protected void reduce(Text person_pair, Iterable<Text> friends, Context context) throws IOException, InterruptedException {
StringBuffer sb = new StringBuffer();
for (Text f : friends) {
sb.append(f).append(" ");
}
/**
* 输出数据格式:
* A-B C E
*/
context.write(person_pair, new Text(sb.toString()));
}
}
}
如有不当之处,请不吝指教。 ヾ(◍°∇°◍)ノ゙