Spark自学之路(七)——数据分区

数据分区

       对数据集在节点间的分区控制。在分布式程序中,网络的通信代价是很大的,因此控制数据分布以获得最少的网络传输可以极大地提升整体性能,Spark可以控制RDD分区来减少网络通信开销。分区并不是对所有的应用都有好处,如果RDD只被扫描一次,没有分区的必要。只有数据集多次在注入连接这种基于键的操作中使用时,分区才会有帮助。

       Spark中所有的键值对RDD都可以进行分区。系统会根据一个针对键的函数对元素进行分组。尽管Spark没有给出显示控制每个键具体落在哪一个工作节点上的方法,但Spark可以确保同一组的键出现在同一个节点上。

例如:我们分析这样一个应用,他在内存中保存着一张很大的用户表——也就是由一个(UserID,UserInfo)对组成的RDD,其中UserInfo包含一个该用户所订阅的主题的列表。该应用会周期性地将这张表与一个小文件组合,这个小文件存着过去五分钟内发生的事件——(UserID,LinkInfo),过去五分钟内个网站用户访问的情况。我们可能需要对用户访问其未订阅主题的页面的情况进行统计。我们可以使用Spark的join操作来实现这个组合操作。

默认情况下,join操作会将两个数据集中的所有键的哈希值都找出来,将该哈希值相同的记录通过网络传到同一台机器上,然后在那台机器上对所有的键相同的记录进行连接操作。

Spark自学之路(七)——数据分区_第1张图片

每次执行join时都对userData表进行哈希值计算和跨节点数据混洗,虽然这些数据从来不会发生变化。为了解决这一问题,可以对userData表使用partitionBy() (不会改变原来的RDD)转换操作,将这张表转化为哈希分区。可以通过向partitionBy()传递一个spark.HashPartitioner对象来实现该操作。 

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

Spark自学之路(七)——数据分区_第2张图片

如果没有将partitionBy()转换操作的结果持久化,那么后面每次用到这个RDD时都会重复地对数据进行分区操作。不进行持久化操作会导致整个RDD谱系图重新求值,导致重复对数据进行分区以及跨节点的混洗。 

你可能感兴趣的:(Spark)