MapReduce实现TopK的示例
由于开始学习MapReduce编程已经有一段时间了,作为一个从编程中寻找自信和乐趣以及热爱编程的孩子来讲,手开始变得很“痒”了,很想小试一下身手。于是自己编写了TopK的代码。TopK的意思就是从原文件中找出词频排名前K的所有单词。首先分析该问题,从中我们可以得到启发:要想知道词频排名前K的所有单词,那么是不是要对所有的单词进行词频的统计啊?于是我们就联想到了一个比较经典的例子:WordCount的例子。是的,没错。就是它,统计原文件中每个单词的个数就靠它。
但是,我们词频统计出来了,接下来需要做的就是如何找出词频排名前K的所有单词。如何找出词频排名前K呢?我们知道,WordCount得到的结果就是所有单词的词频情况,并且是已排好序的。所以,我们接下来需要做的是:
1、将所有相同词频的单词汇总,这一步就是map之后的shuffle过程可以得到相应的结果,只需要在map阶段将词频作为key,单词多作为value即可。
2、找出排名前k的词频的所有单词,并且按照词频的顺序排序,在这一步当中,很多人通过采用TreeMap的数据结构来实现,但是这里要注意点,TreeMap对于相同的键值是会进行覆盖的。因此无法操作相同键值的数据。也有些人对key进行封装,但同样还是避免不了有相同键值的结果。因此,我在这里采用的方法是将所有词频相同的单词用ArrayList存放起来,最后在将ArrayList的内容写入待hdfs中即可。
综上所述,要实现TopK的结果,需要用到两个MR作业,一个是WordCount作业,一个是TopK的作业。
代码如下:
1、WordCount的部分:
import java.io.IOException;
import java.util.StringTokenizer; 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.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; public class MyTopK { public static class Mymap extends Mapper<LongWritable, Text, Text, IntWritable>{ private final IntWritable one =new IntWritable(1);
private Text word =new Text(); public void map(LongWritable ikey,Text ivalue,Context context) throws IOException, InterruptedException{
StringTokenizer str=new StringTokenizer(ivalue.toString());
while(str.hasMoreTokens()){
word.set(str.nextToken());
context.write(word, one);
}
}
} public static class Myreduce extends Reducer<Text, IntWritable, Text, IntWritable>{
private IntWritable result=new IntWritable(); public void reduce(Text ikey,Iterable<IntWritable> ivalue,
Context context) throws IOException, InterruptedException{
int sum=0;
for(IntWritable val:ivalue){
sum+=val.get();
}
result.set(sum);
context.write(ikey, result);
}
} //设置静态的函数,方便直接在main中通过类名 来调用
public static boolean run(String in ,String out) throws IOException, ClassNotFoundException, InterruptedException{ Configuration conf =new Configuration(); Job job=new Job(conf,"Wordcount");
job.setJarByClass(MyTopK.class);
job.setMapperClass(Mymap.class);
job.setReducerClass(Myreduce.class); //设置map输出类型
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(IntWritable.class); //设置reduce的输出类型
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class); //设置输入输出路径
FileInputFormat.addInputPath(job, new Path(in));
FileOutputFormat.setOutputPath(job, new Path(out)); return job.waitForCompletion(true);
}
}
2、TopK的实现过程
import java.io.IOException;
import java.util.Map.Entry;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.TreeMap;
import java.util.regex.Pattern; 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.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.mapreduce.lib.output.MultipleOutputs;
import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat; public class MyTopK1 { public static class MyMap extends Mapper<LongWritable, Text, IntWritable, Text>{ IntWritable outkey=new IntWritable();
Text outvalue=new Text(); public void map(LongWritable ikey,Text ivalue,Context context) throws IOException, InterruptedException{
StringTokenizer str=new StringTokenizer(ivalue.toString());
while(str.hasMoreTokens()){
//这个表示是输入数据的每行数据,每一行包含了单词和单词的次数,这个内容否在ivalue中,下面需要将ivalue中的单词和单词的次数进行分离。
String element=str.nextToken();
if(Pattern.matches("\\d+", element)){//这里利用正则表达式来匹配单词的个数
outkey.set(Integer.parseInt(element));//将单词的个数作为键值
}else {
outvalue.set(element);//将单词作为键值值
}
}
context.write(outkey, outvalue);//在写的过程中会对单词的次数进行排序
} } public static TreeMap<Integer, ArrayList<String> > hm =new TreeMap<Integer, ArrayList<String> >(new Comparator<Integer>() {
public int compare(Integer v1,Integer v2){
return v2.compareTo(v1);
}
});//用来选择出topK
private static MultipleOutputs<Text, IntWritable> mos=null;//用来进行多文件输出 private static String path=null; //通过shuffle过程之后,相同次数的单词就在一起了,并将这个数据作为reduce的输入数据
public static class Myreduce extends Reducer<IntWritable, Text, Text, IntWritable>{ public void reduce(IntWritable ikey,Iterable<Text> ivalue,Context context) throws IOException,
InterruptedException{
ArrayList<String> tmp=new ArrayList<String>(10);
for(Text val:ivalue){
context.write(val,ikey);//输出全排序的内容
// tmp.add(val.toString()); //这里会造成占用较多的内存,这里可以优化 //优化的方法就是限定列表的长度,由于是topk,所以每一个最多也就是10个即可
if(tmp.size()<=10){
tmp.add(val.toString());
}
}
hm.put(ikey.get(), tmp);
} private static int topKNUM=10; //表示求最高的多少个数
protected void cleanup(Context context) throws IOException,
InterruptedException {
//String path = context.getConfiguration().get("topKout");
mos = new MultipleOutputs<Text, IntWritable>(context);
Set<Entry<Integer, ArrayList<String> > > set = hm.entrySet(); for (Entry<Integer, ArrayList<String>> entry : set) {
ArrayList<String> al = entry.getValue();
if (topKNUM-al.size() > 0) {
for (String word : al) {
//if (topKNUM-- > 0) {
mos.write("topKMOS", new Text(word), // 这里参数“topKMOS”表示一个属性名称
new IntWritable(entry.getKey()), path);
//}
}
}
}
mos.close();
} }
@SuppressWarnings("deprecation")
public static void run(String in,String out,String topkout) throws IOException, ClassNotFoundException, InterruptedException{ Configuration conf=new Configuration(); //创建作业,并制定map和reduce类 Job job=new Job(conf);
job.setJarByClass(MyTopK1.class);
job.setMapperClass(MyMap.class);
job.setReducerClass(Myreduce.class); //TopK的输出路径
path=topkout;
//conf.set("topKout",topkout); //设置map输出的类型
job.setMapOutputKeyClass(IntWritable.class);
job.setMapOutputValueClass(Text.class); //设置reduce的输出类型
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class); //设置MultipleOutputs输出格式,//这里的第二个参数“topKMOS”要跟write方法中的参数相同
MultipleOutputs.addNamedOutput(job, "topKMOS",TextOutputFormat.class, Text.class, IntWritable.class); //设置输入输出格式
FileInputFormat.addInputPath(job, new Path(in));
FileOutputFormat.setOutputPath(job, new Path(out)); //提交作业
job.waitForCompletion(true);
}
}
3、程序的入口
import java.io.IOException;
import org.apache.log4j.PropertyConfigurator;
public class TopKmain {
public static void main(String[] args) throws ClassNotFoundException, IOException, InterruptedException {
// TODO Auto-generated method stub、、
//这里要记住一点,手动加载一些log4j文件,一来可以去掉警告,二来可以在出现错误时,通过查看日志,了解错误详细内容
String rootPath = System.getProperty("user.dir" );
PropertyConfigurator.configure(rootPath+"\\log4j.properties");
//要统计字数,排序的文字
String in = "hdfs://192.168.1.21:9000/input";
//统计字数后的结果
String wordCoutoutput = "hdfs://192.168.1.21:9000/out";
//对统计完后的结果再排序后的内容
String sort = "hdfs://192.168.1.21:9000/sort";
//指定前K条输出的文件名称
String topK = "hdfs://192.168.1.21:9000/topK";
//如果统计字数的job完成后就开始排序
if(MyTopK.run(in, wordCoutoutput)){
MyTopK1.run(wordCoutoutput, sort,topK);
}
}
}
MapReduce实现TopK的示例的更多相关文章
- MapReduce框架结构及代码示例
一个完整的 mapreduce 程序在分布式运行时有三类实例进程: 1.MRAppMaster:负责整个程序的过程调度及状态协调 2.MapTask:负责 map 阶段的整个数据处理流程 3.Redu ...
- MapReduce 编程模型 & WordCount 示例
学习大数据接触到的第一个编程思想 MapReduce. 前言 之前在学习大数据的时候,很多东西很零散的做了一些笔记,但是都没有好好去整理它们,这篇文章也是对之前的笔记的整理,或者叫输出吧.一来是加 ...
- MongoDB的MapReduce用法及php示例代码
MongoDB虽然不像我们常用的mysql,sqlserver,oracle等关系型数据库有group by函数那样方便分组,但是MongoDB要实现分组也有3个办法: * Mongodb三种分组方式 ...
- hadoop学习第三天-MapReduce介绍&&WordCount示例&&倒排索引示例
一.MapReduce介绍 (最好以下面的两个示例来理解原理) 1. MapReduce的基本思想 Map-reduce的思想就是“分而治之” Map Mapper负责“分”,即把复杂的任务分解为若干 ...
- MapReduce原理与设计思想
简单解释 MapReduce 算法 一个有趣的例子 你想数出一摞牌中有多少张黑桃.直观方式是一张一张检查并且数出有多少张是黑桃? MapReduce方法则是: 给在座的所有玩家中分配这摞牌 让每个玩家 ...
- 使用MapReduce实现一些经典的案例
在工作中,很多时候都是用hive或pig来自动化执行mr统计,但是我们不能忘记原始的mr.本文记录了一些通过mr来完成的经典的案例,有倒排索引.数据去重等,需要掌握. 一.使用mapreduce实现倒 ...
- MapReduce极简教程
一个有趣的例子 你想数出一摞牌中有多少张黑桃.直观方式是一张一张检查并且数出有多少张是黑桃? MapReduce方法则是: 给在座的所有玩家中分配这摞牌 让每个玩家数自己手中的牌有几张是黑桃,然后 ...
- 大数据 --> MapReduce原理与设计思想
MapReduce原理与设计思想 简单解释 MapReduce 算法 一个有趣的例子:你想数出一摞牌中有多少张黑桃.直观方式是一张一张检查并且数出有多少张是黑桃? MapReduce方法则是: 给在座 ...
- 指导手册04:运行MapReduce
指导手册04:运行MapReduce Part 1:运行单个MapReduce任务 情景描述: 本次任务要求对HDFS目录中的数据文件/user/root/email_log.txt进行计算处理, ...
随机推荐
- (转)springAOP解析-2
原文地址:http://hzbook.group.iteye.com/group/wiki/2262-Spring 3.3.4 AOP拦截器链的调用在了解了对目标对象的直接调用以后,我们开始进入AO ...
- 打不开chm文件解决办法
打不开chm文件解决办法.bat regsvr32 itss.dll /sregsvr32 hhctrl.ocx /s
- DSP基础学习-ADC同步采样
DSP基础学习-ADC同步采样 彭会锋 2015-04-28 20:31:06 在DSP28027 LauchPad学习过程中,关于ADC同步采样和顺序采样的区别稍加研究了一下,发现里面还真有些门道, ...
- WPF:行列显示
新建显示病人信息控件PatientElement Add-->NewItem-->WPF-->UserControl(WPF),名称:PatientElement.xmal < ...
- 在CentOS 7 MySQL / MariaDB
在CentOS7中,MariaDB 替代了MySQL;更多复杂的疑问可以在这里查看 MariaDB versus MySQL – Compatibility Install MySQL / Mari ...
- 最小生成树练习3(普里姆算法Prim)
风萧萧兮易水寒,壮士要去敲代码.本女子开学后再敲了.. poj1258 Agri-Net(最小生成树)水题. #include<cstdio> #include<cstring> ...
- abap注意
1.建表的时候所有的数据元素的总长度不能超过1024. 2.表的主键修改在se11激活不成功,但是可以在se11保存,然后到se14中激活. 3.SM12解锁,在很多时候,经常出现某个表或者可修改的地 ...
- eclipse中SVN分支合并到主干
在项目开发中,需要添加一些新的功能,但是又不想影响到其他开发人员的项目进度,所以决定使用SVN分支进行开发,分支开发完毕后再合并到主干.本文介绍如何在eclipse中合并分支到主干. 1. 要想将分支 ...
- enum使用总结
enum的一般使用方法是它会占用最大的成员长度 然后我忘记的是enum还可以这样使用 enum ExctState { START, SUCCEED, FAILURE=6, REJECT, }; 这样 ...
- FaceBook Twitter实习生简历求内推
写在博客里面吧. 有一个朋友,男,博士在读,研究方向为图像处理,计算机视觉相关. 想在在读期间有一些海外实习经历.不知道哪位博友,有相关的人脉,求内推啊.内推成功的话请吃大餐,哈哈!