行动操作:
惰性求值:【RDD的特性】
-------------------------------------------------------------------------------------------------------------------
在RDD行动操作之前,不触发计算。转换操作和创建操作、控制操作均为惰性的;
只有行动操作可触发Job。
-------------------------------------------------------------------------------------------------------------
定义:触发Job,调用runJob()方法:
比如:collect、count
1.first():T 表示返回RDD中的第一个元素,不排序
2.count(): Long表示返回RDD中的元素个数
3.reduce(f:(T,T)=>T):T根据映射函数f,对RDD中的元素进地二元计算
4.collect():Array[T]表示将RDD转换成数组
5.take(num:Int)Array[T]表示获取RDD中从0到num-1下标的元素,不排序
scala> var rdd1 = sc.makeRDD(Seq(10,4,3,12,3))
rdd1: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[4] at makeRDD at
<console>:24
scala> rdd1.take(1)
res7: Array[Int] = Array(10)
6.top(num:Int)Array[T]表示从RDD中,按照默认(降序)或者指定的排序规则,返回前num个元素
scala> rdd1.top(3)
res8: Array[Int] = Array(12, 10, 4)
7.takeOrdered(num:Int):Array[T]和top类似,只不过以和top相反的顺序返回元素
scala> rdd1.takeOrdered(3)
res9: Array[Int] = Array(3, 3, 4)
8.sortBy[K](f:(T))=>K 定义RDD为键值类型
scala> var rdd1 = sc.makeRDD(Array(("A",2),("A",1),("B",6),("B",3),("B",7)))
rdd1: org.apache.spark.rdd.RDD[(String, Int)] = ParallelCollectionRDD[7] at makeRDD at <console>:24
按照键值升序
scala> rdd1.sortBy(x=>x).collect
res10: Array[(String, Int)] = Array((A,1), (A,2), (B,3), (B,6), (B,7))
值降序排列
scala> rdd1.sortBy(x=>x._2,false).collect
res13: Array[(String, Int)] = Array((B,7), (B,6), (B,3), (A,2), (A,1))
9.foreach
说明:将结果返回值给执行器节点,而非驱动器,
Local模式下:
$ > spark-shell
scala> val a = sc.parallelize(List("dog", "tiger", "lion", "cat", "spider", "eagle"), 2)
a: org.apache.spark.rdd.RDD[String] = ParallelCollectionRDD[6] at parallelize at <console>:24
查看打印结果:
scala> a.foreach(println)
dog
tiger
lion
cat
spider
eagle
scala> :q
$> spark-shell --master spark://master:7077
scala> val a = sc.parallelize(List("dog", "tiger", "lion", "cat", "spider", "eagle"), 2)
a: org.apache.spark.rdd.RDD[String] = ParallelCollectionRDD[0] at parallelize at <console>:24
scala> a.foreach(println)
无结果:
查看master:4040
Running Applications-->Executor Summary-->Logs --> stdout log page for app-20190727155306-0007/2 cat spider eagle
总结:
spark-shell【本地模式】 下所有的守护进程在一个JVM中,所以可以使用foreach
打印RDD的元素:
另一个常见的习惯用法是尝试使用rdd.foreach(println)或打印出RDD的元素rdd.map(println)。
在一台机器上,这将生成预期的输出并打印所有RDD的元素。
但是,在cluster模式下,stdout执行程序调用的输出先写入执行stdout程序,
而不是驱动程序上的输出,因此stdout驱动程序不会显示这些!要打印驱动程序上的所有元素,
可以使用该collect()方法首先将RDD带到驱动程序节点:rdd.collect().foreach(println)。
但是,这会导致驱动程序内存不足,因为collect()将整个RDD提取到一台机器上;
如果您只需要打印RDD的一些元素,更安全的方法是使用take():rdd.take(100).foreach(println)
10.aggregate
def aggregate[U: ClassTag](zeroValue: U)(seqOp: (U, T) => U, combOp: (U, U) => U): U
说明:aggregate用于聚合RDD中的元素,先使用seqOp将RDD中每个分区中的T类型元素聚合成U类型,
再使用combOp将之前每个分区聚合后的U类型聚合成U类型
特别注意seqOp和combOp都会使用zeroValue的值,zeroValue的类型为U
val z = sc.parallelize(List(1,2,3,4,5,6), 2)
z.aggregate(0)(math.max(_, _), _ + _)
res40: Int = 9
说明:
step1:首先在第一个分区[0,1,2,3]中执行math.max,结果为:3
step2:在第二个分区[0,4,5,6]中执行math.max,结果为:6
stepn:在第N个分区中执行math.max,结果为:max
step:将所有分区结果执行combOp(_+_),0+3+6=9
修改初值为5:
z.aggregate(5)(math.max(_, _), _ + _)
结果是多少?
说明:
// This example returns 16 since the initial value is 5
// reduce of partition 0 will be max(5, 1, 2, 3) = 5
// reduce of partition 1 will be max(5, 4, 5, 6) = 6
// final reduce across partitions will be 5 + 5 + 6 = 16
// note the final reduce include the initial value
案例说明:
scala> val z = sc.parallelize(List("12","23","345","4567"),2)
z: org.apache.spark.rdd.RDD[String] = ParallelCollectionRDD[3] at parallelize at <console>:24
scala> z.glom.collect
res11: Array[Array[String]] = Array(Array(12, 23), Array(345, 4567))
scala> z.aggregate("")((x,y) => math.max(x.length, y.length).toString, (x,y) => x + y)
res12: String = 42
scala> z.aggregate("")((x,y) => math.max(x.length, y.length).toString, (x,y) => x + y)
res13: String = 24
说明:
step1:第一个分区中执行math.max(x.length, y.length).toString代码
res0=:math.max(“”.length, “12”.length).toString = “2”
res1=:math.max(res0.length, “23”.length).toString = “2”
第一个分区最终返回值为:2
step2:第二个分区中执行math.max(x.length, y.length).toString代码
res2=:math.max(“”.length, “345”.length).toString = “3”
res3=:math.max(res2.length, “4567”.length).toString = “4”
第一个分区最终返回值为:4
step3:最后执行(x,y) => x + y :24 或 42
【原因分区是在不同的executor下运行,查看webUI task执行的秒数】
scala> z.aggregate("")((x,y) => math.min(x.length, y.length).toString, (x,y) => x + y)
res14: String = 11
step1:第一个分区中执行math.min(x.length, y.length).toString代码
res0=:math.min(“”.length, “12”.length).toString = “0”
res1=:math.min(res0.length, “23”.length).toString = “1”
第一个分区最终返回值为:1
step2:第二个分区中执行math.min(x.length, y.length).toString代码
res2=:math.min(“”.length, “345”.length).toString = “0”
res3=:math.min(res2.length, “4567”.length).toString = “1”
第一个分区最终返回值为:1
step3:最后执行(x,y) => x + y :11 或 11
scala> z.aggregate("12")((x,y) => math.min(x.length, y.length).toString, (x,y) => x + y)
res15: String = 1211
step1:第一个分区中执行math.min(x.length, y.length).toString代码
res0=:math.min(“12”.length, “12”.length).toString = “2”
res1=:math.min(res0.length, “23”.length).toString = “1”
第一个分区最终返回值为:1
step2:第二个分区中执行math.min(x.length, y.length).toString代码
res2=:math.min(“12”.length, “345”.length).toString = “2”
res3=:math.min(res2.length, “4567”.length).toString = “1”
第一个分区最终返回值为:1
step3:最后执行(x,y) => x + y :1211 或 1211
11.fold
def fold(zeroValue: T)(op: (T, T) => T): T
说明:fold理解为aggregate的简化
val a = sc.parallelize(List(1,2,3), 3)
a.fold(0)(_ + _)
res59: Int = 6
12.reduceByKeyLocally:
该函数将RDD[K,V]中每个K对应的V值根据映射函数来运算,运算结果映射到一个Map[K,V]中,而不是RDD[K,V]
def reduceByKeyLocally(func: (V, V) => V): Map[K, V]
scala> val a = sc.parallelize(List("dog", "cat", "owl", "gnu", "ant"), 2)
a: org.apache.spark.rdd.RDD[String] = ParallelCollectionRDD[0] at parallelize at <console>:24
scala> val b = a.map(x => (x.length, x))
b: org.apache.spark.rdd.RDD[(Int, String)] = MapPartitionsRDD[1] at map at <console>:26
scala> b.glom.collect
Array[Array[(Int, String)]] = Array(Array((3,dog), (3,cat)), Array((3,owl), (3,gnu), (3,ant)))
scala> b.reduceByKeyLocally(_+_)
res0: scala.collection.Map[Int,String] = Map(3 -> dogcatowlgnuant)