七、分区
7.1 基本概念
如果使用可控的分区方式,将经常被一起访问的数据放在同一个节点上,那么可以大大减少应用的通信开销。
- 通过正确的分区,可以带来明显的性能提升
- 为分布式数据集选择正确的分区,类似于为传统的数据集选择合适的数据结构
分区并不是对所有应用都是有好处的:如果给定的
RDD
只需要被扫描一次,则我们完全没有必要对其预先进行分区处理。- 只有当数据集多次在诸如连接这种基于键的操作中使用时,分区才会有帮助。
Spark
中所有的键值对RDD
都可以进行分区。系统会根据一个针对键的函数对元素进行分组。spark
可以确保同一个组的键出现在同一个节点上
许多
spark
操作会自动为结果RDD
设定分区sortByKey()
会自动生成范围分区的RDD
groupByKey()
会自动生成哈希分区的RDD
其它还有
join()、leftOuterJoin()、rightOuterJoin()、cogroup()、groupWith()、groupByKey()、reduceByKey()、combineByKey()、partitionBy()
,以及mapValues()
(如果输入RDD
有分区方式)、flatMapValues()
(如果输入RDD
有分区方式)对于
map()
操作,由于理论上它可能改变元素的键,因此其结果不会有固定的分区方式。对于二元操作,输出数据的分区方式取决于输入
RDD
的分区方式- 默认情况下,结果采用哈希分区
- 若其中一个输入
RDD
已经设置过分区方式,则结果就使用该分区方式 - 如果两个输入
RDD
都设置过分区方式,则使用第一个输入的分区方式
许多
spark
操作会利用已有的分区信息,如join()、leftOuterJoin()、rightOuterJoin()、cogroup()、groupWith()、groupByKey()、reduceByKey()、combineByKey()、lookup()
。 这些操作都能从分区中获得收益。- 任何需要将数据根据键跨节点进行混洗的操作,都能够从分区中获得好处
7.2 查看分区
.getNumPartitions
属性可以查看RDD
的分区数
7.3 指定分区
在执行聚合或者分组操作时,可以要求
Spark
使用指定的分区数(即numPartitions
参数)- 如果未指定该参数,则
spark
根据集群的大小会自动推断出一个有意义的默认值
- 如果未指定该参数,则
如果我们希望在除了聚合/分组操作之外,也能改变
RDD
的分区。那么Spark
提供了.repartition()
方法- 它会把数据通过忘了进行混洗,并创建出新的分区集合
- 该方法是代价比较大的操作,你可以通过
.coalesce()
方法将RDD
的分区数减少。它是一个代价相对较小的操作。
.repartition(numPartitions)
:返回一个拥有指定分区数量的新的RDD
- 新的分区数量可能比旧分区数增大,也可能减小。
.coalesce(numPartitions,shuffle=False)
:返回一个拥有指定分区数量的新的RDD
- 新的分区数量必须比旧分区数减小
.partitionBy(numPartitions, partitionFunc=<function portable_hash at 0x7f51f1ac0668>)
:返回一个使用指定分区器和分区数量的新的RDD
- 新的分区数量可能比旧分区数增大,也可能减小。
- 这里
partitionFunc
是分区函数。注意:如果你想让多个RDD
使用同一个分区方式,则应该使用同一个分区函数对象(如全局函数),而不要给每个RDD
创建一个新的函数对象。
对于重新调整分区的操作结果,建议对其持久化。
- 如果未持久化,那么每次用到这个
RDD
时,都会重复地对数据进行分区操作,性能太差
- 如果未持久化,那么每次用到这个