从一个小的例子开始:java
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()),而不能直接赋引用。由于引用从始至终都是指向同一个对象,你若是直接保存它们,那最后它们都指向最后一个输入记录。会影响最终计算结果而出错。ide
解决方案:
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 对了 小白勿进 最好是有开发经验大数据
注:加群要求
一、具备工做经验的,面对目前流行的技术不知从何下手,须要突破技术瓶颈的能够加。
二、在公司待久了,过得很安逸,但跳槽时面试碰壁。须要在短期内进修、跳槽拿高薪的能够加。
三、若是没有工做经验,但基础很是扎实,对java工做机制,经常使用设计思想,经常使用java开发框架掌握熟练的,能够加。
四、以为本身很牛B,通常需求都能搞定。可是所学的知识点没有系统化,很难在技术领域继续突破的能够加。
5.阿里Java高级大牛直播讲解知识点,分享知识,多年工做经验的梳理和总结,带着你们全面、科学地创建本身的技术体系和技术认知!