【MapReduce】常用计算模型详解

来自:http://blog.csdn.net/yongjian1092/article/details/46799371

前一阵子参加炼数成金的MapReduce培训,培训中的作业例子比较有代表性,用于解释问题再好不过了。有一本国外的有关MR的教材,比较实用,点此下载

一.MapReduce应用场景

MR能解决什么问题?一般来说,用的最多的应该是日志分析,海量数据排序处理。最近一段时间公司用MR来解决大量日志的离线并行分析问题。

二.MapReduce机制

对于不熟悉MR工作原理的同学,推荐大家先去看一篇博文: http://blog.csdn.net/athenaer/article/details/8203990

三.常用计算模型

这里举一个例子,数据表在Oracle默认用户Scott下有DEPT表和EMP表。为方便,现在直接写成两个TXT文件如下:

1.部门表

DEPTNO,DNAME,LOC    // 部门号,部门名称,所在地

[html]  view plain  copy
 print ?
  1. 10,ACCOUNTING,NEW YORK  
  2. 20,RESEARCH,DALLAS  
  3. 30,SALES,CHICAGO  
  4. 40,OPERATIONS,BOSTON  

2.员工表

EMPNO,ENAME,JOB,HIREDATE,SAL,COMM,DEPTNO,MGR // 员工号,英文名,职位,聘期,工资,奖金,所属部门,管理者
[html]  view plain  copy
 print ?
  1. 7369,SMITH,CLERK,1980-12-17 00:00:00.0,800,,20,7902  
  2. 7499,ALLEN,SALESMAN,1981-02-20 00:00:00.0,1600,300,30,7698  
  3. 7521,WARD,SALESMAN,1981-02-22 00:00:00.0,1250,500,30,7698  
  4. 7566,JONES,MANAGER,1981-04-02 00:00:00.0,2975,,20,7839  
  5. 7654,MARTIN,SALESMAN,1981-09-28 00:00:00.0,1250,1400,30,7698  
  6. 7698,BLAKE,MANAGER,1981-05-01 00:00:00.0,2850,,30,7839  
  7. 7782,CLARK,MANAGER,1981-06-09 00:00:00.0,2450,    ,10,7839  
  8. 7839,KING,PRESIDENT,1981-11-17 00:00:00.0,5000,,10,  
  9. 7844,TURNER,SALESMAN,1981-09-08 00:00:00.0,1500,0,30,7698  
  10. 7900,JAMES,CLERK,1981-12-03 00:00:00.0,950,,30,7698  
  11. 7902,FORD,ANALYST,1981-12-03 00:00:00.0,3000,,20,7566  
  12. 7934,MILLER,CLERK,1982-01-23 00:00:00.0,1300,,10,7782  

3.实例化为bean

这两个bean的实际作用都是分割传入的字符串,从字符串内得到所属的属性信息。

emp.java
[java]  view plain  copy
 print ?
  1. public Emp(String inStr) {  
  2.         String[] split = inStr.split(",");  
  3.         this.empno = (split[0].isEmpty()? "" : split[0]);  
  4.         this.ename = (split[1].isEmpty() ? "" : split[1]);  
  5.         this.job = (split[2].isEmpty() ? "" : split[2]);  
  6.         this.hiredate = (split[3].isEmpty() ? "" : split[3]);  
  7.         this.sal = (split[4].isEmpty() ? "0" : split[4]);  
  8.         this.comm = (split[5].isEmpty() ? "" : split[5]);  
  9.         this.deptno = (split[6].isEmpty() ? "" : split[6]);  
  10.         try {  
  11.             this.mgr = (split[7].isEmpty() ? "" : split[7]);  
  12.         } catch (IndexOutOfBoundsException e) {     //防止最后一位为空的情况  
  13.             this.mgr = "";  
  14.         }  
  15. }  

dept.java
[java]  view plain  copy
 print ?
  1. public Dept(String string) {  
  2.         String[] split = string.split(",");  
  3.         this.deptno = split[0];  
  4.         this.dname = split[1];  
  5.         this.loc = split[2];  
  6.     }  

4.模型分析

4.1 求和

求各个部门的总工资
[java]  view plain  copy
 print ?
  1. public static class Map_1 extends MapReduceBase implements Mapper<Object, Text, Text, IntWritable> {  
  2.         public void map(Object key, Text value, OutputCollector<Text, IntWritable> output, Reporter reporter) throws IOException {  
  3.             try {  
  4.                 Emp emp = new Emp(value.toString());  
  5.                 output.collect(new Text(emp.getDeptno()), new IntWritable(Integer.parseInt(emp.getSal())));  // { k=部门号,v=员工薪资}  
  6.             } catch (Exception e) {  
  7.             reporter.getCounter(ErrCount.LINESKIP).increment(1);  
  8.             WriteErrLine.write("./input/" + this.getClass().getSimpleName() + "err_lines", reporter.getCounter(ErrCount.LINESKIP).getCounter() + " " + value.toString());  
  9.             }  
  10.         }      
  11.     }  
  12.   
  13.     public static class Reduce_1 extends MapReduceBase implements Reducer<Text, IntWritable, Text, IntWritable> {  
  14.         public void reduce(Text key, Iterator<IntWritable> values, OutputCollector<Text, IntWritable> output, Reporter reporter) throws IOException {  
  15.             int sum = 0;  
  16.             while (values.hasNext()) {  
  17.                 sum = sum + values.next().get();  
  18.             }  
  19.             output.collect(key, new IntWritable(sum));  
  20.         }  
  21.   
  22.     }  


运行结果:



4.3 平均值

求各个部门的人数和平均工资
[java]  view plain  copy
 print ?
  1. public static class Map_2 extends MapReduceBase implements Mapper<Object, Text, Text, IntWritable> {  
  2.         public void map(Object key, Text value, OutputCollector<Text, IntWritable> output, Reporter reporter) throws IOException {  
  3.             try {  
  4.                 Emp emp = new Emp(value.toString());  
  5.                 output.collect(new Text(emp.getDeptno()), new IntWritable(Integer.parseInt(emp.getSal())));  //{ k=部门号,v=薪资}  
  6.             } catch (Exception e) {  
  7.                 reporter.getCounter(ErrCount.LINESKIP).increment(1);  
  8.                 WriteErrLine.write("./input/" + this.getClass().getSimpleName() + "err_lines", reporter.getCounter(ErrCount.LINESKIP).getCounter() + " " + value.toString());  
  9.             }  
  10.   
  11.         }  
  12.     }  
  13.   
  14.     public static class Reduce_2 extends MapReduceBase implements Reducer<Text, IntWritable, Text, Text> {  
  15.         public void reduce(Text key, Iterator<IntWritable> values, OutputCollector<Text, Text> output, Reporter reporter) throws IOException {  
  16.             double sum = 0//部门工资  
  17.             int count =0 ; //人数  
  18.             while (values.hasNext()) {  
  19.                 count++;  
  20.                 sum = sum + values.next().get();  
  21.             }  
  22.             output.collect(key, new Text( count+" "+sum/count));  
  23.         }  
  24.   
  25.     }  


运行结果


4.4 分组排序

求每个部门最早进入公司的员工姓名
[java]  view plain  copy
 print ?
  1. public static class Map_3 extends MapReduceBase implements Mapper<Object, Text, Text, Text> {  
  2.     public void map(Object key, Text value, OutputCollector<Text, Text> output, Reporter reporter) throws IOException {  
  3.         try {  
  4.             Emp emp = new Emp(value.toString());  
  5.             output.collect(new Text(emp.getDeptno()), new Text(emp.getHiredate() + "~" + emp.getEname())); // { k=部门号,v=聘期}  
  6.         } catch (Exception e) {  
  7.             reporter.getCounter(ErrCount.LINESKIP).increment(1);  
  8.             WriteErrLine.write("./input/" + this.getClass().getSimpleName() + "err_lines", reporter.getCounter(ErrCount.LINESKIP).getCounter() + " " + value.toString());  
  9.         }  
  10.   
  11.     }  
  12. }  
  13.   
  14. public static class Reduce_3 extends MapReduceBase implements Reducer<Text, Text, Text, Text> {  
  15.     public void reduce(Text key, Iterator<Text> values, OutputCollector<Text, Text> output, Reporter reporter) throws IOException {  
  16.         DateFormat sdf = DateFormat.getDateInstance();  
  17.         Date minDate = new Date(99991230);  
  18.         Date d;  
  19.         String[] strings = null;  
  20.         while (values.hasNext()) {  
  21.             try {  
  22.                 strings = values.next().toString().split("~"); // 获取名字和日期  
  23.                 d = sdf.parse(strings[0].toString().substring(010));  
  24.                 if (d.before(minDate)) {  
  25.                     minDate = d;  
  26.                 }  
  27.             } catch (ParseException e) {  
  28.                 e.printStackTrace();  
  29.             }  
  30.         }  
  31.         output.collect(key, new Text(minDate.toLocaleString() + " " + strings[1]));  
  32.   
  33.     }  
  34.   
  35. }  


运行结果


4.5 多表关联

求各个城市的员工的总工资
[java]  view plain  copy
 print ?
  1. public static class Map_4 extends MapReduceBase implements Mapper<Object, Text, Text, Text> {  
  2.         public void map(Object key, Text value, OutputCollector<Text, Text> output, Reporter reporter) throws IOException {  
  3.             try {  
  4.                 String fileName = ((FileSplit) reporter.getInputSplit()).getPath().getName();  
  5.                 if (fileName.equalsIgnoreCase("emp.txt")) {  
  6.                     Emp emp = new Emp(value.toString());  
  7.                     output.collect(new Text(emp.getDeptno()), new Text("A#" + emp.getSal()));  
  8.                 }  
  9.                 if (fileName.equalsIgnoreCase("dept.txt")) {  
  10.                     Dept dept = new Dept(value.toString());  
  11.                     output.collect(new Text(dept.getDeptno()), new Text("B#" + dept.getLoc()));  
  12.                 }  
  13.             } catch (Exception e) {  
  14.                 reporter.getCounter(ErrCount.LINESKIP).increment(1);  
  15.                 WriteErrLine.write("./input/" + this.getClass().getSimpleName() + "err_lines", reporter.getCounter(ErrCount.LINESKIP).getCounter() + " " + value.toString());  
  16.             }  
  17.   
  18.         }  
  19.     }  
  20.   
  21.     public static class Reduce_4 extends MapReduceBase implements Reducer<Text, Text, Text, Text> {  
  22.         public void reduce(Text key, Iterator<Text> values, OutputCollector<Text, Text> output, Reporter reporter) throws IOException {  
  23.             String deptV;  
  24.             Vector<String> empList = new Vector<String>(); // 保存EMP表的工资数据  
  25.             Vector<String> deptList = new Vector<String>(); // 保存DEPT表的位置数据  
  26.             while (values.hasNext()) {  
  27.                 deptV = values.next().toString();  
  28.                 if (deptV.startsWith("A#")) {  
  29.                     empList.add(deptV.substring(2));  
  30.                 }  
  31.                 if (deptV.startsWith("B#")) {  
  32.                     deptList.add(deptV.substring(2));  
  33.                 }  
  34.             }  
  35.             double sumSal = 0;  
  36.             for (String location : deptList) {  
  37.                 for (String salary : empList) {  
  38.                     //每个城市员工工资总和  
  39.                     sumSal = Integer.parseInt(salary) + sumSal;  
  40.                 }  
  41.                 output.collect(new Text(location), new Text(Double.toString(sumSal)));  
  42.             }  
  43.         }  
  44.   
  45.     }  


运行结果


4.6 单表关联

工资比上司高的员工姓名及其工资
[java]  view plain  copy
 print ?
  1. public static class Map_5 extends MapReduceBase implements Mapper<Object, Text, Text, Text> {  
  2.         public void map(Object key, Text value, OutputCollector<Text, Text> output, Reporter reporter) throws IOException {  
  3.             try {  
  4.                 Emp emp = new Emp(value.toString());  
  5.                 output.collect(new Text(emp.getMgr()), new Text("A#" + emp.getEname() + "~" + emp.getSal()));  // 员工表 { k=上司名,v=员工工资}  
  6.                 output.collect(new Text(emp.getEmpno()), new Text("B#" + emp.getEname() + "~" + emp.getSal()));// “经理表” { k=员工名,v=员工工资}  
  7.             } catch (Exception e) {  
  8.                 reporter.getCounter(ErrCount.LINESKIP).increment(1);  
  9.                 WriteErrLine.write("./input/" + this.getClass().getSimpleName() + "err_lines", reporter.getCounter(ErrCount.LINESKIP).getCounter() + " " + value.toString());  
  10.             }  
  11.         }  
  12.     }  
  13.   
  14.     public static class Reduce_5 extends MapReduceBase implements Reducer<Text, Text, Text, Text> {  
  15.         public void reduce(Text key, Iterator<Text> values, OutputCollector<Text, Text> output, Reporter reporter) throws IOException {  
  16.             String value;  
  17.             Vector<String> empList = new Vector<String>(); // 员工表  
  18.             Vector<String> mgrList = new Vector<String>(); // 经理表  
  19.             while (values.hasNext()) {  
  20.                 value = values.next().toString();  
  21.                 if (value.startsWith("A#")) {  
  22.                     empList.add(value.substring(2));  
  23.                 }  
  24.                 if (value.startsWith("B#")) {  
  25.                     mgrList.add(value.substring(2));  
  26.                 }  
  27.             }  
  28.             String empName, empSal, mgrSal;  
  29.   
  30.             for (String emploee : empList) {  
  31.                 for (String mgr : mgrList) {  
  32.                     String[] empInfo = emploee.split("~");  
  33.                     empName = empInfo[0];  
  34.                     empSal = empInfo[1];  
  35.                     String[] mgrInfo = mgr.split("~");  
  36.                     mgrSal = mgrInfo[1];  
  37.                     if (Integer.parseInt(empSal) > Integer.parseInt(mgrSal)) {  
  38.                         output.collect(key, new Text(empName + " " + empSal));  
  39.                     }  
  40.                 }  
  41.             }  
  42.         }  
  43.   
  44.     }  

运行结果


4.7 TOP N

列出工资最高的头三名员工姓名及其工资
[java]  view plain  copy
 print ?
  1. public static class Map_8 extends MapReduceBase implements Mapper<Object, Text, Text, Text> {  
  2.         public void map(Object key, Text value, OutputCollector<Text, Text> output, Reporter reporter) throws IOException {  
  3.             try {  
  4.                 Emp emp = new Emp(value.toString());  
  5.                 output.collect(new Text("1"), new Text(emp.getEname() + "~" + emp.getSal()));    // { k=随意字符串或数字,v=员工名字+薪资}  
  6.             } catch (Exception e) {  
  7.                 reporter.getCounter(ErrCount.LINESKIP).increment(1);  
  8.                 WriteErrLine.write("./input/" + this.getClass().getSimpleName() + "err_lines", reporter.getCounter(ErrCount.LINESKIP).getCounter() + " " + value.toString());  
  9.             }  
  10.   
  11.         }  
  12.     }  
  13.   
  14.     public static class Reduce_8 extends MapReduceBase implements Reducer<Text, Text, Text, Text> {  
  15.         public void reduce(Text key, Iterator<Text> values, OutputCollector<Text, Text> output, Reporter reporter) throws IOException {  
  16.             Map<Integer, String> emp = new TreeMap<Integer, String>();   // TreeMap默认key升序排列,巧妙利用这点可以实现top N  
  17.             while (values.hasNext()) {  
  18.                 String[] valStrings = values.next().toString().split("~");  
  19.                 emp.put(Integer.parseInt(valStrings[1]), valStrings[0]);  
  20.             }  
  21.             int count = 0// 计数器  
  22.             for (Iterator<Integer> keySet = emp.keySet().iterator(); keySet.hasNext();) {  
  23.                 if (count < 3) {  //  N =3  
  24.                     Integer current_key = keySet.next();  
  25.                     output.collect(new Text(emp.get(current_key)), new Text(current_key.toString())); // 迭代key,即SAL  
  26.                     count++;  
  27.                 } else {  
  28.                     break;  
  29.                 }  
  30.             }  
  31.         }  
  32.     }  

运算结果

4.8 降序排序

将全体员工按照总收入(工资+提成)从高到低排列,要求列出姓名及其总收入
[java]  view plain  copy
 print ?
  1. public static class Map_9 extends MapReduceBase implements Mapper<Object, Text, Text, Text> {  
  2.         public void map(Object key, Text value, OutputCollector<Text, Text> output, Reporter reporter) throws IOException {  
  3.             try {  
  4.                 Emp emp = new Emp(value.toString());  
  5.                 int totalSal = Integer.parseInt(emp.getComm()) + Integer.parseInt(emp.getSal());  
  6.                 output.collect(new Text("1"), new Text(emp.getEname() + "~" + totalSal));  
  7.             } catch (Exception e) {  
  8.                 reporter.getCounter(ErrCount.LINESKIP).increment(1);  
  9.                 WriteErrLine.write("./input/" + this.getClass().getSimpleName() + "err_lines", reporter.getCounter(ErrCount.LINESKIP).getCounter() + " " + value.toString());  
  10.             }  
  11.   
  12.         }  
  13.     }  
  14.   
  15.     public static class Reduce_9 extends MapReduceBase implements Reducer<Text, Text, Text, Text> {  
  16.         public void reduce(Text key, Iterator<Text> values, OutputCollector<Text, Text> output, Reporter reporter) throws IOException {  
  17.             Map<Integer, String> emp = new TreeMap<Integer, String>(  
  18.             // 重写比较器,使降序排列  
  19.                     new Comparator<Integer>() {  
  20.                         public int compare(Integer o1, Integer o2) {  
  21.                             return o2.compareTo(o1);  
  22.                         }  
  23.                     });  
  24.             while (values.hasNext()) {  
  25.                 String[] valStrings = values.next().toString().split("~");  
  26.                 emp.put(Integer.parseInt(valStrings[1]), valStrings[0]);  
  27.             }  
  28.             for (Iterator<Integer> keySet = emp.keySet().iterator(); keySet.hasNext();) {  
  29.                 Integer current_key = keySet.next();  
  30.                 output.collect(new Text(emp.get(current_key)), new Text(current_key.toString())); // 迭代key,即SAL  
  31.             }  
  32.         }  
  33.     }  

运行结果

四.总结

把sql里常用的计算模型写成MR是一件比较麻烦的事,因为很多情况下一行sql估计要十几甚至几十行代码来实现,略显笨拙。但是从数据计算速度来说,MR跟sql不是一个级别的。
但不可否认的一点是,无论是什么技术都有各自的适用范围,MR不是万能的,具体要看使用场景再选择适当的技术。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值