MapReduce对大数据进行排序的实践

从一个小的例子开始:

webp

Map和reduce之间的shuffle(洗牌)是将key值相同的放在一块,sort(排序)是按照key值进行排序.例如like出现了两次,就会把like放在一起.you也是.然后根据key值进行按照字典的顺序进行排序.下面我想将下面的数据按照时间进行排序,并且ID相同的在一块.具体的数据格式:(数据简化成如下,其实还包含其他的一些数据)

6395        1473840570  
6393        1473840390  
6393        1473840150
6393        1473840450
6395        1473840030  
6395        1473840991  
6394        1473839970  
6394        1473840811  
6394        1473840090
......................

 

第一列是ID号,第二列是Linux时间戳.想输出的结果是:ID号相同的放在一块,对应的Linux时间戳从小到大进行排序.在编写代码之前可以想到,底层的MapReduce已经帮我们做了一些工作:对key值相同进行聚集(shuffle洗牌).这里是看主要是reduce部分,map部分工作已经简化了.
刚开始的时候,我是这么想的:
map(k0,v0)-->list(k1,v1)
key: k1 是ID号, Value: v1 是时间戳
reduce(k1,list(v1)) -->list(k2,v2)
在reduce中对list(v1),也就是时间戳列表,先添加到list中,然后用Collections的sort方法对list进行排序,最后将结果进行输出.程序如下:

public class SortReducer extends Reducer<Text,LongWritable,Text,LongWritable>{
     @Override
     protected void reduce(Text key, Iterable<LongWritable> values,
              Context context) throws IOException, InterruptedException {
         // TODO Auto-generated method stub
         List<LongWritable> queue = new ArrayList<LongWritable>();
         for(LongWritable num: values) {
              queue.add(num);
         }
         Collections.sort(queue);//排序
//将排序结果输出
         for(LongWritable num:queue) {
              context.write(key, num);
         }
     }
}

貌似逻辑没有一点问题,可是结果却是:

 

 

所有的时间都是一样的.这是为什么呢?于是网上百度一番,终于找到原因了:

reduce方法会反复执行多次,但key和value相关的对象只有两个,reduce会反复重用这两个对象。所以如果要保存key或者value的结果,只能将其中的值取出另存或者重新clone一个对象(例如Text store = new Text(value) 或者 String a = value.toString()),而不能直接赋引用。因为引用从始至终都是指向同一个对象,你如果直接保存它们,那最后它们都指向最后一个输入记录。会影响最终计算结果而出错。

解决方案:
String str = num.toString();
LongWritable num1 = new LongWritable(Long.parseLong(str));

修改后的源代码如下:

public class SortReducer extends Reducer<Text,LongWritable,Text,LongWritable>{
     @Override
     protected void reduce(Text key, Iterable<LongWritable> values,
              Context context) throws IOException, InterruptedException {
         // TODO Auto-generated method stub
         List<LongWritable> queue = new ArrayList<LongWritable>();
         
         for(LongWritable num: values) { 
              String str = num.toString();
              LongWritable num1 = new LongWritable(Long.parseLong(str));
              queue.add(num1);
         }
         Collections.sort(queue);
         for(LongWritable num:queue) {
              String str = num.toString();
              LongWritable num1 = new LongWritable(Long.parseLong(str));
              context.write(key, num1);
         }
     }
}

最终结果:

 

感兴趣可以加Java架构师群获取Java工程化、高性能及分布式、高性能、深入浅出。高架构。性能调优、Spring,MyBatis,Netty源码分析和大数据等多个知识点高级进阶干货的直播免费学习权限 都是大牛带飞 让你少走很多的弯路的 群..号是:855801563 对了 小白勿进 最好是有开发经验

注:加群要求

1、具有工作经验的,面对目前流行的技术不知从何下手,需要突破技术瓶颈的可以加。

2、在公司待久了,过得很安逸,但跳槽时面试碰壁。需要在短时间内进修、跳槽拿高薪的可以加。

3、如果没有工作经验,但基础非常扎实,对java工作机制,常用设计思想,常用java开发框架掌握熟练的,可以加。

4、觉得自己很牛B,一般需求都能搞定。但是所学的知识点没有系统化,很难在技术领域继续突破的可以加。

5.阿里Java高级大牛直播讲解知识点,分享知识,多年工作经验的梳理和总结,带着大家全面、科学地建立自己的技术体系和技术认知!

转载于:https://my.oschina.net/u/3959491/blog/2988059

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值