关闭

Learning Spark 笔记(六) -- 指定分区信息改善join()等的操作

467人阅读 评论(0) 收藏 举报
分类:

9 . 默认情况下,join()操作会对两个RDD的主键做哈希以分区,通过网络将主键相同的元素发送到同一台机器上,然后根据相同的主键再进行连接。例子如下:

val sc = new SparkContext()
val userData = sc.sequenceFile[UserID,LinkInfo]("hdfs://...").persist
def processNewLogs(logFileName:String){
    val events = sc.sequenceFile[UserID, LinkInfo](logFileName)
    //RDD of (UserID,(UserInfo,LinkInfo)) pairs
    val joined = usersData.join(events)
    val offTopicVisits = joined.filter {
        // Expand the tuple into its components
        case (userId, (userInfo, linkInfo)) => 
            !userInfo.topics.contains(linkInfo.topic)
    }.count()
    println("Number of visits to non-subscribed opics: " + offTopicVisits)
}

这样的弊端是,两个RDD都会进行shuffle,资源和时间的消耗比较严重。如下图所示:
这里写图片描述
如果userData是一个大数据量、events是一个小数据量的话,每一次join()操作就会进行一次shuffle,这样的弊端体现的会更明显。为解决这个问题,我们可以利用partionBy()来指定分区信息。代码修改如下:

...
val userData = sc.sequenceFile[UserID,LinkInfo]("hdfs://...")
//指定分区信息为100个哈希分区
.partionBy(new HashPartiotioner(100))
//持久化操作,没有持久化等于白做指定分区信息的操作
.persist
...

在之后的join()操作,由于userData含有分区信息,且joined会有和userData一样的分区信息,那么userData就不会有shuffle。比如此处的userData和joined都有HashPartitioner信息,那么userData和joined中的元素只要key相同,就一定会在同一台机器上,所以userData中的数据只会是在本地移动。还一个值得注意的地方是,partionBy()操作也是shuffle,所以在指定分区信息后必须要有持久化操作。如果没有持久化操作,每次执行都会有partitionBy()的shuffle操作,那么就等于啥也没做甚至平白无故又增添shuffle。变化如下图所示:
这里写图片描述

还有另一种改进的方法也可以避免大数据量RDD的shuffle,那就是广播小数据量RDD,弃用join()操作,使用map()操作完成相同功能的操作。

def processNewLogs(logFileName:String){
    val events = sc.sequenceFile[UserID, LinkInfo](logFileName)
    val small = sc.brocast(events)
    //RDD of (UserID,(UserInfo,LinkInfo)) pairs
    val joined = userData.map(x=>{
        val ss = small.value
        ss.map(y=>{
            var tmp:(String,(String,String)) = null
            if(x._1 == y)
                tmp = (x._1,(x._2,y._2))
            tmp
        })
    })
    val offTopicVisits = joined.filter {
        // Expand the tuple into its components
        case (userId, (userInfo, linkInfo)) => 
            !userInfo.topics.contains(linkInfo.topic)
    }.count()
    println("Number of visits to non-subscribed opics: " + offTopicVisits)
}
0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:16069次
    • 积分:422
    • 等级:
    • 排名:千里之外
    • 原创:23篇
    • 转载:4篇
    • 译文:3篇
    • 评论:7条
    最新评论