Spark支持两个类型(算子)操作:Transformation
和Action
主要做的是就是将一个已有的RDD生成另外一个RDD。Transformation具有lazy特性(延迟加载)。Transformation算子的代码不会真正被执行。只有当我们的程序里面遇到一个action算子的时候,代码才会真正的被执行。这种设计让Spark更加有效率地运行。
转换 | 含义 |
---|---|
map(func) | 返回一个新的RDD,该RDD由每一个输入元素经过func函数转换后组成 |
filter(func) | 返回一个新的RDD,该RDD由经过func函数计算后返回值为true的输入元素组成 |
flatMap(func) | 类似于map,但是每一个输入元素可以被映射为0或多个输出元素(所以func应该返回一个序列,而不是单一元素) |
mapPartitions(func) | 类似于map,但独立地在RDD的每一个分片上运行,因此在类型为T的RDD上运行时,func的函数类型必须是Iterator[T] => Iterator[U] |
mapPartitionsWithIndex(func) | 类似于mapPartitions,但func带有一个整数参数表示分片的索引值,因此在类型为T的RDD上运行时,func的函数类型必须是(Int, Interator[T]) => Iterator[U] |
sample(withReplacement, fraction, seed) | 根据fraction指定的比例对数据进行采样,可以选择是否使用随机数进行替换,seed用于指定随机数生成器种子 |
union(otherDataset) | 对源RDD和参数RDD求并集后返回一个新的RDD |
intersection(otherDataset) | 对源RDD和参数RDD求交集后返回一个新的RDD |
distinct([numTasks])) | 对源RDD进行去重后返回一个新的RDD |
groupByKey([numTasks]) | 在一个(K,V)的RDD上调用,返回一个(K, Iterator[V])的RDD |
reduceByKey(func, [numTasks]) | 在一个(K,V)的RDD上调用,返回一个(K,V)的RDD,使用指定的reduce函数,将相同key的值聚合到一起,与groupByKey类似,reduce任务的个数可以通过第二个可选的参数来设置 |
aggregateByKey(zeroValue)(seqOp, combOp, [numTasks]) | 先按分区聚合 再总的聚合 每次要跟初始值交流 例如:aggregateByKey(0)(+,+) 对k/y的RDD进行操作 |
sortByKey([ascending], [numTasks]) | 在一个(K,V)的RDD上调用,K必须实现Ordered接口,返回一个按照key进行排序的(K,V)的RDD |
sortBy(func,[ascending], [numTasks]) | 与sortByKey类似,但是更灵活 第一个参数是根据什么排序 第二个是怎么排序 false倒序 第三个排序后分区数 默认与原RDD一样 |
join(otherDataset, [numTasks]) | 在类型为(K,V)和(K,W)的RDD上调用,返回一个相同key对应的所有元素对在一起的(K,(V,W))的RDD 相当于内连接(求交集) |
cogroup(otherDataset, [numTasks]) | 在类型为(K,V)和(K,W)的RDD上调用,返回一个(K,(Iterable,Iterable))类型的RDD |
cartesian(otherDataset) | 两个RDD的笛卡尔积 的成很多个K/V |
pipe(command, [envVars]) | 调用外部程序 |
coalesce(numPartitions**)** | 重新分区 第一个参数是要分多少区,第二个参数是否shuffle 默认false 少分区变多分区 true 多分区变少分区 false |
repartition(numPartitions) | 重新分区 必须shuffle 参数是要分多少区 少变多 |
repartitionAndSortWithinPartitions(partitioner) | 重新分区+排序 比先分区再排序效率高 对K/V的RDD进行操作 |
foldByKey(zeroValue)(seqOp) (无) | 该函数用于K/V做折叠,合并处理 ,与aggregate类似 第一个括号的参数应用于每个V值 第二括号函数是聚合例如:+ |
combineByKey | 合并相同的key的值 rdd1.combineByKey(x => x, (a: Int, b: Int) => a + b, (m: Int, n: Int) => m + n) |
partitionBy(partitioner) | 对RDD进行分区 partitioner是分区器 例如new HashPartition(2 |
cache | RDD缓存,可以避免重复计算从而减少时间,区别:cache内部调用了persist算子,cache默认就一个缓存级别MEMORY-ONLY ,而persist则可以选择缓存级别 |
persist | |
Subtract | 返回前rdd元素不在后rdd的rdd |
leftOuterJoin (无) | leftOuterJoin类似于SQL中的左外关联left outer join,返回结果以前面的RDD为主,关联不上的记录为空。只能用于两个RDD之间的关联,如果要多个RDD关联,多关联几次即可。 |
rightOuterJoin (无) | rightOuterJoin类似于SQL中的有外关联right outer join,返回结果以参数中的RDD为主,关联不上的记录为空。只能用于两个RDD之间的关联,如果要多个RDD关联,多关联几次即可 |
subtractByKey (无) | substractByKey和基本转换操作中的subtract类似只不过这里是针对K的,返回在主RDD中出现,并且不在otherRDD中出现的元素 |
package com.baizhi
import org.apache.spark.storage.StorageLevel
import org.apache.spark.{Partitioner, SparkConf, SparkContext}
import scala.collection.mutable
object TransformationsDemo2 {
def main(args: Array[String]): Unit = {
val conf = new SparkConf().setMaster("local[*]").setAppName("transformations demo")
val sc = new SparkContext(conf)
// ======================flatMap===============================================
// val rdd = sc.parallelize(List("Hello World","Hello Spark"),2)
// 类似于map,但是每一个输入元素可以被映射为0或多个输出元素
// rdd.flatMap(_.split(" ")).foreach(println)
// ======================mapPartitions===============================================
// val rdd = sc.parallelize(1 to 10,2)
// rdd.mapPartitions(mpFunction).collect
// def mpFunction(iter: Iterator[Int]): Iterator[Int] = {
// val list = List[Int]()
// println(iter.mkString(","))
// list.iterator
// }
// ======================mapPartitionsWithIndex===============================================
// val rdd = sc.parallelize(1 to 10,3)
// rdd.mapPartitionsWithIndex(mpFunction2).collect
// def mpFunction2(index:Int,iter: Iterator[Int]):Iterator[Int] = {
// println("index:"+index)
// println(iter.mkString(","))
// iter
// }
// =======================sample==============================================
// 数据抽样
// val rdd = sc.parallelize(1 to 10,3)
// 元素不可以多次抽样:withReplacement=false,每个元素被抽取到的概率为0.5
// rdd.sample(false,0.5).collect.foreach(println)
// 元素可以多次抽样:withReplacement=true,每个元素被抽取到的期望次数为2
// rdd.sample(true,1.5).collect.foreach(println)
// =======================union==============================================
// val rdd = sc.parallelize(1 to 5,2)
// val rdd2 = sc.parallelize(3 to 8,2)
// 求并集
// rdd.union(rdd2).collect.foreach(println)
// 求交集
// 1 2 3 4 5
// 3 4 5 6 7 8
// result:3 4 5
// rdd.intersection(rdd2).collect.foreach(println)
// =======================distinct==============================================
// 去重
// val rdd = sc.parallelize(List[Int](1,2,2,3,3,4,5),2)
// rdd.distinct(2).collect.foreach(println)
// =======================groupByKey==============================================
// val rdd = sc.parallelize(List("Hello World","Hello Spark"),2)
// rdd.flatMap(_.split(" ")).map((_,1)).groupByKey.collect().foreach(println)
// result: (Hello,CompactBuffer(1, 1))
// (World,CompactBuffer(1))
// =======================reduceByKey==============================================
// val rdd = sc.parallelize(List("Hello World", "Hello Spark"), 2)
// rdd.flatMap(_.split(" ")).map((_, 1)).reduceByKey(_ + _).collect.foreach(println)
// result: (Hello,2)
// (World,1)
// =======================aggregateByKey==============================================
// def seqFunc(a: Int, b: Int): Int = {
// Math.max(a, b)
// }
// def combFunc(a: Int, b: Int): Int = {
// a + b
// }
// val rdd = sc.parallelize(List("Hello World", "Hello Spark"), 2)
// rdd.flatMap(_.split(" ")).map((_, 1)).aggregateByKey(10)(seqFunc,combFunc).collect.foreach(println)
// val rdd = sc.parallelize(List(("user1","www.baidu.com"),("user2","www.taobao.com"),("user1","www.sina.com")),2)
// val set = mutable.Set[String]()
// rdd.aggregateByKey(set)((set,v) => set += v,(e1,e2) => e1 ++= e2).collect.foreach(println)
// result: (user1,Set(www.sina.com, www.baidu.com))
// (user2,Set(www.taobao.com))
// =======================sortByKey==============================================
// val rdd = sc.parallelize(List("Hello World", "Hello Spark"), 2)
// rdd.flatMap(_.split(" ")).map((_, 1)).sortByKey(false).collect.foreach(println)
// =======================sortBy==============================================
// val rdd = sc.parallelize(List("Hello World","Hello Spark"),2)
// rdd.flatMap(_.split(" ")).map((_,1)).sortBy(_._1,false).collect.foreach(println)
// =======================join==============================================
// 类似于内连接
// val rdd1 = sc.parallelize(List(("k1",1),("k2",2)),2)
// val rdd2 = sc.parallelize(List(("k1","v1"),("k2","v2"),("k3","v3")),2)
// rdd1.join(rdd2).collect.foreach(println)
// result: (k1,(1,v1))
// (k2,(2,v2))
// =======================cogroup==============================================
// val rdd1 = sc.parallelize(List(("k1", 1), ("k2", 2)), 2)
// val rdd2 = sc.parallelize(List(("k1", "v1"), ("k2", "v2"), ("k3", "v3")), 2)
// rdd1.cogroup(rdd2).collect.foreach(println)
// result: (k3,(CompactBuffer(),CompactBuffer(v3)))
// (k1,(CompactBuffer(1),CompactBuffer(v1)))
// (k2,(CompactBuffer(2),CompactBuffer(v2)))
// =======================cartesian==============================================
// 笛卡尔积
// val rdd1 = sc.parallelize(List(("k1", 1), ("k2", 2)), 2)
// val rdd2 = sc.parallelize(List(("k1", "v1"), ("k2", "v2"), ("k3", "v3")), 2)
// rdd1.cartesian(rdd2).collect().foreach(println)
// result: ((k1,1),(k1,v1))
// ((k1,1),(k2,v2))
// ((k1,1),(k3,v3))
// ((k2,2),(k1,v1))
// ((k2,2),(k2,v2))
// ((k2,2),(k3,v3))
// =======================pipe==============================================
// val rdd = sc.parallelize(List("hi", "hello", "how", "are", "you"),2)
// rdd.pipe("/Users/gaozhy/echo.sh").collect.foreach(println)
// =======================coalesce==============================================
// 合并分区
// val rdd = sc.parallelize(1 to 10,2)
// rdd.coalesce(1).collect.foreach(println)
// =======================repartition==============================================
// 重新分区
// val rdd = sc.parallelize(1 to 10,2)
// rdd.mapPartitionsWithIndex((index,iter) => {
// println(index +" ---> "+iter.mkString(","))
// iter
// }).collect
// println("-----------------")
// val newRDD = rdd.repartition(4)
// newRDD.mapPartitionsWithIndex((index,iter) => {
// println(index +" ---> "+iter.mkString(","))
// iter
// }).collect
// =======================repartitionAndSortWithinPartitions==============================================
// val rdd = sc.parallelize(List(("k1","v1"),("k3","v3"),("k2","v2")),2)
// rdd.repartitionAndSortWithinPartitions(new CustomPartitioner).collect.foreach(println)
// result: (k1,v1)
// (k2,v2)
// (k3,v3)
// =======================combineByKey==============================================
// val rdd = sc.parallelize(List(("k2",2),("k1",1),("k3",3),("k2",2)),2)
// rdd.combineByKey(x => x, (a: Int, b: Int) => a + b, (m: Int, n: Int) => m + n).collect().foreach(println)
// =======================partitionBy==============================================
// val rdd = sc.parallelize(List(("k2",2),("k1",1),("k3",3),("k2",2)),2)
// rdd.partitionBy(new CustomPartitioner).collect()
// =======================cache==============================================
// rdd缓存
// val rdd = sc.parallelize(List(("k2",2),("k1",1),("k3",3),("k2",2)),2)
// rdd.cache()
// =======================persist==============================================
// val rdd = sc.parallelize(List(("k2",2),("k1",1),("k3",3),("k2",2)),2)
// rdd.persist(StorageLevel.DISK_ONLY).collect().foreach(println)
// =======================Subtract==============================================
// 返回第一个rdd中在第二个rdd不存在的值
// val rdd1 = sc.parallelize(1 to 5,2)
// val rdd2 = sc.parallelize(3 to 8,2)
// rdd1.subtract(rdd2).collect().foreach(println)
// foldByKey(无)
// leftOuterJoin(无)
// rightOuterJoin(无)
// rightOuterJoin(无)
}
class CustomPartitioner extends Partitioner{
override def numPartitions: Int = 1
override def getPartition(key: Any): Int = (key.hashCode() & Integer.MAX_VALUE) % numPartitions
}
}