?優化spark代碼的有一條是避免使用會產生shuffle 的算法,比如 join。對于習慣了寫sql的人來說,使用spark sql 來分析數據,和常規的關系型數據庫寫sql的感覺差不多。spark.sql("select? * from tab1 , tab2 where x=y and z<100")? ,分析就寫完了,多方便。當然有時候對于這樣的寫法,性能不一定是最好的,我在學習一個項目的時候,在最后的優化階段,看著網上的各種優化方法,結合自己的項目看看該如何調到最優。
發現這個job用的時間蠻多的,里面對應的shuffle 還不少對應代碼的里的?
sparkSession.sql("select b.* from global_temp.topTenClick a , user_visit_action b where a.session_id=b.session_id")
有join 產生,這是一個一千行的小表和一個五千萬左右的大表join,網上搜了一些資料看看怎么優化,發現一處寫的不錯
這個例子里面用的是map操作來避免join,我實際使用中發現map寫完執行后報Encoders 相關的錯誤,我使用了filter進行替換。
val topTenClickBroadCastArray= topTenClickBroadCast.value.map(row=> row.getString(0)).collect()
val topTenClickSession = sparkSession.table("user_visit_action").filter( row => topTenClickBroadCastArray.contains(row.getString(2)))
這樣join是避免了,但我運行之后發現job執行時間更長了,一時郁悶
shuffle沒有之后,為什么執行時間邊長了??
我想了半天,一開始以為是序列化問題,單獨修改了序列 化的參數?.config("spark.serializer", "org.apache.spark.serializer.KryoSerializer")來使用spark專用序列化,事實表明沒用。
后來發現job執行時間基本都在compuing time上,跟序列化肯定沒關系,都花在計算上面了。
后來我把注意力放在了代還join僅有的一行代碼上,?topTenClickBroadCastArray.contains(***),我用的是collect方法直接得到的?topTenClickBroadCastArray這個,它屬于Array,array是一個帶下標的集合,我搜索了一下Array的contain方法是否可以優化,
發現了這個文章,寫的不錯,是我想要的
val topTenClickBroadCastArray= topTenClickBroadCast.value.map(row=> row.getString(0)).collect().toSet
用toSet 把Array轉換成Set后,性能上去了很多。
從2.3分鐘(138秒)到34秒,性能提升4倍多,還是很可觀的。