Spark Transform算子和Action算子速查

前言

RDD是spark中最重要的抽象单位,所有的高级操作细化到底层,都是由RDD来完成的,RDD的操作有很多,但从计算的角度来划分,RDD可以分为转换算子和执行算子。

之前我们也讲到,RDD是惰性加载的,转换算子创建时并不会执行计算过程,只有当遇到执行算子时才会产生计算。本文就RDD的转换操作和执行操作作一个总结。

正文

首先创建执行环境和数据集

    val conf: SparkConf = new SparkConf().setMaster("local").setAppName("test01")
    val sc = new SparkContext(conf)
    sc.setLogLevel("ERROR")


    val kv1: RDD[(String, Int)] = sc.parallelize(List(
      ("zhangsan", 11),
      ("zhangsan", 12),
      ("lisi", 13),
      ("wangwu", 14)
    ))
    val kv2: RDD[(String, Int)] = sc.parallelize(List(
      ("zhangsan", 21),
      ("zhangsan", 12),
      ("zhangsan", 22),
      ("lisi", 23),
      ("zhaoliu", 28)
    ))

1、转换算子

1.1 map

--  RDD[U] 将函数应用于RDD的每一元素,并返回一个新的RDD
--  将RDD中的元素一个一个传入,进行转换计算

kv1.map(v=>{(v._1,v._2+1)}).foreach(println)

结果

(zhangsan,12)
(zhangsan,13)
(lisi,14)
(wangwu,15)

1.2 flatMap

	-- 同样是map操作,只是将map操作的数据扁平化了
    val list = List("hello thank you","thank you" ,"very much")
    val listRDD = sc.parallelize(list)
    

结果

hello
thank
you
thank
you
very
much

1.3 mapPartitions

-- 对每个分区进行操作,每一个分区运行一次,函数需要接受Iterator类型,然后返回Iterator。
    val list = List("hello thank you", "thank you", "very much")
    val listRDD = sc.parallelize(list,2)
    listRDD.mapPartitions(iterator=>{
     val sb:ListBuffer[String] =ListBuffer();
      while (iterator.hasNext){
        sb.append("111 "+iterator.next())
      }

结果

111 hello thank you
111 thank you
111 very much

1.4 filter

-- 设置过滤条件,将tuple2元组中第二列大于13的记录过滤掉

 kv1.filter(e=>{(e._2<13)}).foreach(println)

结果

(zhangsan,11)
(zhangsan,12)

1.5 mapPartitionsWithIndex

-- 与mapPartitonsWithIndex功能一样,但是可以获取到分区号

    val listRDD = sc.parallelize(list,2)
    listRDD.mapPartitionsWithIndex((index,iterator)=>{
     val sb:ListBuffer[String] =ListBuffer();
      while (iterator.hasNext){
        sb.append("分区号:"+index+" 值:"+iterator.next())
      }
      sb.iterator
    }).foreach(word=>println(word))

结果

    val listRDD = sc.parallelize(list,2)
    listRDD.mapPartitionsWithIndex((index,iterator)=>{
     val sb:ListBuffer[String] =ListBuffer();
      while (iterator.hasNext){
        sb.append("分区号:"+index+" 值:"+iterator.next())
      }
      sb.iterator
    }).foreach(word=>println(word))

1.6 Sample

  /**
     * sample用来从RDD中抽取样本。他有三个参数
     * withReplacement: Boolean,
     *       true: 有放回的抽样
     *       false: 无放回抽象
     * fraction: Double:
     *      抽取样本的比例
     * seed: Long:
     *      随机种子
     */
     
    val list = 1 to 100
    val listRDD = sc.parallelize(list)
    listRDD.sample(false,0.1,0).foreach(num => print(num + " "))

结果

10 39 41 53 54 58 60 80 89 98 

1.7 union

-- 将kv1和kv2取一个并集

kv1.union(kv2).foreach(println((_)))

结果

(zhangsan,11)
(zhangsan,12)
(lisi,13)
(wangwu,14)
(zhangsan,21)
(zhangsan,22)
(lisi,23)
(zhaoliu,28)

1.8 intersection

-- 将两个RDD取一个并集
-- 为了显示效果,我们在kv2中添加了一条kv1中的记录

kv1.intersection(kv2).foreach(println((_)))

结果

(zhangsan,12)

1.9 distinct

-- 将一个RDD进行去重操作
-- 为了显示效果,我们在kv1中添加了一条重复记录

kv1.distinct().foreach(println(_))

结果

(zhangsan,12)
(lisi,13)
(zhangsan,11)
(wangwu,14)

1.10 partitionBy

--  partitionBy()需要传入一个partitioner

kv1.partitionBy(new org.apache.spark.HashPartitioner(2)).foreach(println)

结果

(zhangsan,11)
(zhangsan,12)
(lisi,13)
(wangwu,14)

1.11 repartiton

-- repartiton需要传入一个numpartition

kv1.repartition(3).foreach(println)

结果

(zhangsan,11)
(zhangsan,12)
(lisi,13)
(wangwu,14)

1.12 join

   -- join操作按key分组,最终成为(key,(value1,value2))的形式
    val list1 = List((1, "张三"), (2, "李四"), (3, "王五"))
    val list2 = List((1, 99), (2, 98), (3, 97))
    val list1RDD = sc.parallelize(list1)
    val list2RDD = sc.parallelize(list2)

    val joinRDD = list1RDD.join(list2RDD)
    joinRDD.foreach(t => println("学号:" + t._1 + " 姓名:" + t._2._1 + " 成绩:" + t._2._2))

结果

学号:1 姓名:张三 成绩:99
学号:3 姓名:王五 成绩:97
学号:2 姓名:李四 成绩:98

1.13 reduceBykey

-- reduceBykey按key分组,对key相同的记录做计算

val res: RDD[(String, Int)] = kv1.reduceByKey((x, y) => x + y)

结果

(zhangsan,23)
(wangwu,14)
(lisi,13)

1.14 cartesian

 -- cartesian求两个RDD的笛卡尔积

kv1.cartesian(kv2).foreach(println(_))

结果

((zhangsan,11),(zhangsan,21))
((zhangsan,11),(zhangsan,12))
((zhangsan,11),(zhangsan,22))
((zhangsan,11),(lisi,23))
((zhangsan,11),(zhaoliu,28))
((zhangsan,12),(zhangsan,21))
((zhangsan,12),(zhangsan,12))
((zhangsan,12),(zhangsan,22))
((zhangsan,12),(lisi,23))
((zhangsan,12),(zhaoliu,28))
((lisi,13),(zhangsan,21))
((lisi,13),(zhangsan,12))
((lisi,13),(zhangsan,22))
((lisi,13),(lisi,23))
((lisi,13),(zhaoliu,28))
((wangwu,14),(zhangsan,21))
((wangwu,14),(zhangsan,12))
((wangwu,14),(zhangsan,22))
((wangwu,14),(lisi,23))
((wangwu,14),(zhaoliu,28))

1.15 goupBykey

-- groupBykey对key进行分组,转换成(k,CompactBuffer())的形式

kv1.groupByKey().foreach(println)

结果

(zhangsan,CompactBuffer(11, 12))
(wangwu,CompactBuffer(14))
(lisi,CompactBuffer(13))

1.16 sortBykey

 -- sortBykey 按key分组从小到大排序
 
 kv1.sortByKey().foreach(println)

结果

(lisi,13)
(wangwu,14)
(zhangsan,11)
(zhangsan,12)

1.17 cogroup

--对两个RDD中的KV元素,每个RDD中相同key中的元素分别聚合成一个集合。
--与reduceByKey不同的是它针对两个RDD中相同的key的元素进行合并。

    val rdd1 = sc.parallelize(Array(("aa",1),("bb",2),("cc",6)))
    val rdd2 = sc.parallelize(Array(("aa",3),("dd",4),("aa",5)))
    rdd1.cogroup(rdd2).foreach(println)

结果

(aa,(CompactBuffer(1),CompactBuffer(3, 5)))
(dd,(CompactBuffer(),CompactBuffer(4)))
(bb,(CompactBuffer(2),CompactBuffer()))
(cc,(CompactBuffer(6),CompactBuffer()))

1.18 coalesce

-- coalesce和repartition都是对RDD进行分区,但是coalesce不会产生shuffle操作,
-- 因此它的分区数也不一定就是用户设置的分区数

    val value: RDD[(String, Int)] = kv1.coalesce(5)
    println(value.partitions.length)

结果

1

1.19 mapValues

 -- mapValues 传入每组数据的value,对其进行计算
 
 kv1.mapValues(x=>x+1).foreach(println)

结果

(zhangsan,12)
(zhangsan,13)
(lisi,14)
(wangwu,15)

1.20 subtract

 -- substract 对两个RDD取差集
 
 kv1.subtract(kv2).foreach(println)

结果

(wangwu,14)
(lisi,13)
(zhangsan,11)

2、执行算子

2.1 reduce

	-- reduce 操作涉及到新值和老值,两个数计算的结果又作为老值传入reduce函数
	
	val list = List(1,2,3,4,5,6)
    val listRDD = sc.parallelize(list)

    val result: Int = listRDD.reduce((x, y) => x + y)
    println(result)

结果

21

2.1 foreach

-- 在数据集的每一个元素上,运行函数func进行更新。

 kv1.foreach(println)

结果

(zhangsan,11)
(zhangsan,12)
(lisi,13)
(wangwu,14)

2.2 takeSample

-- 抽样但是返回一个scala集合。

kv1.takeSample(false,2,0).foreach(println)

结果

(zhangsan,11)
(lisi,13)

2.3 collect

-- 以数组的形式返回数据集的所有元素

val tuples: Array[(String, Int)] = kv1.collect()
tuples.foreach(f=>{println(f._1+" "+f._2)})

结果

zhangsan 11
zhangsan 12
lisi 13
wangwu 14

2.4 count

- 返回RDD中元素的个数

 println(kv1.count())

结果

4

2.5 first

-- 返回RDD的第一个元素

println(kv1.first())

结果

(zhangsan,11)

2.6 take

-- 以返回RDD的前n个元素

val tuples: Array[(String, Int)] = kv1.take(2)
tuples.foreach(f=>println(f._1+" "+f._2))

结果

zhangsan 11
zhangsan 12

2.7 takeOrdered

 -- 返回前几个的排序
val rdd1: RDD[Int] = sc.parallelize( List( 1,2,0,8,9,3,4,5)  )
val ints: Array[Int] = rdd1.takeOrdered(3)
ints.foreach(f=>println(f))

结果

0
1
2

2.8 aggregate

 -- 接受多个输入,并按照一定的规则运算以后输出一个结果值
 
 val rdd1: RDD[Int] = sc.parallelize( List( 1,2,2,8,9,3,4,5))
 
     def func1(v1:Int,v2:Int):Int={
      v1*v2
    }

    def func2(v3:Int,v4:Int):Int={
      v3+v4
    }

    println(rdd1.aggregate(1)(func1, func2))

结果

// 首先运行第一个函数func1:初始值为1,所以1*1*2*2*8*9*3*4*5=17280
// 接着运行第二个函数func2:初始值为1,所以1+17280=17281

17281

2.9 fold

-- 与reduce类似,区别就是fold有一个初始值

val rdd1: RDD[Int] = sc.parallelize( List( 1,2,2,8,9,3,4,5))
println(rdd1.fold(0)(func2))

结果

34

2.10 saveAsTextFile

将RDD以文本文件的方式保存到本地或者HDFS中

val rdd1: RDD[Int] = sc.parallelize( List( 1,2,2,8,9,3,4,5))
rdd1.saveAsTextFile("./data/test/test.txt")

结果

test.txt

2.11 countBykey

-- 按key对记录进行统计,结果以Map(key,int)的类型返回

 println(kv1.countByKey())

结果

Map(zhangsan -> 2, wangwu -> 1, lisi -> 1)

猜你喜欢

转载自blog.csdn.net/qq_37163925/article/details/106216400
今日推荐