十二道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) 其中只有 ...
随机推荐
- URAL 2040 Palindromes and Super Abilities 2(回文树)
Palindromes and Super Abilities 2 Time Limit: 1MS Memory Limit: 102400KB 64bit IO Format: %I64d ...
- bootstrap3.3.6 CDN
<!-- Latest compiled and minified CSS --> <link rel="stylesheet" href="//max ...
- pro_update_role_pwd
DELIMITER | drop procedure if exists pro_update_role_pwd; CREATE PROCEDURE pro_update_role_pwd ( cro ...
- WebService 入门
1. 远程调用技术 2. WebService 概述 WebService 是使用 Http 发送 SOAP 协议数据的一种远程调用技术; WebService 需要开发客户端; WebService ...
- Java 之 Servlet
JavaWeb 三大组件: Servlet, Filter, Listener. Servlet 的作用是处理请求,服务器会把接收到的请求交给 Servlet 来处理.在 Servlet 中通常需要: ...
- Docker Libnetwork Bridge插件实现代码分析----初始化部分
Bridge driver数据结构如下所示: type driver struct { config *configuration network *bridgeNetwork natChain *i ...
- django自带过滤器大全
1.可以通过过滤器来修改变量的显示,过滤器的形式是:{{ variable | filter }},管道符号'|'代表使用过滤器 2.过滤器能够采用链式的方式使用,例如:{{ text | escap ...
- 005-Symbol、Proxy、Reflect
1.Symbol:http://es6.ruanyifeng.com/#docs/symbol 2.Proxy:http://es6.ruanyifeng.com/#docs/proxy Proxy ...
- idea导入项目出现Unable to import maven project: See logs for details提示(转载)
摘要: 从git上面check多工程项目后,maven不能正常下载相应的依赖,最后查询国外网站,找出错误原因.按照此步骤,可以自动配置好每个工程的module. 删除项目根目录下.idea文件夹 关闭 ...
- java 自制Tomcat Andorid IOS 端 证书
java 自制证书 最近做项目用到Https 需要自制各种证书,Tomcat 用的JKS 格式, Andorid 端使用 BKS 格式, IOS 端使用 P12格式正式, 以及各种证书格式之间的转换. ...