链式MapReduce:ChainMapper和ChainReducer

一:背景

Hadoop2.0开始MapReduce作业支持链式处理,类似于富士康生产苹果手机的流水线,每一个阶段都有特定的任务要处理,比如提供原配件——>组装——打印出厂日期,等等。通过这样进一步的分工,从而提高了生成效率,我们Hadoop中的链式MapReduce也是如此,这些Mapper可以像水流一样,一级一级向后处理,有点类似于Linux的管道。前一个Mapper的输出结果直接可以作为下一个Mapper的输入,形成一个流水线。

注:链式MapReduce的执行规则:整个Job中只能有一个Reducer,在Reducer前面可以有一个或者多个Mapper,在Reducer的后面可以有0个或者多个Mapper。


二:技术实现

#需求:现有如下销售数据,要求使用链式MapReduce,在第一个Mapper中过滤金额大于10000的数据,在第二个Mapper中过滤数据在100-10000之间的数据,在Reduce中进行分类汇总,在Reduce后面的Mapper中过滤掉商品名长度大于8的数据。

  1. Phone 5000
  2. Computer 2000
  3. Clothes 300
  4. XieZi 1200
  5. QunZi 434
  6. ShouTao 12
  7. Books 12510
  8. SmallShangPing 5
  9. SmallShangPing 3
  10. DingCan 2


实现代码:

  1. public class ChainMapReduce {
  2. // 定义输入输出路径
  3. private static final String INPUTPATH = "hdfs://liaozhongmin21:8020/chainFiles/*";
  4. private static final String OUTPUTPATH = "hdfs://liaozhongmin21:8020/out";
  5. public static void main(String[] args) {
  6. try {
  7. Configuration conf = new Configuration();
  8. // 创建文件系统
  9. FileSystem fileSystem = FileSystem.get( new URI(OUTPUTPATH), conf);
  10. // 判断输出路径是否存在,如果存在则删除
  11. if (fileSystem.exists( new Path(OUTPUTPATH))) {
  12. fileSystem.delete( new Path(OUTPUTPATH), true);
  13. }
  14. // 创建Job
  15. Job job = new Job(conf, ChainMapReduce.class.getSimpleName());
  16. // 设置输入目录
  17. FileInputFormat.addInputPath(job, new Path(INPUTPATH));
  18. // 设置输入文件格式
  19. job.setInputFormatClass(TextInputFormat.class);
  20. // 设置自定义的Mapper类
  21. ChainMapper.addMapper(job, FilterMapper1.class, LongWritable.class, Text.class, Text.class, DoubleWritable.class, conf);
  22. ChainMapper.addMapper(job, FilterMapper2.class, Text.class, DoubleWritable.class, Text.class, DoubleWritable.class, conf);
  23. ChainReducer.setReducer(job, SumReducer.class, Text.class, DoubleWritable.class, Text.class, DoubleWritable.class, conf);
  24. // 注:Reducer后面的Mapper也要用ChainReducer进行加载
  25. ChainReducer.addMapper(job, FilterMapper3.class, Text.class, DoubleWritable.class, Text.class, DoubleWritable.class, conf);
  26. // 设置自定义Mapper类的输出key和value
  27. job.setMapOutputKeyClass(Text.class);
  28. job.setMapOutputValueClass(DoubleWritable.class);
  29. // 设置分区
  30. job.setPartitionerClass(HashPartitioner.class);
  31. // 设置reducer数量
  32. job.setNumReduceTasks( 1);
  33. // 设置自定义的Reducer类
  34. // 设置输出的Key和value类型
  35. job.setOutputKeyClass(Text.class);
  36. job.setOutputValueClass(DoubleWritable.class);
  37. // 设置输出路径
  38. FileOutputFormat.setOutputPath(job, new Path(OUTPUTPATH));
  39. // 设置输出格式
  40. job.setOutputFormatClass(TextOutputFormat.class);
  41. // 提交任务
  42. System.exit(job.waitForCompletion( true) ? 0 : 1);
  43. } catch (Exception e) {
  44. e.printStackTrace();
  45. }
  46. }
  47. /**
  48. * 过滤掉金额大于10000的记录
  49. * @author 廖钟民 2015年3月17日下午6:27:05
  50. */
  51. public static class FilterMapper1 extends Mapper<LongWritable, Text, Text, DoubleWritable> {
  52. // 定义输出的key和value
  53. private Text outKey = new Text();
  54. private DoubleWritable outValue = new DoubleWritable();
  55. @Override
  56. protected void map(LongWritable key, Text value, Mapper<LongWritable, Text, Text, DoubleWritable>.Context context) throws IOException,
  57. InterruptedException {
  58. // 获取行文本内容
  59. String line = value.toString();
  60. if (line.length() > 0) {
  61. // 对行文本内容进行切分
  62. String[] splits = line.split( "\t");
  63. // 获取money
  64. double money = Double.parseDouble(splits[ 1].trim());
  65. // 过滤
  66. if (money <= 10000) {
  67. // 设置合法结果
  68. outKey.set(splits[ 0]);
  69. outValue.set(money);
  70. // 把合法结果写出去
  71. context.write(outKey, outValue);
  72. }
  73. }
  74. }
  75. }
  76. /**
  77. * 过滤掉金额大于100的记录
  78. * @author 廖钟民 2015年3月17日下午6:29:27
  79. */
  80. public static class FilterMapper2 extends Mapper<Text, DoubleWritable, Text, DoubleWritable> {
  81. @Override
  82. protected void map(Text key, DoubleWritable value, Mapper<Text, DoubleWritable, Text, DoubleWritable>.Context context) throws IOException,
  83. InterruptedException {
  84. if (value.get() < 100) {
  85. // 把结果写出去
  86. context.write(key, value);
  87. }
  88. }
  89. }
  90. /**
  91. * 金额汇总
  92. * @author 廖钟民
  93. *2015年3月21日下午1:46:47
  94. */
  95. public static class SumReducer extends Reducer<Text, DoubleWritable, Text, DoubleWritable> {
  96. // 定义输出的value
  97. private DoubleWritable outValue = new DoubleWritable();
  98. @Override
  99. protected void reduce(Text key, Iterable<DoubleWritable> values, Reducer<Text, DoubleWritable, Text, DoubleWritable>.Context context)
  100. throws IOException, InterruptedException {
  101. // 定义汇总结果
  102. double sum = 0;
  103. // 遍历结果集进行统计
  104. for (DoubleWritable val : values) {
  105. sum += val.get();
  106. }
  107. // 设置输出value
  108. outValue.set(sum);
  109. // 把结果写出去
  110. context.write(key, outValue);
  111. }
  112. }
  113. /**
  114. * 过滤商品名称长度小于8的商品
  115. * @author 廖钟民
  116. *2015年3月21日下午1:47:01
  117. */
  118. public static class FilterMapper3 extends Mapper<Text, DoubleWritable, Text, DoubleWritable> {
  119. @Override
  120. protected void map(Text key, DoubleWritable value, Mapper<Text, DoubleWritable, Text, DoubleWritable>.Context context) throws IOException,
  121. InterruptedException {
  122. // 过滤
  123. if (key.toString().length() < 8) {
  124. // 把结果写出去
  125. System.out.println( "写出去的内容为:" + key.toString() + "++++"+ value.toString());
  126. context.write(key, value);
  127. }
  128. }
  129. }
  130. }
注:驱动类中Reducer后面的Mapper必须应该通过ChainReducer来添加!


输出结果:


版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lzm1340458776/article/details/44976371
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值