sc.parallelize(list)
sc.makeRDD(list)
sc.makeRDD(list, 2)
val list: List[Int] = List(1, 2, 3, 4, 5)
// 从List中创建RDD
val rdd01: RDD[Int] = sc.parallelize(list)
// 底层调用parallelize。从结合list中获取数据
val rdd02: RDD[Int] = sc.makeRDD(list)
// 2:分区数量为2
val rdd03: RDD[Int] = sc.makeRDD(list, 2)
// 从文件中获取
sc.textFile("input/1.txt")
// 无论文件中存储的是什么数据,读取过来都当字符串进行处理
val rdd04: RDD[String] = sc.textFile("input/1.txt")
在其它执行步骤完成后,生成新的RDD对象
val rdd05: RDD[String] = rdd04.map(_ * 2)
从集合中创建
从文件中创建
// 1、创建SparkConf并设置App名称
val conf = new SparkConf().setAppName("SparkCore").setMaster("local[*]")
// 2、创建SparkContext,该对象时提交Spark APP 的入口
val sc = new SparkContext(conf)
// 3、创建RDD
val rdd: RDD[Int] = sc.makeRDD(List(1, 2, 3, 4))
// 4、具体执行步骤
val rdd01: RDD[Int] = rdd.map(x => x * 20)
// 5、打印结果
println(rdd01.collect().toList)
// 6、关闭连接
sc.stop()
// 4、具体执行步骤
val rdd01: RDD[Int] = rdd.map(x => x * 20)
// 4、具体执行步骤
val rdd02: RDD[Int] = rdd01.map(_ * 20)
以分区为单位执行的map()
/**
*
* @param f 分区编号
* @param preservesPartitioning 分区数据迭代器
*/
def mapPartitionsWithIndex[U: ClassTag](
f: (Int, Iterator[T]) => Iterator[U],
preservesPartitioning: Boolean = false): RDD[U] = withScope {
}
rdd03.mapPartitionsWithIndex((index, items) => {
items.map((index, _))
})
// 指定迭代器规则,并使用分区数据迭代器
rdd03.mapPartitionsWithIndex((index, items) => {
items.map((index, _))
}, preservesPartitioning = true)
扁平化(合并流)
功能说明
def flatMap[U: ClassTag](f: T => TraversableOnce[U]): RDD[U] = withScope {
}
val rdd08: RDD[List[Int]] = sc.makeRDD(List(List(1, 2), List(3, 4), List(5, 6)), 2)
val rdd09: RDD[Int] = rdd08.flatMap(list => list)
// List(1, 2, 3, 4, 5, 6)
println(rdd09.collect().toList)
分组
按照传入函数的返回值进行分组。将相同的key对应的值放入一个迭代器。
def groupBy[K](f: T => K)(implicit kt: ClassTag[K]): RDD[(K, Iterable[T])] = withScope {
groupBy[K](f, defaultPartitioner(this))
}
案例
// 3.2 将每个分区的数据放到一个数组并收集到Driver端打印
rdd.groupBy((x)=>{x%2})
// 简化
rdd.groupBy(_%2)
val rdd10: RDD[Int] = sc.makeRDD(List(1, 2, 3, 4, 5, 6, 7, 8, 9), 3)
// (0,CompactBuffer(2, 4, 6, 8))
// (1,CompactBuffer(1, 3, 5, 7, 9))
rdd10.groupBy(_ % 2).collect().foreach(println)
val rdd11: RDD[Int] = sc.makeRDD(List(1, 2, 3, 4, 5), 3)
// 按照数字相同进行分区
// (3,CompactBuffer(3))
// (4,CompactBuffer(4))
// (1,CompactBuffer(1))
// (5,CompactBuffer(5))
// (2,CompactBuffer(2))
rdd11.groupBy(a => a).collect().foreach(println)
过滤
接收一个返回值为布尔类型的函数作为参数。当某个RDD调用filter方法时,会对该RDD中每一个元素应用f函数,如果返回值类型为true,则该元素会被添加到新的RDD中。
rdd11.filter(a => a % 2 == 0)
rdd11.filter(_% 2 == 0)
val rdd11: RDD[Int] = sc.makeRDD(List(1, 2, 3, 4, 5, 6, 7, 8, 9), 3)
val rdd110: RDD[Int] = rdd11.filter(a => a % 2 == 0)
// List(2, 4, 6, 8)
println(rdd110.collect().toList)
去重
// 去重
rdd.distinct()
// 去重(2并发度)
rdd.distinct(2)
val rdd12: RDD[Int] = sc.makeRDD(List(1, 2, 3, 4, 2, 3), 3)
// List(3, 4, 1, 2)
println(rdd12.distinct().collect().toList)
// List(4, 2, 1, 3)(采用多个Task提高并发读)
println(rdd12.distinct(2).collect().toList)
合并分区
rdd13.coalesce(2)
rdd14.coalesce(2, shuffle = true)
缩减分区并执行Shuffer
val rdd14: RDD[Int] = sc.makeRDD(List(1, 2, 3, 4, 5, 6, 7, 8, 9), 3)
// 缩减分区为2个
val rdd131: RDD[Int] = rdd13.coalesce(2)
// 缩减分区为2个,并执行Shuffer
val rdd141: RDD[Int] = rdd14.coalesce(2, shuffle = true)
重新分区
rdd.repartition(2)
val rdd15: RDD[Int] = sc.makeRDD(List(1, 2, 3, 4, 5, 6, 7, 8, 9), 3)
// 重新分区
val rdd151: RDD[Int] = rdd15.repartition(2)
排序
// 正序
rdd.sortBy(num => num)
// 倒叙
rdd.sortBy(num => num, ascending = false)
案例:
val rdd16: RDD[Int] = sc.makeRDD(List(1, 2, 3, 4, 5, 6, 7, 8, 9), 3)
// 重新排序,默认升序
val rdd161: RDD[Int] = rdd16.sortBy(num => num)
// 重新排序,配置降序
val rdd162: RDD[Int] = rdd16.sortBy(num => num, ascending = false)
val rdd17: RDD[(Int, Int)] = sc.makeRDD(List((1, 2), (3, 4), (5, 6)))
// 先按照第1个值升序,在按第2个值排序
val rdd171: RDD[(Int, Int)] = rdd17.sortBy(num => num)
map与mapPartitions的区别
val rdd02: RDD[Int] = rdd01.mapPartitions(a => a.map(b => b * 2))
val rdd03: RDD[Int] = rdd02.mapPartitions(a => a.map(_ * 2))
def repartition(numPartitions: Int)(implicit ord: Ordering[T] = null): RDD[T] = withScope {
coalesce(numPartitions, shuffle = true)
}
并集不去重
println(rdd01.intersection(rdd02)
val rdd01: RDD[Int] = sc.makeRDD(1 to 4)
val rdd02: RDD[Int] = sc.makeRDD(4 to 8)
// 取交集
// 利用shuffle的原理进行求交集 需要将所有的数据落盘shuffle 效率很低 不推荐使用
println(rdd01.intersection(rdd02).collect().toList)
并集不去重
rdd1.union(rdd2)
val rdd01: RDD[Int] = sc.makeRDD(1 to 4)
val rdd02: RDD[Int] = sc.makeRDD(4 to 8)
// 由于不走shuffle 效率高 所有会使用到
rdd1.union(rdd2).collect().foreach(println)
差集
// 计算第一个RDD与第二个RDD的差集并打印
rdd01.subtract(rdd02)
val rdd01: RDD[Int] = sc.makeRDD(1 to 4)
val rdd02: RDD[Int] = sc.makeRDD(4 to 8)
// 同样使用shuffle的原理 将两个RDD的数据写入到相同的位置 进行求差集
// 需要走shuffle 效率低 不推荐使用
// 在rdd01的数据中,与rdd02相差的数据(1,2,3)
rdd01.subtract(rdd02).collect().foreach(println)
拉链
val rdd01: RDD[Int] = sc.makeRDD(Array(1, 2, 3), 3)
val rdd02: RDD[String] = sc.makeRDD(Array("a", "b", "c"), 3)
// List((1,a), (2,b), (3,c))
println(rdd01.zip(rdd02).collect().toList)
// List((a,1), (b,2), (c,3))
println(rdd02.zip(rdd01).collect().toList)
反例:
val rdd02: RDD[String] = sc.makeRDD(Array("a", "b", "c"), 3)
val rdd03: RDD[String] = sc.makeRDD(Array("a", "b"), 3)
// 元素个数不同,不能拉链
// SparkException: Can only zip RDDs with same number of elements in each partition
println(rdd03.zip(rdd02).collect().toList)
val rdd04: RDD[String] = sc.makeRDD(Array("a", "b", "c"), 2)
// 分区数不同,不能拉链
// java.lang.IllegalArgumentException: Can't zip RDDs with unequal numbers of partitions: List(2, 3)
println(rdd04.zip(rdd02).collect().toList)
按照K重新分区
// 使用hash计算方式重分区,并重分区后分区数量 = 2
rdd01.partitionBy(new HashPartitioner(2))
val rdd01: RDD[(Int, String)] = sc.makeRDD(Array((111, "aaa"), (222, "bbbb"), (333, "ccccc")), 3)
val rdd02: RDD[(Int, String)] = rdd01.partitionBy(new HashPartitioner(2))
// 打印重分区后的分区数量
// (0,(2,bbbb))
// (1,(1,aaa))
// (1,(3,ccccc))
val rdd03: RDD[(Int, (Int, String))] = rdd02.mapPartitionsWithIndex((index, datas) => {
datas.map((index, _))
})
rdd03.collect().foreach(println)
按照K重新分组
rdd001.groupByKey()
val rdd001: RDD[(String, Int)] = sc.makeRDD(List(("a", 1), ("b", 5), ("a", 5), ("b", 2)
val rdd002: RDD[(String, Iterable[Int])] = rdd001.groupByKey()
// (a,CompactBuffer(1, 5))
// (b,CompactBuffer(5, 2))
rdd002.collect().foreach(println)
按照K聚合V
rdd01.reduceByKey((v1, v2) => (v1 + v2))
val rdd01: RDD[(String, Int)] = sc.makeRDD(List(("a", 1), ("b", 5), ("a", 5), ("b", 2)))
val rdd02: RDD[(String, Int)] = rdd01.reduceByKey((v1, v2) => (v1 + v2))
// List((a,6), (b,7))
println(rdd02.collect().toList)
分区内和分区间逻辑不同的归约
// zeroValue(初始值):给每一个分区中的每一种key一个初始值;
// seqOp(分区内):函数用于在每一个分区中用初始值逐步迭代value;
// combOp(分区间):函数用于合并每个分区中的结果。
def aggregateByKey[U: ClassTag](zeroValue: U, partitioner: Partitioner)(seqOp: (U, V) => U,
combOp: (U, U) => U): RDD[(K, U)] = self.withScope {
}
// 分区初始值=0,分区内取最大值,分区间求和
rdd01.aggregateByKey(0)(math.max(_, _), _ + _)
val rdd01: RDD[(String, Int)] = sc.makeRDD(List(("a", 1), ("b", 5), ("a", 5), ("b", 2)))
// 取出每个分区相同key对应值的最大值,然后相加
val rdd02: RDD[(String, Int)] = rdd01.aggregateByKey(0)(math.max(_, _), _ + _)
// List((a,6), (b,7))
println(rdd02.collect().toList)
按照K进行排序
// 按照key的正序(默认正序)
rdd01.sortByKey(ascending = true)
// 按照key的倒序排列
rdd01.sortByKey(ascending = false)
val rdd01: RDD[(Int, String)] = sc.makeRDD(Array((3, "aa"), (6, "cc"), (2, "bb"), 1, "dd"))
// 按照key的正序(默认正序)
println(rdd01.sortByKey(ascending = true).collect().toList)
// 按照key的倒序排列
println(rdd01.sortByKey(ascending = false).collect().toList)
只对V进行操作
rdd01.mapValues(_ + "|||")
val rdd01: RDD[(Int, String)] = sc.makeRDD(Array((1, "a"), (1, "d"), (2, "b"), (3, "c")))
// 对Value值添加字符串|||
// List((1,a|||), (1,d|||), (2,b|||), (3,c|||))
println(rdd01.mapValues(_ + "|||").collect().toList)
join() 等同于sql里的内连接,关联上的要,关联不上的舍弃
// 按key进行 内联join
rdd01.join(rdd02)
val rdd01: RDD[(Int, String)] = sc.makeRDD(Array((1, "a"), (2, "b"), (3, "c")))
val rdd02: RDD[(Int, Int)] = sc.makeRDD(Array((1, 4), (2, 5), (4, 6)))
// 按key进行 内联join
// List((1,(a,4)), (2,(b,5)))
println(rdd01.join(rdd02).collect().toList)
cogroup() 类似于sql的全连接,但是在同一个RDD中对key聚合
// cogroup 合并两个RDD,取并集
rdd01.cogroup(rdd02)
val rdd01: RDD[(Int, String)] = sc.makeRDD(Array((1, "a"), (2, "b"), (3, "c")))
val rdd02: RDD[(Int, Int)] = sc.makeRDD(Array((1, 4), (2, 5), (4, 6)))
// cogroup 两个RDD并打印
// List((1,(CompactBuffer(a),CompactBuffer(4))), (2,(CompactBuffer(b),CompactBuffer(5)))
// (3,(CompactBuffer(c),CompactBuffer())), (4,(CompactBuffer(),CompactBuffer(6))))
println(rdd01.cogroup(rdd02).collect().toList)
cogroup后结果处理
val rdd01: RDD[(Int, Int)] = sc.makeRDD(Array((1, 4), (2, 1), (3, 5)))
val rdd02: RDD[(Int, Int)] = sc.makeRDD(Array((1, 4), (2, 5), (4, 6)))
// cogroup后类型为Iterable,key调用其sum进行值求和(相同的key)
val value1: RDD[(Int, (Iterable[Int], Iterable[Int]))] = rdd01.cogroup(rdd02)
val value: RDD[(Int, (Int, Int))] = value1.mapValues(a => {
(a._1.sum, a._2.sum)
})
要实现自定义分区器,需要继承org.apache.spark.Partitioner类,并实现下面三个方法。
val rdd01: RDD[(Int, String)] = sc.makeRDD(Array((1, "a"), (2, "b"), (3, "c")))
val rdd02: RDD[(Int, String)] = rdd01.partitionBy(new MyParTition(2))
println(rdd02.collect().toList)
class MyParTition(num: Int) extends Partitioner {
// 设置分区数
override def numPartitions: Int = num
// 具体分区逻辑
override def getPartition(key: Any): Int = {
// 采用模式匹配。依据不同的类型,采用不同的处理逻辑
// 字符串:放入0号分区。整数:取模分区个数
key match {
case s: String => 0
case i: Int => i % numPartitions
case _ => 0
}
}
}
行动算子是触发了整个作业的执行。因为转换算子都是懒加载,并不会立即执行。
以数组的形式返回数据集
rdd02.collect().toList
返回RDD中元素个数
println(rdd01.count())
返回RDD中的第一个元素
println(rdd01.first())
返回由RDD前n个元素组成的数组
// 返回由前3个元素组成的数组
rdd01.take(3)
val number: Array[(Int, String)] = rdd01.take(3)
返回该RDD排序后前n个元素组成的数组
// returns Array(2)
sc.parallelize(Seq(10, 4, 2, 12, 3)).takeOrdered(1)
// returns Array(2, 3)
sc.parallelize(Seq(2, 3, 4, 5, 6)).takeOrdered(2)
// List(1, 2)
val rdd02: Array[Int] = sc.makeRDD(List(1, 3, 2, 4)).takeOrdered(2)
println(rdd02.toList)
统计每种key的个数
rdd01.countByKey()
val rdd01: RDD[(Int, String)] = sc.makeRDD(List((1, "a"), (1, "a"), (1, "a"), (2, "b"), (3, "c"), (3, "c")))
val rdd02: collection.Map[Int, Long] = rdd01.countByKey()
// Map(1 -> 3, 2 -> 1, 3 -> 2)
println(rdd02)
保存成Text文件
val rdd: RDD[Int] = sc.makeRDD(List(1, 2, 3, 4), 2)
// 保存到本地Text文件
rdd.saveAsTextFile("output01")
保存成Sequencefile文件
val rdd: RDD[Int] = sc.makeRDD(List(1, 2, 3, 4), 2)
// 保存成Sequencefile文件
rdd.saveAsObjectFile("output02")
序列化成对象保存到文件
val rdd: RDD[Int] = sc.makeRDD(List(1, 2, 3, 4), 2)
// 序列化成对象保存到文件
rdd.map((_, 1)).saveAsObjectFile("output03")
遍历RDD中每一个元素
// 收集后打印
rdd.collect().foreach(println)
// 分布式打印
rdd.foreach(println)