十二道MR习题 - 4 - TopN问题
题目:
有一个很大的文件,这文件中的内容全部都是数字,要求尝试从这个文件中找出最大的10个数字。
分析:
看起来像是一个比较简单的问题。不用大数据框架的话,也能比较轻易的实现:就是逐个读取文件中的每个数字,放到一个大顶堆结构中;将大顶堆放满以后,每读取一个数字就将之和大顶堆中的最小值进行比较,如果其大于这个最小值的话,就将其放入堆中,并将堆中的最小值删除;这样读取到最后,堆中剩下来的内容就是top 10了。
用MapReduce实现的话也说不上困难:我们只使用Map任务读取文件,而reduce中输出的内容就是一个有序的结果集,那么后十位自然就是Top10了。这方案虽说可行,但绝说不上是好的方案。
换个思路:map任务中先完成一轮过滤(没必要多添一重Combiner),先取出每个Map中的top10来,而后在reduce中再进行一轮筛选,从所有map的top10中再选出个top10来。这样处理效率应该会高一些。
看看实现过程:
package com.zhyea.dev; import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.NullWritable;
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.slf4j.Logger;
import org.slf4j.LoggerFactory; import java.io.IOException;
import java.util.TreeSet; public class TopN { private static final Logger logger = LoggerFactory.getLogger(TopN.class); public static class SplitterMapper extends Mapper<Object, Text, IntWritable, NullWritable> { private static final IntWritable intWritable = new IntWritable(); private static final TreeSet<Integer> set = new TreeSet<>(); @Override
public void map(Object key, Text value, Context context) {
int num = Integer.valueOf(value.toString()); if (set.size() < 10) {
set.add(num);
return;
} if (num > set.first()) {
set.add(num);
set.pollFirst();
}
} @Override
public void cleanup(Context context) {
for (Integer i : set) {
intWritable.set(i);
try {
context.write(intWritable, NullWritable.get());
} catch (Exception e) {
e.printStackTrace();
}
}
}
} public static class IntegrateReducer extends Reducer<IntWritable, NullWritable, IntWritable, NullWritable> { private static final IntWritable intWritable = new IntWritable();
private static final TreeSet<Integer> set = new TreeSet<>(); @Override
public void reduce(IntWritable key, Iterable<NullWritable> values, Context context) {
try {
int num = key.get();
if (set.size() < 10) {
set.add(num);
return;
} if (num > set.first()) {
set.add(num);
set.pollFirst();
}
} catch (Exception e) {
e.printStackTrace();
}
} @Override
public void cleanup(Context context) {
for (Integer i : set) {
intWritable.set(i);
try {
context.write(intWritable, NullWritable.get());
} catch (Exception e) {
e.printStackTrace();
}
}
} } public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException { Configuration conf = new Configuration(); Job job = Job.getInstance(conf, "top-n");
job.setJarByClass(TopN.class); job.setMapperClass(SplitterMapper.class);
job.setReducerClass(IntegrateReducer.class); job.setOutputKeyClass(IntWritable.class);
job.setOutputValueClass(NullWritable.class); FileInputFormat.addInputPath(job, new Path(args[0]));
FileOutputFormat.setOutputPath(job, new Path(args[1])); System.exit(job.waitForCompletion(true) ? 0 : 1);
} }
程序里在map或reduce方法中没有做任何输出,只是实现了比较逻辑,真正的输出是在cleanup方法中完成的。
用spark实现的话可以先做全排序,然后排重,take前N个记录就可以了。当然也可以按照上面的思路来做实现,下面的代码就是按照我们前面的思路来做的实现:
package com.zhyea.dev
import java.util
import org.apache.hadoop.io.{LongWritable, Text}
import org.apache.hadoop.mapred.TextInputFormat
import org.apache.spark.{SparkConf, SparkContext}
import collection.JavaConversions.asScalaIterator
object TopTen {
def main(args: Array[String]): Unit = {
val inputPath = args(0)
val outputPath = args(1)
val conf = new SparkConf().setAppName("Top Ten")
val sc = new SparkContext(conf)
val data = sc.hadoopFile[LongWritable, Text, TextInputFormat](inputPath)
data.mapPartitions[Long](findTopTen)
.repartition(1)
.distinct()
.sortBy(_.toLong, false)
.mapPartitions(itr => itr.slice(0, 10))
.saveAsTextFile(outputPath)
def findTopTen(itr: Iterator[(LongWritable, Text)]) = {
val set = new util.TreeSet[Long]()
itr.foreach(p => {
val v = p._2.toString.toLong
if (set.size <= 10) {
set.add(v)
} else if (v > set.first) {
set.pollFirst()
set.add(v)
}
})
set.iterator
}
}
}
############################
十二道MR习题 - 4 - TopN问题的更多相关文章
- 十二道MR习题 - 2 - 多文件保存
题目: 需要将MR的执行结果保存到3个文件中,该怎么做. 又是一个送分题. 对于Hadoop的MapReduce来说只需要设置一下reduce任务的数量即可.MR的Job默认reduce数量是1,需要 ...
- 十二道MR习题 - 3 - 交集并集差集
题目 有两个文件A和B,两个文件中都有几百万行数字,现在需要找出A文件和B文件中数字集合的交集.并集.以及A对B的差集. 简单说一下思路: 这个问题关键在于key和value的设计.这里我将文件中的数 ...
- 十二道MR习题 – 1 – 排序
题目: 一个文件,大小约为100G.文件的每一行都是一个数字,要求对文件中的所有数字进行排序. 对于这个题目,了解过Hadoop的同学可以笑而不语了.即使用spark实现也是非常简单的事情. 先说下如 ...
- C primer plus 第五版十二章习题
看完C prime plus(第五版)第十二章,随带完成了后面的习题. 1.不使用全局变量,重写程序清单12.4的程序. 先贴出12.4的程序,方便对照: /* global.c --- 使用外部变量 ...
- hadoop生态系统学习之路(十)MR将结果输出到hbase
之前讲了MR将结果输出到hdfs.hive.db,今天再给大家分享一下,怎样将结果输出到hbase. 首先,提一句,笔者在hadoop集群运行此MR的时候报了一个错误.是一个jar包的缘故,这个错误是 ...
- C和指针 第十六章 习题
16.8 计算平均年龄 #include <stdlib.h> #include <stdio.h> #define MAX_LEN 512 int main() { int ...
- C和指针 第十五章 习题
15.8 十六进制倾印码 #include <stdio.h> #include <stdlib.h> #include <string.h> #include & ...
- C和指针 第十四章 习题
14.1 打印函数 #include <stdio.h> void print_ledger_long(){ printf("function print_ledger_long ...
- 视觉slam十四讲习题ch3-6
题目回顾: 一般解线性方程Ax=b有哪几种做法?你能在Eigen中实现吗? 解: 线性方程组Ax = b的解法 : 1.直接法:(1,2,3,4,5) 2.迭代法:如Jacobi迭代法(6) 其中只有 ...
随机推荐
- 开源平台ghost博客系统
http://docs.ghost.org/installation/windows/ 不会安装的童鞋可以到这里论坛看看 此教程只说windows下的安装: mac的安装教程请移步这里 mac版安装 ...
- 动态代理:JDK原生动态代理(Java Proxy)和CGLIB动态代理原理+附静态态代理
本文只是对原文的梳理总结,以及自行理解.自己总结的比较简单,而且不深入,不如直接看原文.不过自己梳理一遍更有助于理解. 详细可参考原文:http://www.cnblogs.com/Carpenter ...
- 码云平台, 生成并部署SSH key
参考链接: http://git.mydoc.io/?t=154712 步骤如下: 1. 生成 sshkey: ssh-keygen -t rsa -C "xxxxx@xxxxx.com&q ...
- IO 流之字节流和转换流
基本读取操作: InputStream(); OutputStream(); // 直接写入目的地中, 不需要 flush() 刷新 write(byte[] b); // 参数为 byte 数组 字 ...
- Python列表切片详解([][:][::])
Python切片是list的一项基本的功能,最近看到了一个程序,里面有这样一句类似的代码: a = list[::10] 1 不太明白两个冒号的意思就上网百度,发现大多数人写的博客中都没有提到这一个用 ...
- 微信小程序组件form
表单组件form:官方文档 Demo Code: Page({ formSubmit: function(e) { console.log('form发生了submit事件,携带数据为:', e.de ...
- Java Web架构总结
转载至:http://www.cnblogs.com/wuxl360/p/7489763.html 初始搭建 开始的开始,就是各种框架一搭,然后扔到Tomcat容器中跑就是了,这时候我们的文件,数据库 ...
- URAL 2078 Bowling game
题目: Bowling game In all asocial teams members ignore each other uniformly, each tight-knit team buil ...
- 解决Can't connect to local MySQL server through socket '/tmp/mysql.sock'
0 Problem 电脑重启后用python的MySQLdb连接数据库报错 Can't connect to local MySQL server through socket '/tmp/mysql ...
- 新建Maven项目时出错:org.apache.maven.archiver.MavenArchiver.getManifest
新建Maven项目时出错:org.apache.maven.archiver.MavenArchiver.getManifest eclipse新建maven项目时,pom.xml文件第一行报错: o ...