共计 3442 个字符,预计需要花费 9 分钟才能阅读完成。
这篇文章主要介绍“如何用 mapreduce 得到 top 最大的前 n 条记录”,在日常操作中,相信很多人在如何用 mapreduce 得到 top 最大的前 n 条记录问题上存在疑惑,丸趣 TV 小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”如何用 mapreduce 得到 top 最大的前 n 条记录”的疑惑有所帮助!接下来,请跟着丸趣 TV 小编一起来学习吧!
在最初接触 mapreduce 时,top n 问题的解决办法是将 mapreduce 输出(排序后)放入一个集合中,取前 n 个,但这种写法过于简单,内存能够加载的集合的大小是有上限的,一旦数据量大,很容易出现内存溢出。
今天在这里介绍另一种实现方式,当然这也不是最好的方式。
需求,得到 top 最大的前 n 条记录
这里只给出一些核心的代码,其他 job 等配置的代码略
Configuration conf = new Configuration();
conf.setInt(N , 5);
初始化 job 之前需要 conf.setInt(N ,5); 意在在 mapreduce 阶段读取 N,N 就代表着 top N
以下是 map
package com.lzz.one;
import java.io.IOException;
import java.util.Arrays;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;
* #orderid,userid,payment,productid
* [root@x00 hd]# cat seventeen_a.txt
* 1,9819,100,121
* 2,8918,2000,111
* 3,2813,1234,22
* 4,9100,10,1101
* 5,3210,490,111
* 6,1298,28,1211
* 7,1010,281,90
* 8,1818,9000,20
* [root@x00 hd]# cat seventeen_b.txt
* 100,3333,10,100
* 101,9321,1000,293
* 102,3881,701,20
* 103,6791,910,30
* 104,8888,11,39
* 预测结果:(求 Top N=5 的结果)* 1 9000
* 2 2000
* 3 1234
* 4 1000
* 5 910
* @author Administrator
*
*/
public class TopNMapper extends Mapper LongWritable, Text, IntWritable, IntWritable {
int len;
int top[];
@Override
public void setup(Context context) throws IOException,InterruptedException { len = context.getConfiguration().getInt(N , 10);
top = new int[len+1];
}
@Override
public void map(LongWritable key, Text value, Context context)throws IOException, InterruptedException { String line = value.toString();
String arr []= line.split( ,
if(arr != null arr.length == 4){ int pay = Integer.parseInt(arr[2]);
add(pay);
}
@Override
public void cleanup(Context context) throws IOException,InterruptedException { for(int i=1;i =len;i++){ context.write(new IntWritable(top[i]),new IntWritable(top[i]));
}
}
}
接下来是 reduce
package com.lzz.one;
import java.io.IOException;
import java.util.Arrays;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.mapreduce.Reducer;
public class TopNReduce extends Reducer IntWritable, IntWritable, IntWritable, IntWritable {
int len;
int top[];
@Override
public void setup(Context context)
throws IOException, InterruptedException {len = context.getConfiguration().getInt(N , 10);
top = new int[len+1];
@Override
public void reduce(IntWritable key, Iterable IntWritable values,
Context context)
throws IOException, InterruptedException {for(IntWritable val : values){add(val.get());
public void add(int pay){top[0] = pay;
Arrays.sort(top);
@Override
public void cleanup(Context context)
throws IOException, InterruptedException {for(int i=len;i i--){context.write(new IntWritable(len-i+1),new IntWritable(top[i]));
}
说一下逻辑,虽然画图比较清晰,但是时间有限,画图水平有限,只用语言来描述吧,希望能说的明白
如果要取 top 5,则应该定义一个长度为为 6 的数组,map 所要做的事情就是将每条日志的那个需要排序的字段放入数组第一个元素中,调用 Arrays.sort(Array[]) 方法可以将数组按照正序,从数字角度说是从小到大排序,比如第一条记录是 9000,那么排序结果是[0,0,0,0,0,9000],第二条日志记录是 8000,排序结果是[0,0,0,0,8000,9000],第三条日志记录是 8500,排序结果是[0,0,0,8000,8500,9000],以此类推,每次放进去一个数字如果大于数组里面最小的元素,相当于将最小的覆盖掉了,也就是说数组中元素永远是拿到日志中最大的那些个记录
ok,map 将数组原封不动按照顺序输出,reduce 接收到从每个 map 拿到的五个排好序的元素,在进行跟 map 一样的排序,排序后数组里面就是按照从小到大排好序的元素,将这些元素倒序输出就是最终我们要的结果了
与之前的方式做个比较,之前的 map 做的事情很少,在 reduce 中排序后哪前 5 条,reduce 的压力是很大的,要把所有的数据都处理一遍,而一般设置 reduce 的个数较少,一旦数据较多,reduce 就会承受不了,悲剧了。而现在的方式巧妙的将 reduce 的压力转移到了 map,而 map 是集群效应的,很多台服务器来做这件事情,减少了一台机器上的负担,每个 map 其实只是输出了 5 个元素而已,如果有 5 个 map,其实 reduce 才对 5 * 5 个数据进行了操作,也就不会出现内存溢出等问题了
到此,关于“如何用 mapreduce 得到 top 最大的前 n 条记录”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注丸趣 TV 网站,丸趣 TV 小编会继续努力为大家带来更多实用的文章!