一、RDD是什么
RDD(Resilient Distributed Dataset):弹性分布式数据集。
二、RDD创建
2.1 parallelize
val rdd: RDD[Int] = sc.parallelize(List(1, 2, 3, 4, 5))
rdd.collect().foreach(println)
// 输出:1 2 3 4 5
2.2 makeRDD
val rdd: RDD[Int] = sc.makeRDD(List(1, 2, 3, 4, 5))
rdd.collect().foreach(println)// 输出:1 2 3 4 5
三、RDD转换算子
3.1 Value类型
3.1.1 map
val rdd: RDD[Int] = sc.makeRDD(List(1, 2, 3, 4, 5))
val mapRDD: RDD[Int] = rdd.map(_ * 10)
mapRDD.collect().foreach(println)// 输出:10 20 30 40 50
3.1.2 mapPartitions
val rdd: RDD[Int] = sc.makeRDD(List(1, 2, 3, 4, 5), 2)
val MapPartitionsRDD: RDD[Int] = rdd.mapPartitions(
iter => {
iter.map(_ * 10)
}
)
MapPartitionsRDD.collect().foreach(println)// 输出:10 20 30 40 50
3.1.3 mapPartitionsWithIndex
val rdd = sc.makeRDD(List(1,2,3,4), 2)
val mapRDD = rdd.mapPartitionsWithIndex(
(index, iter) => {
if(index == 1) {
iter
} else {
Nil.iterator
}
}
)
mapRDD.collect().foreach(println)// 输出:3 4
3.1.4 flatMap
val rdd: RDD[String] = sc.makeRDD(List(
"Hello Scala", "Hello Spark"
))
val flatRDD: RDD[String] = rdd.flatMap(
s => {
s.split(" ")
}
)
flatRDD.collect().foreach(println)// 输出:Hello Scala Hello Spark
3.1.5 glom
将同一个分区的数据直接转换为相同类型的内存数组进行处理,分区不变。
val rdd: RDD[Int] = sc.makeRDD(List(1,2,3,4), 2)
val glomRDD: RDD[Array[Int]] = rdd.glom()
val maxRDD: RDD[Int] = glomRDD.map(
array => {
array.max
}
)
println(maxRDD.collect().sum)// 输出:6
3.1.6 groupBy
将数据根据指定的规则进行分组, 分区默认不变,但是数据会被打乱重新组合,我们将这样 的操作称之为 shuffle。极限情况下,数据可能被分在同一个分区中。
val rdd = sc.makeRDD(List("Hello", "Spark", "Scala", "Hadoop"), 2)
val groupRDD = rdd.groupBy(_.charAt(0))
groupRDD.collect().foreach(println)// 输出:(H,CompactBuffer(Hello, Hadoop)) (S,CompactBuffer(Spark, Scala))
3.1.7 filter
将数据根据指定的规则进行筛选过滤,符合规则的数据保留,不符合规则的数据丢弃。 当数据进行筛选过滤后,分区不变,但是分区内的数据可能不均衡,生产环境下,可能会出现数据倾斜。
val rdd = sc.makeRDD(List(1,2,3,4))
val filterRDD: RDD[Int] = rdd.filter(num => num % 2 != 0)
filterRDD.collect().foreach(println)// 输出:1 3
3.1.8 sample
数据采样。有三个可选参数:设置是否放回 (withReplacement)、采样的百分比 (fraction)、随机数生成器的种子 (seed) 。
3.1.9 distinct
将数据集中重复的数据去重。
val rdd1 = sc.makeRDD(List(1,2,3,4,1,2,3,4))
val rdd2: RDD[Int] = rdd1.distinct()
rdd2.collect().foreach(println)// 输出:1 2 3 4
3.1.10 coalesce
根据数据量缩减分区,用于大数据集过滤后,提高小数据集的执行效率。当spark程序中,存在过多的小任务的时候,可以通过coalesce方法,收缩合并分区,减少分区的个数,减小任务调度成本。
val rdd = sc.makeRDD(List(1,2,3,4))
val newRDD: RDD[Int] = rdd.coalesce(2)
3.1.11 repartition
该操作内部其实执行的是coalesce操作,参数shuffle的默认值为true。无论是将分区数多的RDD转换为分区数少的RDD,还是将分区数少的RDD转换为分区数多的RDD,repartition操作都可以完成,因为无论如何都会经shuffle过程。
val rdd = sc.makeRDD(List(1,2,3,4),2)
val newRDD: RDD[Int] = rdd.coalesce(3)
3.1.12 sortBy
排序。
val rdd = sc.makeRDD(List(5,2,3,4,1,6,7), 2)
val newRDD: RDD[Int] = rdd.sortBy(num => num)
newRDD.collect().foreach(println)// 输出:1 2 3 4 5 6 7
3.2 双Value类型
3.2.1 intersection
求交集。
val rdd1 = sc.makeRDD(List(1,2,3,4))
val rdd2 = sc.makeRDD(List(3,4,5,6))
val rdd3: RDD[Int] = rdd1.intersection(rdd2)
println(rdd3.collect().mkString(","))// 输出:3,4
3.2.2 union
求并集。
val rdd1 = sc.makeRDD(List(1,2,3,4))
val rdd2 = sc.makeRDD(List(3,4,5,6))val rdd4: RDD[Int] = rdd1.union(rdd2)
println(rdd4.collect().mkString(","))// 输出:1,2,3,4,3,4,5,6
3.2.3 subtract
求差集。
val rdd1 = sc.makeRDD(List(1,2,3,4))
val rdd2 = sc.makeRDD(List(3,4,5,6))val rdd5: RDD[Int] = rdd1.subtract(rdd2)
println(rdd5.collect().mkString(","))// 输出:1,2
3.2.4 zip
拉链。
val rdd1 = sc.makeRDD(List(1,2,3,4))
val rdd2 = sc.makeRDD(List(3,4,5,6))val rdd6: RDD[(Int, Int)] = rdd1.zip(rdd2)
println(rdd6.collect().mkString(","))// 输出:(1,3),(2,4),(3,5),(4,6)
3.3 Key-Value类型
3.3.1 partitionBy
将数据按照指定 Partitioner 重新进行分区。Spark 默认的分区器是 HashPartitioner。
3.3.2 reduceByKey
可以将数据按照相同的 Key 对 Value 进行聚合。
val rdd = sc.makeRDD(List(
("a", 1), ("a", 2), ("a", 3), ("b", 1), ("b", 2)
))
val reduceRDD: RDD[(String, Int)] = rdd.reduceByKey((x: Int, y: Int) => {
x + y
})
reduceRDD.collect().foreach(println)// 输出:(a,6) (b,3)
3.3.3 groupByKey
将数据源的数据根据 key 对 value 进行分组
val rdd = sc.makeRDD(List(
("a", 1), ("a", 2), ("a", 3), ("b", 1), ("b", 2)
))
val groupRDD: RDD[(String, Iterable[Int])] = rdd.groupByKey()
groupRDD.collect().foreach(println)// 输出:(a,CompactBuffer(1, 2, 3)) (b,CompactBuffer(1, 2))
3.3.4 aggregateByKey
将数据根据不同的规则进行分区内计算和分区间计算
val rdd = sc.makeRDD(List(
("a", 1), ("a", 2), ("a", 3), ("a", 4)
), 2)
rdd.aggregateByKey(0)(
(x, y) => math.max(x ,y),
(x ,y) => x + y
).collect().foreach(println)// 输出:(a,6)
3.3.5 foldByKey
当分区内计算规则和分区间计算规则相同时,aggregateByKey就可以简化为foldByKey。
3.3.6 combineByKey
最通用的对 key-value 型 rdd 进行聚集操作的聚集函数(aggregation function)。类似于 aggregate(),combineByKey()允许用户返回值的类型与输入不一致。
3.3.7 sortByKey
在一个(K,V)的RDD上调用,K必须实现Ordered接口(特质),返回一个按照key进行排序的。
3.3.8 join
在类型为(K,V)和(K,W)的RDD上调用,返回一个相同 key 对应的所有元素连接在一起的 (K,(V,W))的 RDD。笛卡儿积。
val rdd1 = sc.makeRDD(List(
("a", 1), ("b" ,2), ("c", 3)
))
val rdd2 = sc.makeRDD(List(
("a", 4), ("b", 5), ("c", 6)
))
val joinRDD: RDD[(String, (Int, Int))] = rdd1.join(rdd2)joinRDD.collect().foreach(println)
// 输出:(a,(1,4)) (b,(2,5)) (c,(3,6))
3.3.9 leftOuterJoin
类似于SQL语句的左外连接。
val rdd1 = sc.makeRDD(List(
("a", 1), ("b" ,2), ("c", 3)
))
val rdd2 = sc.makeRDD(List(
("a", 4), ("b", 5)
))
val leftJoinRDD: RDD[(String, (Int, Option[Int]))] = rdd1.leftOuterJoin(rdd2)
leftJoinRDD.collect().foreach(println)// 输出:(a,(1,Some(4))) (b,(2,Some(5))) (c,(3,None))
3.3.10 cogroup
在类型为(K,V)和(K,W)的 RDD 上调用,返回一个(K,(Iterable,Iterable))类型的RDD。
val rdd1 = sc.makeRDD(List(
("a", 1), ("b" ,2), ("c", 3)
))
val rdd2 = sc.makeRDD(List(
("a", 4), ("b", 5), ("c", 6), ("c", 8)
))
val cgRDD: RDD[(String, (Iterable[Int], Iterable[Int]))] = rdd1.cogroup(rdd2)
cgRDD.collect().foreach(println)// 输出:(a,(CompactBuffer(1),CompactBuffer(4)))
(b,(CompactBuffer(2),CompactBuffer(5)))
(c,(CompactBuffer(3),CompactBuffer(6, 8)))
四、RDD行动算子
4.1 reduce
聚集 RDD 中的所有元素,先聚合分区内数据,再聚合分区间数据。
val rdd: RDD[Int] = sc.makeRDD(List(1, 2, 3, 4))
println(rdd.reduce(_ + _))// 输出:10
4.2 collect
在驱动程序中,以数组 Array 的形式返回数据集的所有元素。
val rdd: RDD[Int] = sc.makeRDD(List(1, 2, 3, 4))
rdd.collect().foreach(println)// 输出:1 2 3 4
4.3 count
返回 RDD 中元素的个数。
val rdd: RDD[Int] = sc.makeRDD(List(1, 2, 3, 4))
println(rdd.count())// 输出:4
4.4 first
返回 RDD 中的第一个元素。
val rdd: RDD[Int] = sc.makeRDD(List(4, 2, 3, 1))
println(rdd.first())// 输出:4
4.5 take
返回一个由 RDD 的前 n 个元素组成的数组。
val rdd: RDD[Int] = sc.makeRDD(List(4, 2, 3, 1))
rdd.take(2).foreach(println)// 输出:4 2
4.6 takeOrdered
返回该 RDD 排序后的前 n 个元素组成的数组。
val rdd: RDD[Int] = sc.makeRDD(List(4, 2, 3, 1))
rdd.takeOrdered(2).foreach(println)// 输出:1 2
4.7 aggregate
分区的数据通过初始值和分区内的数据进行聚合,然后再和初始值进行分区间的数据聚合。
val rdd: RDD[Int] = sc.makeRDD(List(1, 2, 3, 4),4)
println(rdd.aggregate(10)(_ + _, _ + _))// 输出:60
4.8 fold
折叠操作,aggregate 的简化版操作。
val rdd: RDD[Int] = sc.makeRDD(List(1, 2, 3, 4),4)
println(rdd.fold(0)(_+_))// 输出:10
4.9 countByKey
计算每个键出现的次数。
4.10 saveAsTextFile
保存成Text 文件。
4.11 saveAsObjectFile
序列化成对象保存到文件。
4.12 saveAsSequenceFile
保存成Sequencefile文件。
4.13 foreach
分布式遍历RDD中的每一个元素,调用指定函数。