Hadoop的ChainMapper和ChainReducer使用案例(链式处理)(四)
不多说,直接上干货!
Hadoop的MR作业支持链式处理,类似在一个生产牛奶的流水线上,每一个阶段都有特定的任务要处理,比如提供牛奶盒,装入牛奶,封盒,打印出厂日期,等等,通过这样进一步的分工,从而提高了生产效率,那么在我们的Hadoop的MapReduce中也是如此,支持链式的处理方式,这些Mapper像Linux管道一样,前一个Mapper的输出结果直接重定向到下一个Mapper的输入,形成一个流水线,而这一点与Lucene和Solr中的Filter机制是非常类似的,Hadoop项目源自Lucene,自然也借鉴了一些Lucene中的处理方式。
举个例子,比如处理文本中的一些禁用词,或者敏感词,等等,Hadoop里的链式操作,支持的形式类似正则Map+ Rrduce Map*,代表的意思是全局只能有一个唯一的Reduce,但是在Reduce的前后是可以存在无限多个Mapper来进行一些预处理或者善后工作的。
注意:
1. 本人目前使用的版本是1.2.1,因此ChainMapper使用的还是old api。
2. 老的API之中,只支持 N-Mapper + 1-Reducer的模式。 Reducer不在链式任务最开始即可。
比如:
Map1 -> Map2 -> Reducer -> Map3 -> Map4
(不确定在新版的API之中是否支持 N-Reducer的模式。不过new api 确实要简单简洁很多)

在编程的时候,我们可以借用源码提供给我们的程序!在此基础上进行修改和编写。
比如我的源码本地目录如下:(找我的本地ChainMapper和ChainReducer案例)
D:\SoftWare\hadoop-2.2.0-src\hadoop-mapreduce-project\hadoop-mapreduce-client\hadoop-mapreduce-client-core\src\main\java\org\apache\hadoop\mapreduce\lib\chain

任务介绍:
这个任务需要两步完成:
1. 对一篇文章进行WordCount
2. 统计出现次数超过5词的单词
WordCount我们很熟悉,因为版本限制,先使用old api 实现一次:
Java代码
- package hadoop_in_action_exersice;
- import java.io.IOException;
- import java.util.Iterator;
- import java.util.StringTokenizer;
- import org.apache.hadoop.fs.FileSystem;
- 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.mapred.FileInputFormat;
- import org.apache.hadoop.mapred.FileOutputFormat;
- import org.apache.hadoop.mapred.JobClient;
- import org.apache.hadoop.mapred.JobConf;
- import org.apache.hadoop.mapred.MapReduceBase;
- import org.apache.hadoop.mapred.Mapper;
- import org.apache.hadoop.mapred.OutputCollector;
- import org.apache.hadoop.mapred.Reducer;
- import org.apache.hadoop.mapred.Reporter;
- import org.apache.hadoop.mapred.TextInputFormat;
- import org.apache.hadoop.mapred.TextOutputFormat;
- public class ChainedJobs {
- public static class TokenizeMapper extends MapReduceBase implements Mapper<LongWritable, Text, Text, IntWritable> {
- private final static IntWritable one = new IntWritable(1);
- public static final int LOW_LIMIT = 5;
- @Override
- public void map(LongWritable key, Text value,
- OutputCollector<Text, IntWritable> output, Reporter reporter)
- throws IOException {
- String line = value.toString();
- StringTokenizer st = new StringTokenizer(line);
- while(st.hasMoreTokens())
- output.collect(new Text(st.nextToken()), one);
- }
- }
- public static class TokenizeReducer extends MapReduceBase implements Reducer<Text, IntWritable, Text, IntWritable> {
- @Override
- public void reduce(Text key, Iterator<IntWritable> values,
- OutputCollector<Text, IntWritable> output, Reporter reporter)
- throws IOException {
- int sum = 0;
- while(values.hasNext()) {
- sum += values.next().get();
- }
- output.collect(key, new IntWritable(sum));
- }
- }
- public static void main(String[] args) throws IOException {
- JobConf conf = new JobConf(ChainedJobs.class);
- conf.setJobName("wordcount"); //设置一个用户定义的job名称
- conf.setOutputKeyClass(Text.class); //为job的输出数据设置Key类
- conf.setOutputValueClass(IntWritable.class); //为job输出设置value类
- conf.setMapperClass(TokenizeMapper.class); //为job设置Mapper类
- conf.setCombinerClass(TokenizeReducer.class); //为job设置Combiner类
- conf.setReducerClass(TokenizeReducer.class); //为job设置Reduce类
- conf.setInputFormat(TextInputFormat.class); //为map-reduce任务设置InputFormat实现类
- conf.setOutputFormat(TextOutputFormat.class); //为map-reduce任务设置OutputFormat实现类
- // Remove output folder before run job(s)
- FileSystem fs=FileSystem.get(conf);
- String outputPath = "/home/hadoop/DataSet/Hadoop/WordCount-OUTPUT";
- Path op=new Path(outputPath);
- if (fs.exists(op)) {
- fs.delete(op, true);
- System.out.println("存在此输出路径,已删除!!!");
- }
- FileInputFormat.setInputPaths(conf, new Path("/home/hadoop/DataSet/Hadoop/WordCount"));
- FileOutputFormat.setOutputPath(conf, new Path(outputPath));
- JobClient.runJob(conf); //运行一个job
- }
- }
上面是独立的一个Job,完成第一步。为了能紧接着完成第二步,我们需要在原来的基础上进行修改。
为了方便理解,上面的输入的例子如下:
Java代码
- accessed 3
- accessible 4
- accomplish 1
- accounting 7
- accurately 1
- acquire 1
- across 1
- actual 1
- actually 1
- add 3
- added 2
- addition 1
- additional 4
old api 的实现方式并不支持 setup() / cleanup() 操作这一点非常不好,因此在有可能的情况下最好还是要迁移到Hadoop 2.X
新的API会方便简洁很多
下面是增加了一个Mapper 来过滤
Java代码
- public static class RangeFilterMapper extends MapReduceBase implements Mapper<Text, IntWritable, Text, IntWritable> {
- @Override
- public void map(Text key, IntWritable value,
- OutputCollector<Text, IntWritable> output, Reporter reporter)
- throws IOException {
- if(value.get() >= LOW_LIMIT) {
- output.collect(key, value);
- }
- }
- }
这个Mapper做的事情很简单,就是针对每个key,如果他的value > LOW_LIMIT 那么就输出
所以,目前为止,任务链如下:
TokenizerMapper -> TokenizeReducer -> RangeFilterMapper
所以我们的main函数改成下面的样子:
Java代码
- public static void main(String[] args) throws IOException {
- JobConf conf = new JobConf(ChainedJobs.class);
- conf.setJobName("wordcount"); //设置一个用户定义的job名称
- // conf.setOutputKeyClass(Text.class); //为job的输出数据设置Key类
- // conf.setOutputValueClass(IntWritable.class); //为job输出设置value类
- // conf.setMapperClass(TokenizeMapper.class); //为job设置Mapper类
- // conf.setCombinerClass(TokenizeReducer.class); //为job设置Combiner类
- // conf.setReducerClass(TokenizeReducer.class); //为job设置Reduce类
- // conf.setInputFormat(TextInputFormat.class); //为map-reduce任务设置InputFormat实现类
- // conf.setOutputFormat(TextOutputFormat.class); //为map-reduce任务设置OutputFormat实现类
- // Step1 : mapper forr word count
- JobConf wordCountMapper = new JobConf(false);
- ChainMapper.addMapper(conf,
- TokenizeMapper.class,
- LongWritable.class, // input key type
- Text.class, // input value type
- Text.class, // output key type
- IntWritable.class, // output value type
- false, //byValue or byRefference 传值还是传引用
- wordCountMapper);
- // Step2: reducer for word count
- JobConf wordCountReducer = new JobConf(false);
- ChainReducer.setReducer(conf,
- TokenizeReducer.class,
- Text.class,
- IntWritable.class,
- Text.class,
- IntWritable.class,
- false,
- wordCountReducer);
- // Step3: mapper used as filter
- JobConf rangeFilterMapper = new JobConf(false);
- ChainReducer.addMapper(conf,
- RangeFilterMapper.class,
- Text.class,
- IntWritable.class,
- Text.class,
- IntWritable.class,
- false,
- rangeFilterMapper);
- // Remove output folder before run job(s)
- FileSystem fs=FileSystem.get(conf);
- String outputPath = "/home/hadoop/DataSet/Hadoop/WordCount-OUTPUT";
- Path op=new Path(outputPath);
- if (fs.exists(op)) {
- fs.delete(op, true);
- System.out.println("存在此输出路径,已删除!!!");
- }
- FileInputFormat.setInputPaths(conf, new Path("/home/hadoop/DataSet/Hadoop/WordCount"));
- FileOutputFormat.setOutputPath(conf, new Path(outputPath));
- JobClient.runJob(conf); //运行一个job
- }
下面是运行结果的一部分:
Java代码
- a 40
- and 26
- are 12
- as 6
- be 7
- been 8
- but 5
- by 5
- can 12
- change 5
- data 5
- files 7
- for 28
- from 5
- has 7
- have 8
- if 6
- in 27
- is 16
- it 13
- more 8
- not 5
- of 23
- on 5
- outputs 5
- see 6
- so 11
- that 11
- the 54
可以看到,英文之中,如果NLP不去除停用词(a, the, for ...) 等,效果确实会被大大的影响。
Hadoop的ChainMapper和ChainReducer使用案例(链式处理)(四)的更多相关文章
- Hadoop工作流--ChainMapper/ChainReducer?(三)
不多说,直接上干货! Hadoop的ChainMapper和ChainReducer使用案例(链式处理) 什么是ChainMapper/ChainReducer?
- 组合式+迭代式+链式 MapReduce
1.迭代式mapreduce 一些复杂的任务难以用一次mapreduce处理完成,需要多次mapreduce才能完成任务,例如Pagrank,Kmeans算法都需要多次的迭代,关于mapreduce迭 ...
- MR案例:链式ChainMapper
类似于Linux管道重定向机制,前一个Map的输出直接作为下一个Map的输入,形成一个流水线.设想这样一个场景:在Map阶段,数据经过mapper01和mapper02处理:在Reduce阶段,数据经 ...
- Hadoop基础-Map端链式编程之MapReduce统计TopN示例
Hadoop基础-Map端链式编程之MapReduce统计TopN示例 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.项目需求 对“temp.txt”中的数据进行分析,统计出各 ...
- Hadoop生态圈-Knox网关的应用案例
Hadoop生态圈-Knox网关的应用案例 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.Knox网关简介 据Knox官网所述(http://knox.apache.org/) ...
- Apache Hadoop 2.9.2 的归档案例剖析
Apache Hadoop 2.9.2 的归档案例剖析 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 能看到这篇文章说明你对NameNode 工作原理是有深入的理解啦!我们知道 ...
- Hadoop生态圈-CDH与HUE使用案例
Hadoop生态圈-CDH与HUE使用案例 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.HUE的介绍 1>.HUE的由来 HUE全称是HadoopUser Experi ...
- hadoop一代集群运行代码案例
hadoop一代集群运行代码案例 集群 一个 master,两个slave,IP分别是192.168.1.2.192.168.1.3.192.168.1.4 hadoop版 ...
- Hadoop基础-MapReduce的Partitioner用法案例
Hadoop基础-MapReduce的Partitioner用法案例 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.Partitioner关键代码剖析 1>.返回的分区号 ...
随机推荐
- because joins aren’t as important.
“MongoDB wasn’t designed in a lab. We built MongoDB from our own experiences building large-scale, h ...
- JS中prototype,js原型扩展
作者:轩脉刃(yjf512)出处:(http://www.cnblogs.com/yjf512/)版权声明:本文的版权归作者与博客园共有.欢迎转载阅读,转载时须注明本文的详细链接. 原文 http:/ ...
- node安装与升级
node安装与升级 1.安装 sudo apt-get install nodejs sudo apt-get install npm 2.升级 如果node不是最新的,node有一个模块叫n,是专门 ...
- POJ - 2142 The Balance(扩展欧几里得求解不定方程)
d.用2种砝码,质量分别为a和b,称出质量为d的物品.求所用的砝码总数量最小(x+y最小),并且总质量最小(ax+by最小). s.扩展欧几里得求解不定方程. 设ax+by=d. 题意说不定方程一定有 ...
- JRE System Library 与Java EE Libraries的区别
JRE System Library是只要做java开发都需要的完整的.标准的库. Java EE5 Libraries只是java三个方向中做java EE所需要的库.如果做Web方面的开发的话就 ...
- 各种java生成word解决方案的优缺点对比
解决方案 优点 缺点 Jacob 功能强大 直接调用VBA接口,程序异常复杂:服务器必须是:windows系统+安装Office:服务器端自动化com接口容易产生死进程造成服务器宕机 Apache P ...
- MD5Util1
package com.cc.hkjc.util; import java.math.BigInteger;import java.security.MessageDigest;import java ...
- string类中运算符重载实现
C++中预定义的加.减等运算符的操作对象只能是基本的数据类型.如果要在用户自定义的类型对象上应用同样的运算符,就需要通过运算符重载来重新定义其实现,使它能够用于自定义类型执行特定的操作,所以运算符重载 ...
- hihoCoder 1032
最长回文子串的O(1)算法Manacher算法 #include <iostream> #include <stdio.h> #include <string.h> ...
- 自己动手搭建SSM
1.工具 apache-tomcat 7 apache-maven(后面详细讲!这东西我一开始也很懵逼) mysql 5以上的版本 navicat(有了这个就不用cmd了,可以直接显示数据库,如下图, ...