package com.xxx.spark.day03
import org.apache.spark.rdd.RDD
import org.apache.spark.rdd.RDD.rddToPairRDDFunctions
import org.apache.spark.{SparkConf, SparkContext}
object _01ExampleOperator {
def main(args: Array[String]): Unit = {
testRepartition
}
/**
* 此算子也是重新指定分区数,默认开启shuffle,所以可以指定新分区数大于原来分区数
*/
def testRepartition: Unit ={
val conf = new SparkConf().setMaster("local[1]").setAppName("saa")
val sc = new SparkContext(conf)
val rdd1: RDD[String] = sc.parallelize(Array("1", "2", "3", "4", "5","6","7","8"), 4)
val value: RDD[String] = rdd1.repartition(1)
value.foreach(println)
/*
运行结果:
1
2
3
4
5
6
7
8
*/
}
/**
* 此算子会将RDD重新进行分区,第一个参数为重新分区的分区个数,第二个参数是是否开启shuffle,默认为false,false则重新指定的分区个数大于原来的分区数时,不会生效,还是原来的分区数
*
*/
def testCoalesce: Unit ={
val conf = new SparkConf().setMaster("local[1]").setAppName("saa")
val sc = new SparkContext(conf)
val rdd1: RDD[String] = sc.parallelize(Array("1", "2", "3", "4", "5","6","7","8"), 4)
val value: RDD[String] = rdd1.coalesce(1)
value.foreach(println)
/*
运行结果:
1
2
3
4
5
6
7
8
*/
}
/**
* 此算子先按key分组,然后将每一组中的每一个元素和默认值进行拼接
*/
def testAggregateByKey: Unit ={
val conf = new SparkConf().setMaster("local[1]").setAppName("saa")
val sc = new SparkContext(conf)
val rdd1: RDD[(Int, String)] = sc.parallelize(Array((1001, "张作霖"), (1002, "张学良"), (1003, "郭松龄"), (1004, "汤玉麟"), (1001, "张作霖"), (1005, "张作霖")), 3)
val value: RDD[(Int, String)] = rdd1.aggregateByKey("-")((x, y) => x + y, (x, y) => x + y)
value.foreach(println)
/*
运算结果:
(1002,-张学良)
(1005,-张作霖)
(1003,-郭松龄)
(1001,-张作霖-张作霖)
(1004,-汤玉麟)
*/
}
/**
* aggtegate:合计,总计,集合体
* 此算子的第一个参数是一个默认值,第二个参数中将默认值和整个分区作为一个整体进行拼接,然后再将所有分区作为一个整体和默认值再次拼接
*
*/
def testAggregate: Unit ={
val conf = new SparkConf().setMaster("local[1]").setAppName("saa")
val sc = new SparkContext(conf)
val rdd1: RDD[String] = sc.parallelize(Array("1", "2", "3", "4", "5","6","7","8"), 4) //默认为1个分区
val str: String = rdd1.aggregate("-")((x, y) => x + y, (x, y) => x + y)
println(str)
/*
运行结果:
--12-34-56-78
*/
}
/**
* 此算子调用reduceByKey对RDD中的元素去重,底层还是调用combineByKey,重新指定分区的时候会触发shuffle
*/
def testDistinct: Unit = {
val conf = new SparkConf().setMaster("local[1]").setAppName("saa")
val sc = new SparkContext(conf)
val rdd1: RDD[Int] = sc.parallelize(Array(1, 2, 3, 4, 5, 4, 2, 4, 5, 1, 2, 3), 3) //默认为1个分区
val value: RDD[Int] = rdd1.distinct(1)
value.foreach(println)
/*
运行结果:
4
1
3
5
2
*/
}
/**
* 通过key将分区内的元素通过key累加value,可以指定分组之后的分区数,也可以自定义分区函数
* 此算子底层调用了combineByKey,所以在指定分区数量的时候会触发shuffle
*/
def ReduceByKey: Unit = {
val conf: SparkConf = new SparkConf().setMaster("local").setAppName("saa")
val sc = new SparkContext(conf)
val rdd1: RDD[(Int, String)] = sc.parallelize(Array((1001, "张作霖"), (1002, "张学良"), (1003, "郭松龄"), (1004, "汤玉麟"), (1001, "张作霖"), (1005, "张作霖")), 3)
val value: RDD[(Int, String)] = rdd1.reduceByKey((x, y) => x + y, 1)
value.foreach(println)
/*
(1002,张学良)
(1005,张作霖)
(1001,张作霖张作霖)
(1003,郭松龄)
(1004,汤玉麟)
*/
}
/**
* 就是将每个分区中的相同的元素分到一组并且提供这个集合的迭代器,返回值是一个元组,key是这个元素,value是这个分区中所有对应元素的集合
* 底层先是调用了groupByKey,然后调用了combineByKey,也是在重新指定分区时触发shuffle
*
* 这个操作可能非常昂贵。如果要对每个键进行分组以执行聚合(比如求和或平均),请使用PairRDDFunctions。aggregateByKey
* 或PairRDDFunctions。reduceByKey将提供更好的性能。
*/
def GroupBy: Unit = {
val conf = new SparkConf().setMaster("local[1]").setAppName("saa")
val sc = new SparkContext(conf)
val rdd1: RDD[Int] = sc.parallelize(Array(1, 2, 3, 4, 5, 4, 2, 4, 5, 1, 2, 3), 3) //默认为1个分区
val value: RDD[(Int, Iterable[Int])] = rdd1.groupBy(x => x)
value.foreach(println)
/*
运行结果
(4,CompactBuffer(4, 4, 4))
(1,CompactBuffer(1, 1))
(3,CompactBuffer(3, 3))
(5,CompactBuffer(5, 5))
(2,CompactBuffer(2, 2, 2))
*/
}
/**
* 此算子是根据key进行分组,第一个参数为分区个数,如果不指定,原来几个分区,就输出几个分区,可以自定义分组之后的分区个数,在重新指定了分区个数时,会触发shuffle,
* 第二个参数partitioner用于指定分区函数
*/
def testGroupByKey: Unit = {
val conf: SparkConf = new SparkConf().setMaster("local").setAppName("saa")
val sc = new SparkContext(conf)
val rdd1: RDD[(Int, String)] = sc.parallelize(Array((1001, "张作霖"), (1002, "张学良"), (1003, "郭松龄"), (1004, "汤玉麟"), (1001, "张作霖"), (1005, "张作霖")), 3)
val value: RDD[(Int, Iterable[String])] = rdd1.groupByKey(1)
value.foreach(println)
/*
(1002,CompactBuffer(张学良))
(1005,CompactBuffer(张作霖))
(1001,CompactBuffer(张作霖, 张作霖))
(1003,CompactBuffer(郭松龄))
(1004,CompactBuffer(汤玉麟))
*/
}
/**
* 该函数用于将RDD[K,V]转换成RDD[K,C],这里的V类型和C类型可以相同也可以不同。
*
* 其中的参数:
*
* createCombiner:组合器函数,用于将V类型转换成C类型,输入参数为RDD[K,V]中的V,输出为C
*
* mergeValue:合并值函数,将一个C类型和一个V类型值合并成一个C类型,输入参数为(C,V),输出为C
*
* mergeCombiners:合并组合器函数,用于将两个C类型值合并成一个C类型,输入参数为(C,C),输出为C
*
* numPartitions:结果RDD分区数,默认保持原有的分区数
*
* partitioner:分区函数,默认为HashPartitioner
*
* mapSideCombine:是否需要在Map端进行combine操作,类似于MapReduce中的combine,默认为true
*/
def ComblneByKey: Unit = {
val conf: SparkConf = new SparkConf().setMaster("local").setAppName("saa")
val sc = new SparkContext(conf)
val rdd1: RDD[(Int, String)] = sc.parallelize(Array((1001, "张作霖"), (1002, "张学良"), (1003, "郭松龄"), (1004, "汤玉麟"), (1001, "张作霖"), (1005, "张作霖")), 3)
// rdd1.combineByKey((v: String) => v + "_", (c: String, v: String) => c + "-" + v, (c1: String, c2: StringContext) => c1 + ":" + c2,1)
val value: RDD[(Int, String)] = rdd1.combineByKey((v: String) => v + "_", (c: String, v: String) => c + v, (c1: String, c2: String) => c1 + c2, 1)
value.foreach(println)
/*
运行结果:
(1002,张学良_)
(1005,张作霖_)
(1001,张作霖_张作霖_)
(1003,郭松龄_)
(1004,汤玉麟_)
*/
}
/**
* 此算子是将RDD中的元素进行全局排序,之后按照分区显示,第一个参数指定排序规则,默认true为升序,第二个参数指定排序后的分区的个数,会触发shuffle
*/
def testSortByKey: Unit = {
val conf: SparkConf = new SparkConf().setMaster("local").setAppName("saa")
val sc = new SparkContext(conf)
val rdd1: RDD[(Int, String)] = sc.parallelize(Array((1001, "张作霖"), (1002, "张学良"), (1003, "郭松龄"), (1004, "汤玉麟"), (1001, "张作霖"), (1005, "张作霖")), 3)
val value: RDD[(Int, String)] = rdd1.sortByKey(true, 1)
value.foreach(println)
/*
运行结果:
(1001,张作霖)
(1001,张作霖)
(1002,张学良)
(1003,郭松龄)
(1004,汤玉麟)
(1005,张作霖)
*/
}
/**
* 此算子是将RDD中的元素进行全局排序,之后按照分区显示,第二个参数指定排序规则,默认true为升序,第三个参数指定排序后的分区的个数,底层是调用了sortByKey,会触发shuffle
*/
def testSortBy: Unit = {
val conf: SparkConf = new SparkConf().setMaster("local").setAppName("saa")
val sc = new SparkContext(conf)
val rdd1: RDD[(Int, String)] = sc.parallelize(Array((1001, "张作霖"), (1002, "张学良"), (1003, "郭松龄"), (1004, "汤玉麟"), (1001, "张作霖"), (1005, "张作霖")))
val value: RDD[(Int, String)] = rdd1.sortBy(x => x)
value.foreach(println)
/*
(1001,张作霖)
(1001,张作霖)
(1002,张学良)
(1003,郭松龄)
(1004,汤玉麟)
(1005,张作霖)
*/
}
/**
* 此算子先按第一个RDD的元素的key进行一次groupby,然后再用结果和第二个RDD中元素的key进行groupby
* 也可以理解为相当于sql中的full outer join ,返回两个RDD的元素,没有一样的key的为空
*/
def testCoGroup: Unit = {
val conf: SparkConf = new SparkConf().setMaster("local").setAppName("saa")
val sc = new SparkContext(conf)
val rdd1: RDD[(Int, String)] = sc.parallelize(Array((1001, "张作霖"), (1002, "张学良"), (1003, "郭松龄"), (1004, "汤玉麟"), (1001, "张作霖"), (1005, "张作霖")))
val rdd2: RDD[(Int, String)] = sc.parallelize(Array((1001, "张作霖"), (1002, "张学良"), (1003, "郭松龄"), (1004, "汤玉麟")))
val value: RDD[(Int, (Iterable[String], Iterable[String]))] = rdd1.cogroup(rdd2)
value.foreach(println)
/*
运行结果:
(1002,(CompactBuffer(张学良),CompactBuffer(张学良)))
(1005,(CompactBuffer(张作霖),CompactBuffer()))
(1001,(CompactBuffer(张作霖, 张作霖),CompactBuffer(张作霖)))
(1003,(CompactBuffer(郭松龄),CompactBuffer(郭松龄)))
(1004,(CompactBuffer(汤玉麟),CompactBuffer(汤玉麟)))
*/
}
/**
* 此函数是将kv形式的RDD中的元素统计相同key的value的个数
*/
def testCountByValue: Unit = {
val conf = new SparkConf().setMaster("local[1]").setAppName("saa")
val sc = new SparkContext(conf)
val rdd1: RDD[(Int, String)] = sc.parallelize(Array((1001, "张作霖"), (1002, "张学良"), (1003, "郭松龄"), (1004, "汤玉麟"), (1001, "张作霖"), (1005, "张作霖")))
val tupleToLong: collection.Map[(Int, String), Long] = rdd1.countByValue()
println(tupleToLong)
}
/**
* mapPartitionsWithIndex 是可以选择带上分区号,对每个分区中的元素映射出来做操作
* 和mapPartitions效果一样,只是再第一个参数可以得到分区号
*/
def testMapParttitonsWithIndex: Unit = {
val conf = new SparkConf().setMaster("local[1]").setAppName("saa")
val sc = new SparkContext(conf)
val rdd1: RDD[Int] = sc.parallelize(Array(1, 2, 3, 4, 5), 2)
val value: RDD[String] = rdd1.mapPartitionsWithIndex((x: Int, iter) => iter.map(_ + 1 + ":" + x))
value.foreach(println)
/*
运行结果:
2:0
3:0
4:1
5:1
6:1
*/
}
/**
* mapPartitions是将每一个分区中的元素映射出来进行操作
* 该函数和map函数有些类似,只不过映射函数的参数由RDD中的每一个元素变成了RDD中的每一个分区的迭代器
* 如果再映射的过程中需要频繁的创建额外的对象,使用mapPartitions要比map效率高,因为不用为每一个元素创建一个connection,而是一个分区创建一个connection
* 第三个参数:preservesPartitioning表示是否保留父RDD的partition分区的信息
*/
def testMapPartitions: Unit = {
val conf = new SparkConf().setMaster("local[1]").setAppName("saa")
val sc = new SparkContext(conf)
val rdd1: RDD[Int] = sc.parallelize(Array(1, 2, 3, 4, 5), 2)
val value: RDD[Int] = rdd1.mapPartitions(x => {
x.map(_ + 2)
})
value.foreach(println)
/*
运行结果:
3
4
5
6
7
*/
}
/**
* glom 是将RDD中的每一个分区中的元素返回一个数组,多个分区返回多个数组
* 将RDD中的每一个分区中类型为T的元素转换成Array[t],这样一个分区就只有一个数组元素
*/
def testGlom: Unit = {
val conf = new SparkConf().setMaster("local[1]").setAppName("saa")
val sc = new SparkContext(conf)
val rdd1: RDD[Int] = sc.parallelize(Array(1, 2, 3, 4, 5), 2)
val value: RDD[Array[Int]] = rdd1.glom()
// value.foreach(_.foreach(println))
value.foreach(for (i <- _) println(i))
/*
运行结果;
1
2
3
4
5
*/
}
}
SparkCore -- 04 【常用的RDD算子】
于 2020-11-18 21:52:13 首次发布