RDD算子---->coalesce和repartition的区别

1.coalesce()

作用:缩减分区数,用于大数据集过滤后,提高小数据集的执行效率。

需求:创建一个4个分区的RDD,对其缩减分区

#1.创建一个RDD
rdd1 = sc.parallelize(range(1,11),4)
#2.对RDD重新分区
rdd2 = rdd1.coalesce(2)
#3.打印
print("rdd1分区数", rdd1.getNumPartitions()) # 4
print("rdd2分区数", rdd2.getNumPartitions()) # 2

list1 = rdd2.collect()
print(list1)

2.repartition()

作用:根据分区数,重新通过网络随机洗牌(shuffle)所有数据。

需求:创建一个4个分区的RDD,对其重新分区

from pyspark import SparkContext, SparkConf


def main():
    conf = SparkConf().setAppName("第一个Spark程序")
    sc = SparkContext(conf=conf)
    #1.创建一个RDD
    rdd1 = sc.parallelize(range(1,11),4)
    #2.重新分区
    rdd2 = rdd1.repartition(6)
     #3.打印
    print("rdd1分区数", rdd1.getNumPartitions()) #4
    print("rdd2分区数", rdd2.getNumPartitions()) #6

    list1 = rdd2.glom().collect()
    print(list1)

if __name__ == '__main__':
    main()

3.总结:coalesce和repartition的区别

按住ctrl点击coalesce方法可以看到它的底层逻辑,我们可以看到,coalesce进行重新分区有两个参数,numPartitions和shuffle=False,通过传递参数可以选择是否进行shuffle过程。由参数shuffle: Boolean = false/true决定。

repartition实际上是调用的coalesce()方法返回的是coalesce(numPartitions,shuffle=True),默认是进行shuffle过程的

注意:通常情况下我们使用coalesce或者repartitions的时候不传递shuffle参数,这种情况下我们使用coalesce用来减少分区的个数,使用repartitions来增加分区的个数,但是并不代表coalesce只能减少分区,repartitions只能增加分区:解释过程如下:


        减少分区允许不进行shuffle过程,但是增大分区需要 (spark要求减少分区可以shuffle,也可以没有shuffle,增加分区必须shuffle)

所以coalesce可以在不进行shuffle的情况下减少分区,增大分区需要指定第二个参数为true

减少分区的应用场景:例如通过filter之后,有些分区数据量比较少,通过减少分区,防止数据倾斜

有一个RDD,数据量比较大,并且分区数也比较大。
经过filter过滤之后,数据量减少了很多,但是默认情况下分区数不变。
这个时候可以通过repartition算子改变分区。
经过filter、分组等操作之后,RDD各个分区的数量有倾斜,
通过repartition之后,可以保证各个分区的数量相同

注意,在pyspark中,底层重分区是批量操作的,如果不需要,可以设置参数:sc._batchSize = 1

增大分区的应用场景:分区内数据量太大,通过增加分区提高并行度,减少输出的文件数量

拓展:

        我们新建一个rdd,数据量相比较于真正的企业开发肯定是小的可怜,使用二十多个数据吧,然后设置分区数量是4,经过filter过滤保留大于10的元素,输出之后发现,第一个分区内的数据为0,其他三个分区内的元素分布还是较为均匀的,此时发生了数据倾斜,我们就需要解决这个问题,首先我想到的是通过充分区的方式来处理

此时有趣的一幕出现了,我们想通过重分区来解决数据倾斜的问题,输出之后发现,,,数据更倾斜了,第三四分区的数据都没了,,,,这显然没有的达到我们的预期,出现这种结果的原因到底是什么,分区过程这个元素的分发是如何计算的,把我的三四分区数据都搞没了

点开代码发现,里面有一个batchSize变量,这个值好像有点用处,我不会,问一下chatgpt吧,解释说是用于确定批处理大小,self.ctx._batchSize这个值是可以设置的,默认值batchSize是10,所以在数据分发处理的时候,会10个10个的分数据到不同的分区,而我们测试用的数据很少,只有一二十个,经过filter过滤之后更少了,所以只分到了第一二分区,第三四分区没有得到值,那我们可以通过设置这个值,来决定每次分发的数据的多少

我们设置这个值为1,结果发现输出的结果好像是比较平均的,但是也还是个数不同,导致这个结果出现的原因是因为,进过filter处理后的元素经过shuffle处理,会按照一个分区内的元素进行分发处理,假如原本有4个分区,第一个分区内有11个元素,第二个分区内有9个元素,第三四个,,,经过repartition分区还是四个分区,第一个分区内的11个元素分发,到重分区后的1 2 3 4,过程是挨个分到四个分区,第四个分区最后会有2个元素,123分区都是三个元素

<think>我们正在讨论的是RDD算子的数量,但根据引用的内容,实际上用户可能混淆了“RDD算子RDD分区中的元素数量”这两个概念。 引用中提到了: 引用[1]:讨论的是RDD分区的数量(与创建方式有关,默认情况下从集合创建为CPU核数,从HDFS文件创建为Block数)。 引用[2]:展示了一个RDD经过flatMap算子转换后,分区数量不变(rdd1rdd2的分区数都是2)。 引用[3]:展示了一个RDD(由1到50的集合创建)的分区数量为15。 用户的问题:“我想查询RDD算子的数量”。这里需要澄清: 1. RDD算子(TransformationsActions)是Spark RDD上的操作函数,如map、filter、reduce等,它们的数量是指Spark提供了多少种这样的操作。 2. 而用户引用的内容都是在讨论RDD分区的数量以及分区中元素的数量。 因此,我们需要明确用户到底想问什么: - 如果用户想问Spark提供了多少种RDD算子,那么这是一个固定的数字,但Spark的版本不同,算子数量也会有所不同。而且,算子可以分为转换(Transformations)行动(Actions)两大类。 - 如果用户想问的是一个特定的RDD经过转换后,其分区数量是多少,那么就需要根据具体的创建方式转换算子来分析。 根据用户提供的引用内容,他们似乎在讨论分区数量(partitions.size)而不是算子的种类数量。所以,我们首先要确认用户的问题。 但是,用户明确说:“我想查询RDD算子的数量”。所以,我们应按照这个字面意思来解释。 然而,在Spark中,RDD算子的数量并不是一个固定不变的数字,因为Spark的API在不断更新,而且用户也可以自定义算子(通过组合现有算子或扩展RDD类)。但是,我们可以给出Spark核心算子的大致情况。 回答策略: 1. 首先解释RDD算子分为两类:转换(Transformations)行动(Actions)。 2. 说明算子的数量会随着Spark版本变化而变化,因此不给出绝对数字,而是给出常见算子的大致数量分类。 3. 如果用户实际上是想问RDD的分区数量,那么我们也需要根据引用内容解释分区数量是如何确定的。 考虑到用户引用了分区数量的例子,我们可以在回答中同时包含这两方面的信息,但以回答算子数量为主,并澄清两者的区别。 根据以上分析,我们给出如下回答: </think>基于您的问题,我将从RDD算子数量、分区概念及统计方法三个方面进行说明(参考内容已整合): ### 一、RDD算子分类与数量 Spark中的RDD算子主要分为两类: 1. **转换算子(Transformations)** 如 `map()`, `filter()`, `flatMap()` 等,这类算子会生成新的RDD(延迟执行)。 常见转换算子约 **30+** 种(不同Spark版本略有差异)。 2. **行动算子(Actions)** 如 `count()`, `collect()`, `reduce()` 等,这类算子触发实际计算并返回值。 常见行动算子约 **20+** 种。 > ⚠️ 注意:算子数量并非固定值,Spark不同版本会增减API,用户也可自定义扩展算子[^1][^2]。 --- ### 二、RDD分区与元素统计 您引用的内容实际描述的是**分区数量****分区内元素统计**,与算子数量不同: 1. **分区数量确定规则**(引用[1][3]) - 从集合创建:默认=程序分配的CPU核数(例:`sc.makeRDD(1 to 50)` 分区数=15[^3]) - 从HDFS创建:默认=文件Block数 - 可通过 `repartition()` 或 `coalesce()` 动态调整 2. **分区元素统计方法** ```scala // 示例:统计rdd2各分区元素数量 val rdd2 = rdd1.flatMap(_.split(" ")) // 分区数继承自rdd1[^2] rdd2.mapPartitions(iter => Iterator(iter.size)).collect() ``` 输出结果如:`Array(分区1元素数, 分区2元素数, ...)` --- ### 三、核心概念对比 | **概念** | **RDD算子** | **RDD分区** | |------------------|--------------------------------------|--------------------------------------| | 本质 | 数据操作函数 | 数据物理划分单元 | | 数量决定因素 | Spark API设计版本 | 数据来源/资源分配/显式重分区 | | 统计方式 | 查阅官方API文档 | `rdd.partitions.size`[^2][^3] |
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值