join操作避免数据混洗的partitionBy()方法

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wy250229163/article/details/52388305

我们经常需要把两张表进行join操作。
在join时,我们对数据集是如何分区的一无所知。
默认情况下,会把两个数据集中所有键的哈希值都求出来,将该哈希值相同的记录通过网络传到同一台机器上,然后在那台机器上对所有键相同的记录进行连接。
当出现特殊情况时,比如两张表里某张表非常大,并且这张表里的数据又没有变化过。那么每一次join都会去求所有哈希值,浪费了不少时间,每一次求出的哈希值都是一样的。如下图。
这里写图片描述

partitionBy()方法就是避免这种情况的。
可以在程序起始时就对userData表使用partitionBy()转化操作,将这张表转为哈希分区。
可以通过向partitionBy传递一个spark.HashPartitioner对象来实现该操作。

userData = sc.sequenceFile[UserID,UserInfo]("hdfs://...")
             .partitionBy(new HashPartitioner(100)) //构造100个分区
             .persist()

将userData分区后,spark会自动利用这一点。
当调用userData.join(events)时,spark就只会对events数据进行混洗操作,将events中特定的userID的记录发送到userData的对应分区所在的那台机器上,这样可以大大减少网络传输以及计算量。
这里写图片描述

要注意的是,partitionBy()是一个转化操作。因此它的返回值总是一个新的RDD,但它不会改变原来的RDD。所以一定要对partitionBy的结果进行持久化。不然每一次jion它都会重新分区,得不偿失。

阅读更多
换一批

没有更多推荐了,返回首页