import org.apache.spark.sql.SparkSession
import scala.collection.mutable.ArrayBuffer
/**
* Created by LE on 2017/3/23.
*/
object DemoTransformations {
//spark入口
def main(args: Array[String]): Unit = {
val spark = SparkSession.builder.appName("DemoTransformations").master("local[*]").getOrCreate()
val sc = spark.sparkContext
//RDD算子
//map
{
val list = 1 to 30
val rdd = sc.parallelize(list).map(a => a * a) //1-30的每个数自乘
println(rdd.collect.mkString(";")) //collect相当于一个汇总
val list1 = new ArrayBuffer[Int]()
def fun_map(a: Int): Int = {
return a * 2
}
for (i <- list1) {
list1.append(fun_map(i)) //把fun_map()追加到list1里面
}
println(list1.mkString(","))
println("$" * 50)
}
//flatMap
{
val list2 = Array("abc def", "x,y,z")
val rdd2 = sc.parallelize(list2).flatMap(_.split("|,"))
println(rdd2.collect.mkString(";")) //;a;b;c; ;d;e;f;;x;,;y;,;z
val rdd3 = sc.parallelize(list2).map(_.split("|,")).collect //,a,b,c, ,d,e,f
rdd3.foreach(a => println(a.mkString(","))) //,x,,,y,,,z
println("*" * 50)
}
//mapPartitions用户通过函数 f (iter)=>iter.f ilter(_>=3) 对分区中所有数据进行过滤,大于和等于 3 的数据保留。
// 一个方块代表一个 RDD 分区,含有 1、 2、 3 的分区过滤只剩下元素 3。
{
var rdd4 = sc.parallelize(1 to 20).mapPartitions(a => a.filter(_ >= 10)) //小于等于10的数删除展示大于10的数
rdd4.glom.foreach(a => println(a.mkString(","))) //a.mkstring表示转换类型以,分割
println("*" * 50)
}
//glom函数将每个分区形成一个数组分区Array[(V1),(V2),(V3)]。
{
val rdd1 = sc.parallelize(1 to 20)
rdd1.glom.foreach(a => println(a.mkString(",")))
println(rdd1.glom.count())
println("*" * 50)
}
//union返回的 RDD 数据类型和被合并的 RDD 元素数据类型
// 相同含有V1、V2、U1、U2、U3、U4的RDD和
// 含有V1、V8、U5、U6、U7、U8的RDD合并所有元素形成一个RDD。V1、V1、V2、V8形成一个分区,
// U1、U2、U3、U4、U5、U6、U7、U8形成一个分区。
{
val list1 = Array("v1,v2")
val list2 = Array("u1,u2,u3,u4")
val list3 = Array("v1,v8")
val list4 = Array("u5,u6,u7,u8")
val rdd1 = list1.union(list2)
val rdd2 = list3 ++ list1
println(rdd1.mkString(","))
println(rdd2.mkString(","))
}
//cartesian V1 和 另 一 个 RDD 中 的 W1、 W2、 Q5 进 行 笛 卡 尔 积 运 算
// 形 成 (V1,W1)、(V1,W2)、 (V1,Q5)。
{
val rdd = sc.parallelize(1 to 5)
val rdd1 = sc.parallelize(11 to 15)
val rdd2 = rdd.cartesian(rdd1)
println(rdd2.collect.mkString(";"))
println("*" * 50)
}
//groupby将元素通过函数生成相应的 Key,数据就转化为 Key-Value 格式,之后将 Key 相同的元素分为一组
{
val rdd1 = sc.parallelize(Array("A1", "A2", "A3", "B1", "B2"))
val rdd2 = rdd1.groupBy(_ (1)) //下划线表示每一个独立的元素 A1,A2 (1)表示元素的下标
rdd2.foreach(println) //foreach一个循环 1,A1,B1 2,A2,B2 3, A3
println("*" * 50)
}
//filter对元素进行过滤
{
val rdd = sc.parallelize(1 to 10)
//1-10 个元素
val rdd1 = rdd.filter(_ > 5) //小于5的元素过滤掉
println(rdd1.collect.mkString(";"))
println("*" * 50)
}
//distinct将RDD中的元素进行去重操作
{
val rdd = sc.parallelize((1 to 10) ++ (6 to 15))
//++相当于连接符
val rdd1 = rdd.distinct()
println(rdd.collect.mkString(";")) //把1-10和6-15汇总到一起
println(rdd1.collect.mkString(";")) //把1-10和6-15之间相同的去掉后的汇总
println("*" * 50)
}
//subtract进行集合的差操作
{
val rdd1 = sc.parallelize(1 to 10)
val rdd2 = sc.parallelize(6 to 15)
val rdd3 = rdd1.subtract(rdd2)//把1-10和6-15之间的数进行相减12345
val rdd4 = rdd2.subtract(rdd1)//11,12,13,14,15
println(rdd3.collect.mkString(";"))
println(rdd4.collect.mkString(";"))
println("*" * 50)
}
//sample 将 RDD 这个集合内的元素进行采样,获取所有元素的子集
{
val rdd = sc.parallelize(1 to 100)
val rdd1 = rdd.sample(false, 0.5)
println(rdd1.collect.mkString(";"))
val rdd2 = rdd.sample(true, 0.5)
println(rdd2.collect.mkString(";"))
//每次结果不同
println("$"*50)
}
//takeSample takeSample()函数和上面的sample函数是一个原理,但是不使用相对比例采样,
// 而是按设定的采样个数进行采样,同时返回结果不再是RDD,而是相当于对采样后的数据进行
val rdd = sc.parallelize(1 to 100)
val rdd1 =rdd.takeSample(false,20)//去1-100之内的20为数字
println(rdd1.mkString(","))
println("$"*50)
//mapvalues 针对(Key, Value)型数据中的 Value 进行 Map 操作,而不对 Key 进行处理。
//
val rdd1 = sc.parallelize(List("A" -> 1,"A" -> 2,"B1" -> 3,"B2" -> 4))
val rdd2 = rdd1.mapValues(_*2)
println(rdd2.collect.mkString(","))
println("&"*50)//(A,2),(A,4),(B1,6),(B2,8)
//combineByKey 相当于将元素为 (Int, Int) 的 RDD 转变为了
// (Int, Seq[Int]) 类型元素的 RDD
val rdd1 = sc.parallelize(Array(("A1" -> 1), ("B1" -> 2), ("B1" -> 3)))
val rdd2 = rdd1.combineByKey(
(a: Int) => "@" + a.toString,
(a: String, b: Int) => a + "#" + b.toString,
(a: String, b: String) => a + "&" + b)
println(rdd2.collect.mkString(";"))
println("*" * 50)
//reduceByKey 通过用户自定义函数 (A,B) => (A + B) 函数,
// 将相同 key 的数据 (V1,2) 和 (V1,1) 的 value 相加运算,结果为( V1,3)。
val rdd = sc.parallelize(Array(("A1"-> 2),("B1"->4),("B1"->5)))
val rdd1 = rdd.reduceByKey(_+_)
println(rdd1.collect.mkString(","))
println("$"*50)
}
//partitionBy如果原有RDD的分区器和现有分区器(partitioner)一致,
// 则不重分区,如果不一致,则相当于根据分区器生成一个新的ShuffledRDD
{
val rdd1 = sc.parallelize(Array(("A1" -> 1), ("B1" -> 2), ("B1" -> 3)))
val rdd2 = rdd1.partitionBy(new org.apache.spark.HashPartitioner(4))
rdd1.glom.foreach(a => println(a.mkString(",")))
rdd2.glom.foreach(a => println(a.mkString(",")))
println("&" * 50)
}
//Cogroup函数将两个RDD进行协同划分RDD1中的数据(U1,1)、 (U1,2)
// 和RDD2中的数据(U1,2)合并为(U1,((1,2),(2)))。
{
val rdd = sc.parallelize(Array(("A1" -> 1),("B1" -> 12),("B1" ->13),("E1" -> 4)))
val rdd1 = sc.parallelize(Array(("A1" -> 11),("B1" -> 22),("C1" ->10)))
val rdd2 = rdd.cogroup(rdd1)
println(rdd2.collect.mkString(","))
println("&"*50)
}
//join java中的for循环
{
val rddA = sc.parallelize(Array(("A1" -> 1), ("B1" -> 2), ("B1" -> 3)))
val rddB = sc.parallelize(Array(("A1" -> 11), ("B1" -> 12), ("C1" -> 13)))
// A1->((1),(11)) B1->((2,3),12)
//A1->(1,11) B1->(2,12) B1->(3,12)
val rdd1 = rddA.join(rddB)
println(rdd1.collect.mkString(";"))
println("*" * 50)
}
//leftOuterJoin左连接
{
val rddA = sc.parallelize(Array(("A1" -> 1), ("B1" -> 2), ("B1" -> 3)))
val rddB = sc.parallelize(Array(("A1" -> 11), ("B1" -> 12), ("C1" -> 13)))
val rdd1 = rddA.leftOuterJoin(rddB)
println(rdd1.collect.mkString(";"))
println("*" * 50)
}
// rightOuterJoin 右连接
{
val rddA = sc.parallelize(Array(("A1" -> 1), ("B1" -> 2), ("B1" -> 3)))
val rddB = sc.parallelize(Array(("A1" -> 11), ("B1" -> 12), ("C1" -> 13), ("C1" -> 14)))
// A1->((1),(11)) B1->((2,3),(12)) C1->((NULL),(13,14))
//A1->(1,11) B1->(2,12) B1->(3,12) C1->(NULL,13) C1->(NULL,14)
val rdd1 = rddA.rightOuterJoin(rddB)
println(rdd1.collect.mkString(";"))
println("*" * 50)
}
spark.stop()
}}