Action行动算子 及相应的举例

7.Action行动算子
转换算子 起始就是记录了数据的一个操作流程 RDD1->RDD2->RDD3->RDD4 , 流式运算现象
RDD1 到 RDD4 之间维护血缘关系(操作行为)
RDD的转换算子是lazy加载 , 不执行行动算子 , RDD根本没有计算数据
只有执行行动算子才会触发RDD去读取数据 (分区:task) 分布式进行运算 JOB

RDD 是spark抽象出来的运算逻辑,RDD中是不存储数据的,只记录数据的操作和RDD之间的血缘关系,只有执行到行动算子的时候才会处理真正的数据

7.1 takeSample
takeSample()函数和上面的sample函数是一个原理,但是不使用相对比例采样,而是按设定的采样个数进行采样,同时返回结果不再是RDD,而是相当于对采样后的数据进行Collect(),返回结果的集合为单机的数组。
object TakeSampleFunction {
def main(args: Array[String]): Unit = {
val sc: SparkContext = SparkUtils.getSparkContext
val rdd1: RDD[Int] = sc.parallelize(1 to 10, 3)
// 行动算子 返回值 不是算子
/**
* 参数一 参数二 获取样本数据的个数
*/
val arr: Array[Int] = rdd1.takeSample(false, 3, 1)
for (elem <- arr) {
println(elem)
}
sc.stop()
}
}
7.2 collect
collect,将数据以数组形式收集回Driver端,数据按照分区编号有序返回
collect是Action里边的,根据RDD的惰性机制,真正的计算发生在RDD的Action操作。由于collect是从各节点将数据拉到driver端,需要重新分区,所以,一次collect就会导致一次Shuffle,而一次Shuffle调度一次stage,然而一次stage包含很多个已分解的任务碎片Task。这么一来,会导致程序运行时间大大增加,属于比较耗时的操作,即使是在local模式下也同样耗时,一般把数据写道Hbase中或者Mysql中都是从executor中往里面写
def main(args: Array[String]): Unit = {
val sc: SparkContext = SparkUtil.getSparkContext()
val arr = Array(1, 2, 3, 4, 5, 6, 7, 8, 9)
val rdd: RDD[Int] = sc.parallelize(arr, 3)
// 返回本地一个数组
val res: Array[Int] = rdd.collect()
sc.stop()
}

7.3 reduce
将数据以输入的函数进行聚合返回一个值
reduce将RDD中元素两两传递给输入函数,同时产生一个新值,新值与RDD中下一个元素再被传递给输入函数,直到最后只有一个值为止。
def main(args: Array[String]): Unit = {
val sc: SparkContext = SparkUtil.getSparkContext()
val arr = Array(1,2,3,4,5,6,7,8,9)
val rdd: RDD[Int] = sc.parallelize(arr ,3)
//数据已经处理完成 得到最终的结果
val i: Int = rdd.reduce((x1, x2) => x1 + x2) reduce(+)
// 所以调用完算子返回的就是结果 直接打印
println(rdd.reduce((x1, x2) => x1 + x2))
sc.stop()
}

7.4 count
返回rdd元素的数量
def main(args: Array[String]): Unit = {
val sc: SparkContext = SparkUtil.getSparkContext()
val arr1 = Array(“a”, “b”, “c”, “c”)
val arr2 = Array(1, 2, 3, 4)
//拉链成对偶
val rdd: RDD[(String, Int)] = sc.parallelize(arr1.zip(arr2),3)
val l: Long = rdd.count()
println(l)
sc.stop()
}

7.5 top
将RDD中数据按照降序或者指定的排序规则,返回前n个元素
def main(args: Array[String]): Unit = {
val sc: SparkContext = SparkUtil.getSparkContext()
// 读取本地文件中的数据
val rdd: RDD[String] = sc.textFile(“d://word.txt”)
// 切割每行数据
val rdd2: RDD[String] = rdd.flatMap(_.split("\s"))
//获取前n个元素 his排好序的数据
val res: Array[String] = rdd2.top(4)
res.foreach(println)
sc.stop()
}

7.6 take
返回一个包含数据集前n个元素的数组(从0下标到n-1下标的元素),不排序。

def main(args: Array[String]): Unit = {
val sc: SparkContext = SparkUtil.getSparkContext()
// 读取本地文件中的数据
val rdd: RDD[String] = sc.textFile(“d://word.txt”)
// 切割每行数据
val rdd2: RDD[String] = rdd.flatMap(_.split("\s"))
//返回一个包含数据集前n个元素的数组(从0下标到n-1下标的元素),不排序。
val res: Array[String] = rdd2.take(4)
res.foreach(println)
sc.stop()
}

7.7 first
返回数据集的第一个元素(类似于take(1)),返回0号分区的第一个元素!
def main(args: Array[String]): Unit = {
val sc: SparkContext = SparkUtil.getSparkContext()
val arr1 = Array(“a”, “b”, “c”, “c”)
val arr2 = Array(1, 3, 2, 3)
//拉链成对偶
val rdd: RDD[(String, Int)] = sc.parallelize(arr1.zip(arr2),3)
println(rdd.first())
sc.stop()
}

7.8 takeOrdered
返回RDD中前n个元素,并按默认顺序排序(升序)或者按自定义比较器顺序排序
def main(args: Array[String]): Unit = {
val sc: SparkContext = SparkUtil.getSparkContext()
// 读取本地文件中的数据
val rdd: RDD[String] = sc.textFile(“d://word.txt”)
// 切割每行数据
val rdd2: RDD[String] = rdd.flatMap(_.split("\s"))
//获取前n个元素 his排好序的数据
val res: Array[String] = rdd2.takeOrdered(4)
res.foreach(println)
sc.stop()
}
·top返回最大的k个元素。
·take返回最小的k个元素。
·takeOrdered返回最小的k个元素,并且在返回的数组中保持元素的顺序。
·first相当于top(1)返回整个RDD中的前k个元素,可以定义排序的方式Ordering[T]。
返回的是一个含前k个元素的数组。

7.9 saveAsTextFile
函数将数据输出,存储到 HDFS 的指定目录或者是本地目录中。
下面为 saveAsTextFile 函数的内部实现,其内部
  通过调用 saveAsHadoopFile 进行实现:
将结果写入到HDFS中
def main(args: Array[String]): Unit = {
System.setProperty(“HADOOP_USER_NAME” , “root”)
val sc: SparkContext = SparkUtil.getSparkContext()
// 读取本地文件中的数据
val rdd: RDD[String] = sc.textFile(“d://word.txt”)
// 切割每行数据
val rdd2: RDD[String] = rdd.flatMap(.split("\s+"))
//将结果数据写到指定的文件夹下 根据分区的个数存储到不同的文件中
rdd2.repartition(3).map((
, 1)).reduceByKey(_ + ).sortBy(._2).saveAsTextFile(“hdfs://doit01:9000/res”)
sc.stop()
}

7.10 aggregate
传入两个函数,第一个函数在分区内聚合,第二个全局聚合 局部聚合和全局聚合都使用初始值
aggregate先对每个分区的所有元素进行aggregate操作,再对分区的结果进行fold操作。
  aggreagate与fold和reduce的不同之处在于,aggregate相当于采用归并的方式进行数据聚集,这种聚集是并行化的。 而在fold和reduce函数的运算过程中,每个分区中需要进行串行处理,每个分区串行计算完结果,结果再按之前的方式进行聚集,并返回最终聚集结果。
val arr = Array(1,2,3,4)
val rdd: RDD[Int] = sc.parallelize(arr,4)
// 参数一 区内计算 参数二区之间的运算
val res: Int = rdd.aggregate(10)(+ , _
_) // 11
12
13
14*10
println(res)

7.11 foreach
将数据一条一条的取出来进行处理,函数没有返回
def main(args: Array[String]): Unit = {
val sc: SparkContext = SparkUtil.getSparkContext()
val arr = Array(1, 2, 3, 4, 5, 6, 7, 8, 9)
val rdd: RDD[Int] = sc.parallelize(arr, 3)
// 直接对RDD中的每个元素再本客户端操作 一般用于打印展示在控制台
rdd.foreach(e => println(e * 10))
sc.stop()
}

7.12 ****foreachPartition
foreachPartition, 和foreach类似,只不过是以分区位单位,一个分区对应一个迭代器,应用外部传的函数,函数没有返回值,通常使用该方法将数据写入到外部存储系统中,一个分区获取一个连接,效果更高
val rdd1 = sc.parallelize(List(1,2,3,4,5,6,7,8,9), 2)
rdd1.foreachPartition(it => it.foreach(println))

7.13 fold
fold和reduce的原理相同,但是与reduce不同,相当于每个reduce时,迭代器取的第一个元素是zeroValue。
  图中通过下面的用户自定义函数进行fold运算,图中的一个方框代表一个RDD分区。 读者可以参照reduce函数理解。
fold((”V0@”,2))((A,B)=>(A._1+”@”+B._1,A._2+B._2)))

val arr = Array(1,2,3,4)
val rdd: RDD[Int] = sc.parallelize(arr,4)
val res: Int = rdd.fold(10)(+) // 60

你可能感兴趣的:(Action行动算子 及相应的举例)