RDD转换算子分类依据:RDD转换算子根据数据处理方式不同分为Value类型、双Value类型和Key - Value类型。这种分类有助于开发者针对不同的数据处理需求,快速选择合适的算子,提高开发效率。
Value类型算子
map算子:函数签名为 def map[U: ClassTag](f: T => U): RDD[U] ,它会对RDD中的每个元素逐一进行函数 f 的转换操作。如示例中,先将 RDD[Int] 中的每个元素乘以2,再将结果转换为 String 类型,实现了数据值和类型的转换。
mapPartitions算子:函数签名 def mapPartitions[U: ClassTag](f: Iterator[T] => Iterator[U], preservesPartitioning: Boolean = false): RDD[U] ,它以分区为单位处理数据,将每个分区的数据以迭代器形式传递给函数 f 。相比 map 算子逐元素处理,它更适合需要对分区内数据整体操作的场景,但由于是批量处理,长时间占用内存可能导致内存溢出。
mapPartitionsWithIndex算子:函数签名 def mapPartitionsWithIndex[U: ClassTag](f: (Int, Iterator[T]) => Iterator[U], preservesPartitioning: Boolean = false): RDD[U] ,与 mapPartitions 类似,不过在处理数据时还能获取当前分区的索引,方便进行与分区索引相关的操作。
flatMap算子:函数签名 def flatMap[U: ClassTag](f: T => TraversableOnce[U]): RDD[U] ,先对数据进行扁平化处理,再进行映射。例如将包含多个集合的 RDD 扁平化后再处理,与 map 的区别在于 flatMap 会把映射后的集合合并成一个大集合。
glom算子:函数签名 def glom(): RDD[Array[T]] ,它将每个分区的数据转换为数组,方便对整个分区数据进行批量操作,分区数量和数据分布不变。
groupBy算子:函数签名 def groupBy[K](f: T => K)(implicit kt: ClassTag[K]): RDD[(K, Iterable[T])] ,按照指定规则对数据分组,会发生shuffle,即数据会打乱重新组合,一个分区中可能包含多个组的数据。
filter算子:函数签名 def filter(f: T => Boolean): RDD[T] ,根据指定规则筛选数据,符合规则的保留,不符合的丢弃。筛选后分区不变,但分区内数据可能不均衡,在生产环境中可能引发数据倾斜问题。
sample算子:函数签名 def sample(withReplacement: Boolean, fraction: Double, seed: Long = Utils.random.nextLong): RDD[T] ,用于从数据集中抽样。分为不放回抽样(伯努利算法)和放回抽样(泊松算法),通过设置参数控制抽样方式、抽样几率和随机数种子。
Value类型算子
distinct算子:有两个函数签名,无参数时按默认分区去重,指定 numPartitions 时按指定分区数去重。它会遍历数据集,利用元素的 equals 和 hashCode 方法判断重复,去除重复数据,常用于数据清洗,保证数据的唯一性。
coalesce算子:用于缩减分区,提高小数据集执行效率。 shuffle 为 false 时,合并相邻分区,适用于数据分布均匀、无需重新洗牌的场景; shuffle 为 true 时类似 repartition ,会重新洗牌。在大数据集过滤后,通过减少分区数量,能降低任务调度开销。
repartition算子:内部调用 coalesce 且 shuffle 默认为 true ,无论增加或减少分区数都执行shuffle操作。增加分区可并行处理更多数据,减少分区能降低资源消耗和调度成本,适用于数据分布不均衡,需要重新分布数据的场景。
sortBy算子:先使用函数 f 处理数据,再按处理结果排序,默认升序,可指定分区数。排序时,RDD元素按指定规则比较和排序, shuffle 过程会将数据重新分区和排序,常用于对数据按特定规则排序的场景。
双Value类型算子
intersection算子:对两个RDD求交集,返回包含共同元素的新RDD。实现时需遍历两个RDD,通过比较元素确定交集,常用于筛选两个数据集中都存在的数据,如在用户行为分析中找出同时参与两个活动的用户。
union算子:求两个RDD的并集,重复数据保留。它将两个RDD的元素简单合并到新RDD ,可用于合并多个数据源的数据,增加数据规模。
subtract算子:以源RDD为主,去除重复元素,保留源RDD独有的元素。通过比较两个RDD元素,筛选出源RDD中独有的部分,常用于找出数据差异,如对比两个版本数据的不同。
zip算子:将两个RDD按相同位置元素组合成键值对,要求两个RDD分区数和元素个数相同。它为后续的关联操作提供数据结构,如将用户ID和对应的行为数据关联起来,方便进行综合分析
分区与分组算子
partitionBy:按照指定的 Partitioner 重新分区数据,Spark默认的分区器是 HashPartitioner 。通过指定不同的分区器和分区数,可以改变数据的分布,提升并行处理效率。
groupByKey:根据键对值进行分组,有多个重载函数,可以指定分区数或分区器。在处理大规模数据时,合理设置分区能优化性能,但要注意数据倾斜问题。
聚合算子
reduceByKey:按相同键对值进行聚合,在shuffle前会对分区内相同键的数据预聚合,减少数据传输量,提高性能。适用于需要对数据进行分组聚合计算的场景。
aggregateByKey:分区内和分区间计算规则可不同,使用初始值与数据进行计算。常用于复杂聚合场景,如求平均值、标准差等,可自定义分区内和分区间的计算逻辑。
foldByKey:是 aggregateByKey 的简化形式,分区内和分区间计算规则相同。在简单聚合场景下使用,代码更简洁。
combineByKey:功能最通用,可让第一个数据转换结构,适用于数据结构需转换或更复杂的聚合场景,如统计每个键的总值及对应键值对个数。
排序与连接算子
sortByKey:对键值对RDD按键排序,要求键实现 Ordered 接口,可指定升序或降序以及分区数。常用于需要对数据按特定键排序的场景。
join:对两个键值对RDD按相同键连接,返回连接后的新RDD 。在数据关联场景中广泛应用,如关联用户信息和订单信息。
leftOuterJoin:类似SQL左外连接,保留左RDD所有键,右RDD无对应键时用 Option 类型表示。用于需要保留一侧数据完整性的关联场景。
cogroup:将两个键值对RDD按相同键分组,返回包含两个可迭代集合的RDD 。适用于需要同时对两个RDD按相同键进行分组操作的场景。