【Spark】算子

本文介绍了Apache Spark中RDD的各种操作,包括转换操作如mapWith、flatMapWith等,以及行动操作如countByKey、filterByRange等。详细解释了这些操作的功能及使用场景,并提供了具体的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. mapWith
mapWith(i => i*10)((a,b) => b+2)
(拿到分区号)(a是每次取到的RDD中的元素,b接收i*10的结果)
2. flatMapWith
类似mapWith,区别在于flatMapWith返回的是一个序列

3. mapPartitions
每次取到的是分区号
val rdd1 = sc.parallelize(Array(1,2,3,4,5,6,7),3)
对分区每个元素乘10
rdd1.mapPartitions(_.map(_ * 10))

4. mapPartitionsWithIndex
对RDD中的每个分区进行操作,带有分区号
val rdd1 = sc.parallelize(List(1,2,3,4,5,6,7,8,9),2)
创建一个函数
(index分区号,iter分区中的每个元素)
def func1(index:Int,iter:Iterator[Int]):Iterator[String] ={
ter.toList.map(x=>"[PartID:" + index +",value="+x+"]").iterator
}
rdd1.mapPartitionsWithIndex(func1).collect
结果:
Array(
[PartID:0,value=1], [PartID:0,value=2], [PartID:0,value=3], [PartID:0,value=4],
[PartID:1,value=5], [PartID:1,value=6], [PartID:1,value=7], [PartID:1,value=8], [PartID:1,value=9])

5. aggregate:聚合操作
先对局部进行操作,再对全局进行操作
val rdd1 = sc.parallelize(List(1,2,3,4,5),2)
(初始值)(局部操作,全局操作)
rdd1.aggregate(0)(math.max(_,_),_+_)

6. aggregateByKey
类似aggregate,也是先对局部,再对全局
区别:aggregateByKey操作<key,value>
val pairRDD = sc.parallelize(List( ("cat",2), ("cat", 5), ("mouse", 4),("cat", 12), ("dog", 12), ("mouse", 2)), 2)
把每个笼子中,每种动物最多的个数进行求和
(初始值)(局部操作,全局操作)
pairRDD.aggregateByKey(0)(math.max(_,_),_+_).collect

7. foldByKey:对相同key进行聚合操作
foldByKey(初始值)(对value的操作)
拼接相同key的value字符串
val rdd1 = sc.parallelize(List("dog", "wolf", "cat", "bear"), 2)
val rdd2 = rdd1.map(x => (x.length, x))
val rdd3 = rdd2.foldByKey("")(_+_)
结果:Array[(Int, String)] = Array((4,wolfbear), (3,dogcat))

8. combineByKey 操作的是key-value
val rdd3 = rdd1.combineByKey(x => x + 10, (a: Int, b: Int) => a + b, (m: Int, n: Int) => m + n)

第一个参数:List(_),(分区的每一个元素:它的类型就是整个函数的返回类型(List[String]))
第二参数 (x: List[String], y: String=> x :+ y,):分区内的局部聚合,x与第一个参数的返回类型一致,y是RDD的每一个value
第三个参数((m: List[String], n: List[String]) => m ++ n): 全局聚合,类型与第一个参数一致
val rdd7 = rdd6.combineByKey(List(_), (x: List[String], y: String) => x :+ y, (m: List[String], n: List[String]) => m ++ n)

9. coalesce、repartition、partitionBy:重新分区
coalesce:默认不会shuffle,可以重新分更小的分区,不能分更大的分区,如果要shuffle,需要传入参数true
val rdd1 = sc.parallelize(1 to 10, 5)
val rdd2 = rdd1.coalesce(10, true)
rdd2.partitions.length
repartition: 会进行shuffle,任意分区都可以,传入参数是Int数字
rdd1.repartition(8)
partitionBy:会进行shuffle,任意分区都可以,传入参数是分区器
rdd1.partitionBy(new org.apache.spark.HashPartitioner(7))

10. countByKey 计算相同key的元组有多少个
countByValue:计算相同value的元组有多少个
val rdd1 = sc.parallelize(List(("a", 1), ("b", 2), ("b", 2), ("c", 2), ("c", 1)))
rdd1.countByKey
rdd1.countByValue

11. filterByRange :根据key的范围进行过滤
val rdd1 = sc.parallelize(List(("e", 5), ("f",2),("c", 3), ("d", 4), ("c", 2), ("a", 1)))
取出c到d范围的元组
val rdd2 = rdd1.filterByRange("c", "d")
rdd2.colllect

12. flatMapValues :对元组的值进行操作并压平
val rdd3 = sc.parallelize(List(("a","1 2"), ("b","3 4")))
rdd3.flatMapValues(_.split(" ")).collect
结果: Array[(String, String)] = Array((a,1), (a,2), (b,3), (b,4))

13. foreachPartition :对每个分区的操作,返回每个分区的结果
val rdd1 = sc.parallelize(List(1, 2, 3, 4, 5, 6, 7, 8, 9), 3)
rdd1.foreachPartition(x => println(x.reduce(_ + _)))
结果
6
15
24

14. keyBy : 将传入的参数作为元组的key,原RDD元素作为value
val rdd1 = sc.parallelize(List("dog", "salmon", "salmon", "rat", "elephant"), 3)
val rdd2 = rdd1.keyBy(_.length)
rdd2.collect
结果:Array[(Int, String)] = Array((3,dog), (6,salmon), (6,salmon), (3,rat), (8,elephant))

15. keys :获取RDD的key
values :获取RDD的value
val rdd1 = sc.parallelize(List("dog", "tiger", "lion", "cat", "panther", "eagle"), 2)
val rdd2 = rdd1.map(x => (x.length, x))
rdd2.keys.collect
rdd2.values.collect

16. collectAsMap :将集合转化成元组
val rdd = sc.parallelize(List(("a", 1), ("b", 2)))
rdd.collectAsMap
结果 :scala.collection.Map[String,Int] = Map(b -> 2, a -> 1)
### Spark算子概述 Spark 是一种分布式计算框架,其核心概念之一是 **RDD(弹性分布式数据集)**。通过一系列的转换操作(Transformation),可以构建复杂的并行计算流程。最终可以通过行动操作(Action)触发实际的任务执行。 以下是常见的 Spark 算子分类及其使用方法: --- #### 转换算子(Transformation) ##### `map` 将输入中的每一个元素应用指定函数,并返回一个新的 RDD。 ```python rdd = sc.parallelize([1, 2, 3]) mapped_rdd = rdd.map(lambda x: x * 2) print(mapped_rdd.collect()) # 输出: [2, 4, 6] ``` ##### `filter` 过滤掉不满足条件的数据项。 ```python filtered_rdd = rdd.filter(lambda x: x % 2 == 0) print(filtered_rdd.collect()) # 输出: [2] ``` ##### `flatMap` 类似于 map,但是会将结果扁平化处理。 ```python words = ["hello world", "this is a test"] flat_mapped_rdd = sc.parallelize(words).flatMap(lambda line: line.split()) print(flat_mapped_rdd.collect()) # 输出: ['hello', 'world', 'this', 'is', 'a', 'test'] ``` ##### `repartition` 重新分配分区数量,可能引发 Shuffle 操作。 ```python rep_rdd = rdd.repartition(4) # 将分区数调整为4 print(rep_rdd.getNumPartitions()) # 输出: 4 ``` 此过程涉及 Shuffle 的实现细节可参见[^3]。 --- #### 行动算子(Action) ##### `reduce` 对 RDD 中的所有元素进行两两聚合运算。 ```python sum_result = rdd.reduce(lambda x, y: x + y) print(sum_result) # 输出: 7 ``` ##### `collect` 将整个 RDD 收集到驱动程序中作为列表返回。 ```python collected_data = rdd.collect() print(collected_data) # 输出: [1, 2, 3] ``` ##### `count` 统计 RDD 中的元素总数。 ```python cnt = rdd.count() print(cnt) # 输出: 3 ``` ##### `take` 获取前 N 个元素。 ```python taken_elements = rdd.take(2) print(taken_elements) # 输出: [1, 2] ``` --- #### Join 类型算子 ##### `join` 和 `leftOuterJoin` 用于两个键值对类型的 RDD 进行连接操作。 ```python rdd1 = sc.parallelize([(1, "Apple"), (2, "Banana")]) rdd2 = sc.parallelize([(2, "Yellow"), (3, "Red")]) joined_rdd = rdd1.join(rdd2) print(joined_rdd.collect()) # 输出 [(2, ('Banana', 'Yellow'))] outer_joined_rdd = rdd1.leftOuterJoin(rdd2) print(outer_joined_rdd.collect()) # 结果示例可见于[^4] ``` --- #### 自定义算子 在 Java 或 Scala 中自定义算子时,通常需要继承特定接口并重写方法。例如,在 Java 中实现 Filter 功能: ```java JavaRDD<String> filteredRdd = rdd.filter(new Function<String, Boolean>() { public Boolean call(String row) throws Exception { return !row.isEmpty(); // 只保留非空字符串 } }); ``` 上述逻辑也可扩展至其他复杂场景下,具体实现方式详见[^2]。 --- ### 总结 以上展示了部分常用的 Spark 算子以及它们的应用实例。每种算子都有独特的用途和性能特点,合理选择能够显著提升作业效率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值