一、RDD的创建
1、从内存中创建-> rddBuilderMemory
sc.makeRDD(List(1,2,3,4,5))
2、从文件中创建->rddBuilderFile
val value2: RDD[String] = sparkContext.textFile("/**/**")
val value1: RDD[Nothing] = sparkContext.objectFile("/**/**")
val value: RDD[(String, Int)] = sparkContext.sequenceFile("/**/**")
二、RDD算子
RDD算子 = RDD方法:
1、转换 :功能的补充和封装,将旧的RDD包装成新的RDD
eg:flatMap、map
2、行动:触发任务的调度和作业的执行
eg:collect
RDD转换算子
单值类型
map
//此处函数作为参数
/*
map是一对一的转换操作
map算子是作用在每个分区、每个元素上,对每个元素执行自定义的函数
val rddMap: Array[Int] = rdd.collect().map((i: Int) => { i * 5})
*/
val rddMap = rdd.map(_ * 5)
rddMap.collect().foreach(println)
mapPartitions
val rdd: RDD[Int] = sparkContext.makeRDD(List(1, 2, 3, 4, 5, 6),2)
//mapPartitions,相当于把同一个分区的先执行
将待处理的数据
以分区为单位发送到计算节点进行处理,
这里的处理是指可以进行任意的处理,哪怕是过滤数据。
(效率较高,得到一个分区后的数据才开始计算,但是对内存需求较高)
val mapParRdd: RDD[Unit] = rdd.mapPartitions(
_.map(println)//此时的参数为 迭代器 iter
)
mapParRdd.collect()
mapPartitionsWithIndex
带分区号的map,把iter进行更改,再返回
样例为输出带分区号的元素
val rdd = sparkContext.makeRDD(List(1, 2, 3, 4, 5, 6, 7, 8, 9))
rdd.mapPartitionsWithIndex(
f = (index, iter) => {
iter.map((index,_))
}
).collect().foreach(println(_))
groupBy
/*
* 返回值为key,根据内层函数的返回值分组归类*/
println("奇偶数归类")
val rdd: RDD[Int] = sparkContext.makeRDD(List(1, 2, 3, 4, 5, 6, 7, 8, 9))
val groupByRdd: RDD[(Int, Iterable[Int])] = rdd.groupBy(_ % 2)
groupByRdd.collect().foreach(println)
println("根据字符串首字母归类")
val rdd1: RDD[String] = sparkContext.makeRDD(List("pokey", "hotpot", "login", "hello", "hello"))
rdd1.groupBy(_.charAt(0)).collect().foreach(println(_))
glom
/*
* 将同一个分区的数据转换为同类型的内存数组进行处理
*/
val rdd: RDD[Int] = sparkContext.makeRDD(List(1, 2, 3, 4, 5, 6, 7, 8, 9))
val glomRdd: RDD[Array[Int]] = rdd.glom()//Int->Array[Int]
glomRdd.collect().foreach(data=>println(data.mkString(",")))
flatMap
/*
flatMap就是扁平化处理
*/
val rddStr: RDD[String] = sparkContext.makeRDD(List("hello hotpot", "hello pokey", "hello login"))
println("\neg No2 按空格分隔")
val flatRddStr: RDD[String] = rddStr.flatMap(_.split(" "))
flatRddStr.collect().foreach(println(_))
filter
/*
* filter 就是过滤器,将数据根据指定的规则筛选符合的数据保留
自定义函数用于定义过滤规则
* */
val rdd: RDD[Int] = sparkContext.makeRDD(List(1, 23, 456, 789, 456, 123, 4, 5, 0, 9, 132, 96874, 132, 898, 9, 4, 65497, 43))
val filterRdd: RDD[Int] = rdd.filter(_ >= 12)
filterRdd.collect().foreach(println(_))
sample
//sample的三个参数
withReplacement: Boolean,#是否又放回抽样
fraction: Double,#抽取的几率
seed: Long = Utils.random.nextLong#随机数种子
val rdd: RDD[Int] = sparkContext.makeRDD(List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10))
rdd.sample(true,0.4).collect().foreach(println(_))
distinct
对元素进行去重,去重原理:
去重的方式是通过将数值map成键值对的形式然后通过reducebykey聚合,最后选出聚合结果。
a->(a,1),通过reducebukey聚合
val rdd: RDD[Int] = sparkContext.makeRDD(List(1, 1, 2, 132, 456, 15, 489, 12, 12, 12, 12, 12, 12, 12))
rdd.distinct().sortBy(data=>data).collect().foreach(println(_))
coalesce
根据数据量缩减分区,用于大数据集过滤后,提高小数据集的执行效率,当 spark 程序中,存在过多的小任务的时候,可以通过coalesce 方法,收缩合并分区,减少分区的个数,减小任务调度成本。(该方法不会打乱数据,可能会导致数据倾斜。也可以设置成shuffle,也可以扩大分区,但是需要shuffle,扩大分区时等于repartition)
sortBy
排序
rdd2.sample(false, 0.4).collect().foreach(println)
println("555555555555555")
rdd2.sortBy(x=>x)
println(rdd2.collect().mkString(","))
println(rdd2.distinct().sortBy(x=>x).collect().mkString(","))
双值类型
val rdd1: RDD[Int] = sparkContext.makeRDD(List(1,2,3,4,9,8,7))
val rdd2: RDD[Int] = sparkContext.makeRDD(List(9,8,7,2,6,5,9))
//交集:intersection,元素类型要相同
println(rdd1.intersection(rdd2).collect().mkString(","))
//并集:union,元素类型要相同
println(rdd1.union(rdd2).collect().mkString(","))
//差集:subtract,区分谁作为主集合,元素类型要相同
println(rdd1.subtract(rdd2).collect().mkString(","))
println(rdd2.subtract(rdd1).collect().mkString(","))
//拉链:zip 将相同位置的数据放在一起,必须是元素数量相同,元素类型相同,分区数相同
println(rdd2.zip(rdd1).collect().mkString(","))
键值类型
partitionBy
/*
*根据指定的规则,对数据进行分区
*分区规则: 默认的为HASH,还有RANGE HashPartitioner
* */
val rdd: RDD[Int] = sparkContext.makeRDD(List(1, 2, 3, 4, 5, 6, 7, 8, 9), 2)
rdd.map((_,1)).partitionBy(new HashPartitioner(2)).collect()
reduceByKey
/*相同的key进行value的聚合
聚合方式是两两聚合,所以参数有两个,传入的方法是数字相加,字符串拼接等
*其中的key如果只有一个是不会进行运算的
*/
val rdd: RDD[(String, String)] = sparkContext.makeRDD(List(("chaichai", "hotpot"), ("chaichai", "paopao"), ("yeye", "lorin"), ("yeye", "rainbaby")))
rdd.reduceByKey((x,y)=>x+"&"+y).map(
data=>data._1+":"+data._2
).collect().foreach(println(_))
groupByKey
/*
* groupByKey将相同的Key放在同一个组中,形成元组
* 元组第一个值为key
* 第二个值为,相同key的value的集合
* */
val rdd: RDD[(String, String)] = sparkContext.makeRDD(List(("chaichai", "hotpot"), ("chaichai", "paopao"), ("yeye", "lorin"), ("yeye", "rainbaby")))
/*
* groupByKey和groupBy的区别
* 1、返回的RDD中groupBy的值原本的是键+值,
* groupByKey的值为原本的值,因为本身就是根据键分组的
* 2、groupByKey只能根据键分组,而groupBy可以自定义
* */
rdd.groupByKey().collect().foreach(println(_))
rdd.groupBy(_._1).collect().foreach(println(_))
/*
* groupByKey和reducByKey的区别
* 1、reducByKey有一个聚合的概念
* */
包含shuffle操作即打乱数据重新组合的时候,需要落盘(文件交互)
aggregateByKey &foldByKey
/*
* aggregateByKey,根据key去聚合,聚合的规则分两种,分区内计算规则和分区间计算规则
*包含两个参数 aggregateByKey()()
* 第一个参数是初始比较值,第一个参与凉凉计算的
* 第二个值是两个函数,第一个 是分区内计算函数,第二个是分区间计算函数
* */
val rdd: RDD[(String, Int)] = sparkContext.makeRDD(List(
("a", 2), ("a", 4), ("a", 6), ("a", 8)
), 2)
rdd.aggregateByKey(5)(
math.max(_,_),
_+_
).collect().foreach(println)
//简化版本foldByKey
rdd.foldByKey(0)(_+_).collect().foreach(println)
cogroup
groupByKey是对单个 RDD 的数据进行分组
cogroup() 是对多个共享同一个键的 RDD 进行分组 ,相当于先关联,再分组
join
将两个不同的数据源,数据类型为key-value。
将相同的key的value连接在一起形成元组
如果有多个相同的key会形成笛卡尔乘积,造成数据几何增长
leftOuterJoin
类似于sql中的 leftjoin
rightOuterJoin
类似于sql中的 rightjoin
val rdd1: RDD[(Int, String)] = sparkContext.makeRDD(List((4, "d"), (3, "c"), (2, "b"), (1, "a")))
val rdd2: RDD[(Int, String)] = sparkContext.makeRDD(List((4, "D"), (3, "C"), (2, "B"), (1, "A")))
val rdd3: RDD[(Int, String)] = sparkContext.makeRDD(List ((3, "C"), (2, "B"), (1, "A")))
rdd1.join(rdd2).collect().foreach(println(_))
println("########")
rdd1.join(rdd3).collect().foreach(println(_))
println("leftOuterJoin")
rdd1.leftOuterJoin(rdd3).collect().foreach(println)
println("########")
rdd1.leftOuterJoin(rdd3).collect().foreach(println)
RDD行动算子
行动算子:是触发RDD的计算,返回值不是RDD,一般是具体的值
reduce
聚集 RDD 中的所有元素,先聚合分区内数据,再聚合分区间数据
reduce算子是触发计算,返回值不再是RDD
val rdd = sparkContext.makeRDD(List(1, 2, 3, 4, 5, 6, 7, 8, 9))
val result = rdd.reduce(_ + _)
println(s"reduce的结果:${result}")
collect
在驱动程序中,以数组 Array 的形式返回数据集的所有元素
返回值可以用数组的方法
//collect在驱动程序中,以数组 Array 的形式返回数据集的所有元素
val resultCollect = rdd.collect()
println(s"collect的结果:${resultCollect.mkString}")
println(s"返回数组的最大值:${resultCollect.max}")
count
返回 RDD 中元素的个数
take
返回一个由 RDD 的前 n 个元素组成的数组
val arrayTake = rdd.take(5)
println(s"返回前5个元素为:${arrayTake.mkString(",")}")
takeOrdered
返回该 RDD 排序后的前 n 个元素组成的数组,相当于增加了排序,但是没有新增rdd
val takeOrderedArray = rdd.takeOrdered(3)
println(s"takeOrdered的获取的前三个元素为:${takeOrderedArray.mkString(",")}")
aggregate
分区的数据通过初始值和分区内的数据进行聚合,然后再和初始值进行分区间的数据聚合
val aggregateResult = rdd.aggregate(0)(_ + _, _ + _)
println(s"aggregate的结果:${aggregateResult}")
fold
简化版aggregate,只有一个函数表示的是分区内和分区间一致
countByKey
统计每种 key 的个数
val countByKeyResult = rdd.map(i => (i%2, i )).countByKey()
println(s"countByKey的结果:${countByKeyResult}")
countByKey的结果:Map(0 -> 5, 1 -> 5)
save 相关算子
将数据保存到不同格式的文件中
rdd.saveAsTextFile("output")
1、saveAsTextFile
保存成 Text 文件
def saveAsTextFile(path: String): Unit
rdd.saveAsTextFile("output")
2、saveAsObjectFile
序列化成对象保存到文件
def saveAsObjectFile(path: String): Unit
rdd.saveAsObjectFile("output1")
3、saveAsSequenceFile
保存成 Sequencefile 文件,要求数据格式必须是K-V类型
def saveAsSequenceFile(
path: String,
codec: Option[Class[_ <: CompressionCodec]] = None): Unit
rdd.map((_,1)).saveAsSequenceFile("output2")
foreach
分布式遍历 RDD 中的每一个元素,调用指定函数
行动算子总结
object actionRDD {
def main(args: Array[String]): Unit = {
val sparkConf = new SparkConf().setMaster("local[3]").setAppName("mapPartitionsWithIndex")
val sparkContext = new SparkContext(sparkConf)
val rdd = sparkContext.makeRDD(List(1, 2, 3, 4, 5, 6, 7, 8, 9,0))
val result = rdd.reduce(_ + _)
println(s"reduce的结果:${result}")
//collect在驱动程序中,以数组 Array 的形式返回数据集的所有元素
val resultCollect = rdd.collect()
println(s"collect的结果:${resultCollect.mkString}")
println(s"返回数组的最大值:${resultCollect.max}")
//count
val count = rdd.count()
println(s"count的结果是:${count}")
//take
val arrayTake = rdd.take(5)
println(s"take返回前5个元素为:${arrayTake.mkString(",")}")
//takeOrdered
val takeOrderedArray = rdd.takeOrdered(3)
println(s"takeOrdered的获取的前三个元素为:${takeOrderedArray.mkString(",")}")
val aggregateResult = rdd.aggregate(0)(_ + _, _ + _)
println(s"aggregate的结果:${aggregateResult}")
val countByKeyResult = rdd.map(i => (i%2, i )).countByKey()
println(s"countByKey的结果:${countByKeyResult}")
rdd.saveAsTextFile("output")
sparkContext.stop()
}
}