MapReduce對大資料進行排序的實踐
從一個小的例子開始:
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高階大牛直播講解知識點,分享知識,多年工作經驗的梳理和總結,帶著大家全面、科學地建立自己的技術體系和技術認知!