Spark数据分区

版权声明:https://github.com/wusuopubupt https://blog.csdn.net/wusuopuBUPT/article/details/53236953

Spark程序可以通过分区来减少网络通信开销。分区并非对于所有场景都是有好处的:比如, 如果给定RDD只被扫描一遍,那么完全没有必要做分区, 只有当数据多次在诸如连接这种基于键的操作时,分区才会有帮助。 假设我们有一份不变的大文件userData, 以及每5分钟产生的小数据events, 现要求在每5分钟产出events数据后, userData对events做一次join操作。 该过程的代码示例如下:

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)
}

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

 1. 未对userData使用partitionBy()时的数据流动示意图:


这样的弊端是,每次调用时,都要对userData进行哈希值计算和跨节点数据混洗(shuffle),资源和时间的消耗比较严重 -- 虽然这份数据从来都不会变化。


解决的办法是, 对userData进行分区和持久化:

val userData = sc.sequenceFile[UserID,LinkInfo]("hdfs://...")
.partionBy(new HashPartiotioner(100))
.persist

扫描二维码关注公众号,回复: 3109911 查看本文章

2.使用partitionBy()时的数据流动示意图:



由于在构造userData时指定了分区和持久化, Spark在调用userData.join(events)时, 便不会再重新对userData进行数据shuffle, 而只对events做shuffle, 将events中特定key对应的记录发送到userData的对应分区所在的机器上(如上图所示), 这样便大大减少了需要做网络通信的数据, 加快了程序运行时间。


注意:

partitionBy()必须和persist()同时出现, 否则分区的数据再下次调用时, 还会被重新计算哈希和shuffle!


猜你喜欢

转载自blog.csdn.net/wusuopuBUPT/article/details/53236953