Hadoop实战演练:搜索数据分析----多个不同的Job进行串连(4)

    摘要:在hadoop中,一个job需要另一个job的输出结果作为输入源。本文写了一个例子来设置4个不同Job的依赖实例

   工程源码下载:https://github.com/appleappleapple/BigDataLearning/tree/master/Hadoop-Demo

在文章中

Hadoop实战演练:搜索数据分析----数据去重 (1)

Hadoop实战演练:搜索数据分析----TopK计算(2)

Hadoop实战演练:搜索数据分析----计算结果存储到Mysql(3)

上面加起来总共有4个job。而且都是有上下依赖关系(文章1的结果输给文章2做为输入,文章2的结果输出给文章3作为输入),照之前笔者的作法都是分开的,下面将对4个job进行串连。

1、代码编写

package com.lin.keyword;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.db.DBConfiguration;
import org.apache.hadoop.mapreduce.lib.db.DBOutputFormat;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.input.TextInputFormat;
import org.apache.hadoop.mapreduce.lib.jobcontrol.ControlledJob;
import org.apache.hadoop.mapreduce.lib.jobcontrol.JobControl;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;
import org.apache.hadoop.util.GenericOptionsParser;

import com.lin.common.Constrants;
import com.lin.keyword.SaveResult.StudentMapper;
import com.lin.keyword.SaveResult.StudentReducer;
import com.lin.keyword.TopK.KMap;
import com.lin.keyword.TopK.KReduce;

/**
 * 功能概要:四个Job汇总依次运行
 * 
 * @author linbingwen
 */
public class Test {
	
	public static void main(String[] args) throws Exception {
		
		Configuration conf = new Configuration();
		
		DBConfiguration.configureDB(conf, Constrants.JDBC_DRIVE,Constrants.JDBC_URL,Constrants.JDBC_USER, Constrants.JDBC_PASSWORD);  
		
		//设置hadoop的机器、端口
		conf.set(Constrants.CONF_NAME, Constrants.CONF_VALUE);
		//设置输入输出文件目录
		String[] ioArgs = new String[] { Constrants.HDFS_PATH +"data_in", Constrants.HDFS_PATH + "cleanSame_out" , Constrants.HDFS_PATH +"wordCount_out",Constrants.HDFS_PATH +"result_out" };
		String[] otherArgs = new GenericOptionsParser(conf, ioArgs).getRemainingArgs();
		if (otherArgs.length != 4) {
			System.err.println("Usage:  <in> <out>");
			System.exit(2);
		}
		
		/***********************************去除重复数据作业***********************************/
		// 设置一个job
		Job job0 = Job.getInstance(conf, "clean same data");
		job0.setJarByClass(CleanSameData.class);

	  // 设置Map、Combine和Reduce处理类
		job0.setMapperClass(CleanSameData.Map.class);
		job0.setCombinerClass(CleanSameData.Reduce.class);
		job0.setReducerClass(CleanSameData.Reduce.class);

		// 设置输出类型
		job0.setOutputKeyClass(Text.class);
		job0.setOutputValueClass(Text.class);

		// 将输入的数据集分割成小数据块splites,提供一个RecordReder的实现
		job0.setInputFormatClass(TextInputFormat.class);

		// 提供一个RecordWriter的实现,负责数据输出
		job0.setOutputFormatClass(TextOutputFormat.class);

		// 设置输入和输出目录
		FileInputFormat.addInputPath(job0, new Path(otherArgs[0]));
		FileOutputFormat.setOutputPath(job0, new Path(otherArgs[1]));
		
		//加入控制容器 
	    ControlledJob ctrljob0=new  ControlledJob(conf); 
	    ctrljob0.setJob(job0); 
	    
	    
		/***********************************统计搜索词次数作业***********************************/
		//设置一个job
		Job job1 = Job.getInstance(conf, "key Word count");
		job1.setJarByClass(KeyWordCount.class);
		
		// 设置Map、Combine和Reduce处理类
		job1.setMapperClass(KeyWordCount.Map.class);
		job1.setCombinerClass(KeyWordCount.Reduce.class);
		job1.setReducerClass(KeyWordCount.Reduce.class);
		
		// 设置输出类型
		job1.setOutputKeyClass(Text.class);
		job1.setOutputValueClass(IntWritable.class);
		
		// 将输入的数据集分割成小数据块splites,提供一个RecordReder的实现
		job1.setInputFormatClass(TextInputFormat.class);
		
		// 提供一个RecordWriter的实现,负责数据输出
		job1.setOutputFormatClass(TextOutputFormat.class);
		
		//加入控制容器 
	    ControlledJob ctrljob1=new  ControlledJob(conf); 
	    ctrljob1.setJob(job1); 
	    //设置多个作业直接的依赖关系 	  
	    ctrljob1.addDependingJob(ctrljob0); 
		
		// 设置job1输入和输出目录
		FileInputFormat.addInputPath(job1, new Path(otherArgs[1]));
		FileOutputFormat.setOutputPath(job1, new Path(otherArgs[2]));
		
		/***********************************统计top k作业***********************************/
	    //设置一个job
	  	Job job2 = Job.getInstance(conf, "top K");
	  	job2.setJarByClass(TopK.class);
	  		
	  	// 设置Map、Combine和Reduce处理类
	  	job2.setMapperClass(KMap.class);
	  	job2.setCombinerClass(KReduce.class);
	  	job2.setReducerClass(KReduce.class);
	  		
	  	// 设置输出类型
	  	job2.setOutputKeyClass(IntWritable.class);
	  	job2.setOutputValueClass(Text.class);
	  		
	  	// 将输入的数据集分割成小数据块splites,提供一个RecordReder的实现
	  	job2.setInputFormatClass(TextInputFormat.class);
	  		
	  	// 提供一个RecordWriter的实现,负责数据输出
	  	job2.setOutputFormatClass(TextOutputFormat.class);
	  	//job2.setOutputFormatClass(DBOutputFormat.class);
	  	
	    //作业2加入控制容器 
	    ControlledJob ctrljob2=new ControlledJob(conf); 
	    ctrljob2.setJob(job2); 
	    
	    //设置多个作业直接的依赖关系 	  
	    ctrljob2.addDependingJob(ctrljob1); 
	    
	    //输入路径是上一个作业的输出路径,因此这里填args[2],要和上面对应好
	    FileInputFormat.addInputPath(job2, new Path(otherArgs[2]));
	    
	    //输出路径从新传入一个参数,这里需要注意,因为我们最后的输出文件一定要是没有出现过得
	    //因此我们在这里new Path(args[3])因为args[3]在上面没有用过,只要和上面不同就可以了
	    FileOutputFormat.setOutputPath(job2,new Path(otherArgs[3]));
	    
		/***********************************保存到数据库作业***********************************/
	    //第四个作业,将结果保存到mysql
	  	Job job3 = Job.getInstance(conf, "SaveResult");
	  	job3.setJarByClass(SaveResult.class);
	  		
	  	// 输入路径
	  	FileInputFormat.addInputPath(job3, new Path(otherArgs[3]));
	          
	    // Mapper
	  	job3.setMapperClass(StudentMapper.class);
	    // Reducer
	  	job3.setReducerClass(StudentReducer.class);
	          
	    // mapper输出格式
	  	job3.setOutputKeyClass(LongWritable.class);
	  	job3.setOutputValueClass(Text.class);
	          
	    // 输入格式,默认就是TextInputFormat
	  	job3.setOutputFormatClass(DBOutputFormat.class);  
	          
	    // 输出到哪些表、字段
	    DBOutputFormat.setOutput(job3, "key_word", "word", "total");
	    
	    //作业2加入控制容器 
	    ControlledJob ctrljob3=new ControlledJob(conf); 
	    ctrljob3.setJob(job3); 
	    
	    //设置多个作业直接的依赖关系 	  
	    ctrljob3.addDependingJob(ctrljob2); 
	    

	    //主的控制容器,控制上面的总的两个子作业 
	    JobControl jobCtrl=new JobControl("myctrl"); 
	  
	    //添加到总的JobControl里,进行控制
	    jobCtrl.addJob(ctrljob0); 
	    jobCtrl.addJob(ctrljob1); 
	    jobCtrl.addJob(ctrljob2); 
	    jobCtrl.addJob(ctrljob3); 
	  		
	   //在线程启动,记住一定要有这个
	    Thread  t=new Thread(jobCtrl); 
	    t.start(); 

	    while(true) { 
	      if(jobCtrl.allFinished()){//如果作业成功完成,就打印成功作业的信息 
	         System.out.println(jobCtrl.getSuccessfulJobList()); 
	         jobCtrl.stop(); 
	         break; 
	       }
	    }
	}

}

这里是一些常量定义:

package com.lin.common;

/**
 * 功能概要:
 * 
 * @author linbingwen
 * @since  2016年7月31日 
 */
public class Constrants {
	
	public static String JDBC_DRIVE = "com.mysql.cj.jdbc.Driver";
	
	public static String JDBC_URL = "jdbc:mysql://localhost:3306/learning?serverTimezone=UTC";
	
	public static String JDBC_USER = "root";
	
	public static String JDBC_PASSWORD = "linlin";
	
	public static String CONF_NAME = "mapred.job.tracker";
	
	public static String CONF_VALUE = "10.75.201.125:9000";
	
	public static String HDFS_PATH = "hdfs://hmaster:9000/";

}

输出结果:


总共有3个输出目录:


数据库保存结果:


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值