MapReduce案例学习(5) 列出工资比上司高的员工姓名及其工资

设计思路:

数据部分截取,用于方便分析    
---------------------------------                        
empno ename     mgr    sal   
 7369 SMITH    7902    800           
 7499 ALLEN    7698   1600           
 7521 WARD     7698   1250           
 7566 JONES    7839   2975           
 7654 MARTIN   7698   1250           
 7698 BLAKE    7839   2850           
 7782 CLARK    7839   2450           
 7839 KING            5000           
 7844 TURNER   7698   1500           
 7900 JAMES    7698    950           
 7902 FORD     7566   3000           

-----------------------------------
map阶段
读取:7566 JONES    7839   2975     
输出:在输出的value中用一个状态位标示该人员身份,用emp表示员工;mgr表示管理者
7566 emp,JONES,2975       --表示7566是一个员工,员工姓名为JONES,薪水为2975
7839 mgr,JONES,2975       --表示7839是一个管理者,他的下属是JONES,该下属的薪水为2975

以下类似的
读取:7698 BLAKE    7839   2850
输出:
7698 emp,BLAKE,2850
7839 mgr,BLAKE,2850 


读取:7782 CLARK    7839   2450
输出:
7782 emp,CLARK,2450
7839 mgr,CLARK,2450 


读取:7839 KING            5000
输出:
7839 emp,KING,5000
null mgr,KING,5000  (这类数据直接筛去,不write)


----------------------------------
reduce阶段
读取:
key为7839的数据聚集
7839 mgr,JONES,2975
7839 mgr,BLAKE,2850
7839 mgr,CLARK,2450
7839 emp,KING,5000
这里就汇总了员工号为7839的的数据集合,根据值中的关键标示emp和mgr来做数据处理:
值为emp时,7839作为员工,值value里面的是他的姓名和薪水;
值为mgr时,7839作为管理者,值value里面是他的下属员工和下属员工的薪水。
有了员工及其管理者的姓名和薪水,那么接下来的处理就简单了。


package week06;

import java.io.IOException;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.conf.Configured;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.*;
import org.apache.hadoop.mapreduce.*;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.util.GenericOptionsParser;
import org.apache.hadoop.util.Tool;
import org.apache.hadoop.util.ToolRunner;

/**
 *  5) 列出工资比上司高的员工姓名及其工资                      
* */
public class Emp_Test5 extends Configured implements Tool {

	/**
	 * 计数器 用于计数各种异常数据
	 */
	enum Counter {
		LINESKIP,
	}

	/**
	 * MAP任务
	 */
	public static class Map extends Mapper {

		@Override
		public void map(LongWritable key, Text value, Context context)
				throws IOException, InterruptedException {

			String line = value.toString();// 每行文件
			// 输入文件首行,不处理
			if (line.contains("empno") == true) {
				return;
			}

			Employee emp = Employee.parser(line);
			if (emp.isValid()) {
				context.write(new Text(emp.getEmpno()),
						new Text("emp," + emp.getEname() + "," + emp.getSal()));

				if (!"".equals(emp.getMgr())) {//管理者字段不为空时
					context.write(new Text(emp.getMgr()),
							new Text("mgr," + emp.getEname() + "," + emp.getSal()));
				}
			} else {
				context.getCounter(Counter.LINESKIP).increment(1); // 出错令计数器+1
				return;
			}
		}
	}

	/**
	 * REDUCE
	 */
	public static class Reduce extends Reducer {

		@Override
		public void reduce(Text key, Iterable values, Context context)
				throws IOException, InterruptedException {
			
			List empList = new ArrayList();

			int mgrSal=0;
			//遍历reduce的输入的Iterable集合,将所有人员都加入到人员列表数组中
			for (Text emp : values) {
				empList.add(new Text(emp.toString()));
				String[] tmps = emp.toString().split(",");
				if (tmps.length == 3) {
					//遍历的过程中,取得管理者的薪水,注意:管理者本人在reduce输入的Iterable集合中是标志为emp,即作为一个员工
					if (tmps[0].equals("emp")) {
						mgrSal = new Integer(tmps[2]);
					}
				}
			}

			//System.out.println("管理者:"+key+"--管理者薪资:" + mgrSal);
			
			//遍历人员列表数组
			for (Text emp : empList) {
				String[] tmps = emp.toString().split(",");
				if (tmps.length == 3) {					
					//System.out.println(tmps[1]+"--下属薪资:" + tmps[2]);

					//将员工取出来,并比较其薪水是否比其管理者的薪水高,高则输出					
					//注意:该管理者的下属在reduce输入的Iterable集合中是标志为mgr
					if (tmps[0].equals("mgr")
							&& (Integer.parseInt(tmps[2]) - mgrSal > 0)) {
						System.out.println("bingo!!!!!");
						context.write(new Text(tmps[1]), new Text(tmps[2]));
					}
				}
			}
		}
	}

	public int run(String[] args) throws Exception {
		Configuration conf = getConf();

		conf.set("mapred.job.tracker", "192.168.1.201:9001");
		String[] ioArgs = new String[] { "emp_in", "emp_out_test5" };
		String[] otherArgs = new GenericOptionsParser(conf, ioArgs)
				.getRemainingArgs();
		if (otherArgs.length != 2) {
			System.err.println("Usage: Test < input path > < output path >");
			System.exit(2);
		}

		Job job = new Job(conf, "week06_test_05"); // 任务名
		job.setJarByClass(Emp_Test5.class); // 指定Class

		FileInputFormat.addInputPath(job, new Path(otherArgs[0])); // 输入路径
		FileOutputFormat.setOutputPath(job, new Path(otherArgs[1])); // 输出路径

		job.setMapperClass(Map.class); // 调用上面Map类作为Map任务代码
		job.setReducerClass(Reduce.class);// 调用上面Reduce类作为Reduce任务代码

		job.setMapOutputKeyClass(Text.class);
		job.setMapOutputValueClass(Text.class);

		job.setOutputKeyClass(Text.class); // 指定输出的KEY的格式
		job.setOutputValueClass(Text.class); // 指定输出的VALUE的格式

		job.waitForCompletion(true);

		// 输出任务完成情况
		System.out.println("任务名称:" + job.getJobName());
		System.out.println("任务成功:" + (job.isSuccessful() ? "是" : "否"));
		System.out.println("输入行数:"
				+ job.getCounters()
						.findCounter("org.apache.hadoop.mapred.Task$Counter",
								"MAP_INPUT_RECORDS").getValue());
		System.out.println("输出行数:"
				+ job.getCounters()
						.findCounter("org.apache.hadoop.mapred.Task$Counter",
								"MAP_OUTPUT_RECORDS").getValue());
		System.out.println("跳过的行:"
				+ job.getCounters().findCounter(Counter.LINESKIP).getValue());
		return job.isSuccessful() ? 0 : 1;
	}

	/**
	 * 设置系统说明 设置MapReduce任务
	 */
	public static void main(String[] args) throws Exception {
		// 记录开始时间
		DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		Date start = new Date();

		// 运行任务
		int res = ToolRunner.run(new Configuration(), new Emp_Test5(), args);

		// 输出任务耗时
		Date end = new Date();
		float time = (float) ((end.getTime() - start.getTime()) / 60000.0);
		System.out.println("任务开始:" + formatter.format(start));
		System.out.println("任务结束:" + formatter.format(end));
		System.out.println("任务耗时:" + String.valueOf(time) + " 分钟");

		System.exit(res);
	}
}



你可能感兴趣的:(mapreduce,hadoop)