普通的join,那么肯定是要走shuffle;那么,所以既然是走shuffle,那么普通的join,就肯定是走的是reduce join。
先将所有相同的key,对应的values,汇聚到一个task中,然后再进行join。
reduce join转换为map join,适合在什么样的情况下,可以来使用?
- 如果两个RDD要进行join,其中一个RDD是比较小的。一个RDD是100万数据,一个RDD是1万数据。(一个RDD是1亿数据,一个RDD是100万数据)
- 其中一个RDD必须是比较小的,broadcast出去那个小RDD的数据以后,就会在每个executor的block manager中都驻留一份。要确保你的内存足够存放那个小RDD中的数据
这种方式下,根本不会发生shuffle操作,肯定也不会发生数据倾斜;从根本上杜绝了join操作可能导致的数据倾斜的问题;
对于join中有数据倾斜的情况,大家尽量第一时间先考虑这种方式,效果非常好;前提是某个RDD比较小的情况下。
不适合的情况:
两个RDD都比较大,那么这个时候,你去将其中一个RDD做成broadcast,就很笨拙了。很可能导致内存不足。最终导致内存溢出,程序挂掉。
而且其中某些key(或者是某个key),还发生了数据倾斜;此时可以采用最后两种方式。
对于join这种操作,不光是考虑数据倾斜的问题;即使是没有数据倾斜问题,也完全可以优先考虑,用我们讲的这种高级的reduce join转map join的技术,不要用普通的join,去通过shuffle,进行数据的join;完全可以通过简单的map,使用map join的方式,牺牲一点内存资源;在可行的情况下,优先这么使用。
不走shuffle,直接走map,是不是性能也会高很多?这是肯定的。
/*
userid2partAggrInfoRDD的数据量可能是比较大的 比如1000万条数据
而userid2InfoRDD是一用户表 数据量可能是比较小的
可以将它改成map join
*/
JavaPairRDD<Long,Tuple2<String,Row>> userid2FullInfoRDD=userid2PartAggrInfoRDD.join(userid2InfoRDD);
JavaPairRDD<String,String> sesionid2FullAggrInfoRDD=userid2FullInfoRDD.mapToPair(
new PairFunction<Tuple2<Long, Tuple2<String, Row>>, String, String>() {
@Override
public Tuple2<String, String> call(Tuple2<Long, Tuple2<String, Row>> tuple) throws Exception {
String partAggrInfo=tuple._2._1;
Row userInfoRow=tuple._2._2;
String sessionid=StringUtils.getFieldFromConcatString(partAggrInfo,"\\|",Constants.FIELD_SESSION_ID);
int age=userInfoRow.getInt(3);
String professional=userInfoRow.getString(4);
String city=userInfoRow.getString(5);
String sex=userInfoRow.getString(6);
String fullAggrInfo=partAggrInfo+"|"
+Constants.FIELD_AGE+"="+age+"|"
+Constants.FIELD_PROFESSIONAL+"="+professional+"|"
+Constants.FIELD_CITY+"="+city+"|"
+Constants.FIELD_SEX+"="+sex;
return new Tuple2<String, String>(sessionid,fullAggrInfo);
}
}
);
List<Tuple2<Long,Row>> userInfos=userid2InfoRDD.collect();
final Broadcast<List<Tuple2<Long,Row>>> userInfosBroadcast=sc.broadcast(userInfos);
JavaPairRDD<String,String> tunedRDD=userid2PartAggrInfoRDD.mapToPair(new PairFunction<Tuple2<Long, String>, String, String>() {
@Override
public Tuple2<String, String> call(Tuple2<Long, String> tuple) throws Exception {
List<Tuple2<Long,Row>> userInfos=userInfosBroadcast.value();
Map<Long,Row> userInfoMap=new HashMap<Long, Row>();
for(Tuple2<Long,Row> userInfo:userInfos){
userInfoMap.put(userInfo._1,userInfo._2);
}
String partAggrInfo=tuple._2;
Row userInfoRow=userInfoMap.get(tuple._1);
String sessionid=StringUtils.getFieldFromConcatString(partAggrInfo,"\\|",Constants.FIELD_SESSION_ID);
int age=userInfoRow.getInt(3);
String professional=userInfoRow.getString(4);
String city=userInfoRow.getString(5);
String sex=userInfoRow.getString(6);
String fullAggrInfo=partAggrInfo+"|"
+Constants.FIELD_AGE+"="+age+"|"
+Constants.FIELD_PROFESSIONAL+"="+professional+"|"
+Constants.FIELD_CITY+"="+city+"|"
+Constants.FIELD_SEX+"="+sex;
return new Tuple2<String, String>(sessionid,fullAggrInfo);
}
});