大数据技术之SparkCore(一)
一:RDD概述
-
RDD定义:
RDD(Resilient Distributed Dataset)叫做弹性分布式数据集。是Spark中最基本的数据抽象。代码中是一个抽象类,代表一个不可变、可分区、其中的元素可并行计算的集合。
-
RDD的属性
- partition:一组分区(partition),即数据集的基本组成单位。
- Function:每个分区的函数
- dependencies:RDD之间的依赖关系
- Partitioner:即RDD的分片函数
- List:一个列表、存储存取每个Partition的优先位置
-
特点
RDD表示只读的分区的数据集,对RDD进行改动,只能通过RDD的转换操作,由一个RDD转换为一个新的RDD。新的RDD包含了其他RDD衍生所必须的额信息。RDDs之间存在历来,RDD的执行是按照血缘关系进行延迟计算的。如果血缘关系较长,可以通过持久化RDD来切断血缘关系。
-
二:RDD编程
-
编程模型
在 Spark 中, RDD 被表示为对象,通过对象上的方法调用来对 RDD 进行转换。经过一系列的 transformations 定义 RDD 之后,就可以调用 actions 触发 RDD 的计算, action 可以是向应用程序返回结果(count, collect 等),或者是向存储系统保存数据(saveAsTextFile 等)。在Spark 中,只有遇到 action,才会执行 RDD 的计算(即延迟计算),这样在运行时可以通过管道的方式传输多个转换。
-
RDD的创建:(集合中创建、外部存储中创建、其他RDD转换)
-
集合中创建:(parallelize和makeRDD)
val rdd = sc.parallelize(Array(1,2,3,4,5)) val rdd = sc.makeRDD(Array(1,2,3,4,5))
-
外部存储系统的数据集进行创建RDD
包括本地的文件系统,还有所有 Hadoop 支持的数据集,比如 HDFS、 Cassandra、 HBase 等, val rdd2= sc.textFile("hdfs://hadoop102:9000/RELEASE"
-
RDD转换(下章单独解析)
-
三:RDD转换(面试开发重点)
-
Value类型
- map(func)案例
作用: 返回一个新的 RDD,该 RDD 由每一个输入元素经过 func 函数转换后组成 创建一个 1-10 数组的 RDD,将所有元素*2 形成新的 RDD var source = sc.parallelize(1 to 10) source.collect() val mapadd = source.map(_*2) mapadd.collect()
- mapPartition(func)案例
类似于 map,但独立地在 RDD 的每一个分片上运行,因此在类型为 T 的 RDD 上 运行时, func 的函数类型必须是 Iterator[T] => Iterator[U]。 假设有 N 个元素, 有 M 个分区,那么 map 的函数的将被调用 N 次,而 mapPartitions 被调用 M 次,一个函数一次处理分区内所有。 创建一个 RDD,使每个元素*2 组成新的 RDD val rdd = sc.parallelize(Array(1,2,3,4)) rdd.mapPartitions(x=>map(_*2)).collect
- mapPartitionsWithIndex(func)案例
类似于 mapPartitions,但 func 带有一个整数参数表示分片的索引值,因此在类型 为 T 的 RDD 上运行时, func 的函数类型必须是(Int, Interator[T]) => Iterator[U]; 需求:创建一个 RDD,使每个元素跟所在分区形成一个元组组成一个新的 RDD val rdd = sc.parallelize(Array(1,2,3,4)) val indexRdd = rdd,mapPartitionsWithIndex((index,items)=>(items.map((index,_)))) indexRdd.collect
- flatMap(func)案例
作用:蕾仕于map,但是每一个输出元素可以被映射为0或者多个输出元素(所以func应该返回一个序列,而不是一个单一元素) 需求:创建一个元素为1-5的RDD,使用flatMap创建一个新的RDD,新的RDD为原来RDD的每个元素的2倍 val sourceFlat = sc.parallelize(1 to 5) sourceFlat.collect() val flatMapRdd = sourceFlat.flatMap(1 to _).collect() 结果:res12: Array[Int] = Array(1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 2, 3, 4, 5)
- map()和mapPartitions的区别
- map(): 每次处理一条数据。
- mapPartition(): 每次处理一个分区的数据,这个分区的数据处理完后,原 RDD 中分区的
数据才能释放,可能导致 OOM。 - 开发指导:当内存空间较大的时候建议使用 mapPartition(),以提高处理效率。
- glom案例
作用: 将每一个分区形成一个数组,形成新的 RDD 类型是 RDD[Array[T]] 需求:创建一个 4 个分区的 RDD,并将每个分区的数据放到一个数组 val rdd = sc.parallelize(1 to 16,4) rdd.glom().collect() 结果:res25: Array[Array[Int]] = Array(Array(1, 2, 3, 4), Array(5, 6, 7, 8), Array(9, 10, 11, 12),Array(13, 14, 15, 16))
- groupBy(func)案例
作用: 分组,按照传入函数的返回值进行分组。 将相同的 key 对应的值放入一个迭代器。 需求:创建一个 RDD,按照元素模以 2 的值进行分组。 val rdd = sc.parallzlize(1 to 4) val group = rdd.groupBy(_%2).collect() res0: Array[(Int, Iterable[Int])] = Array((0,CompactBuffer(2, 4)), (1,CompactBuffer(1, 3)))
- filter(func)案例
作用: 过滤。 返回一个新的 RDD,该 RDD 由经过 func 函数计算后返回值为 true 的输入 元素组成。 需求:创建一个 RDD(由字符串组成),过滤出一个新 RDD(包含”xiao”子串) var sourceFilter =sc.parallelize(Array("xiaoli",“xiaotian”,"zhangli")) sourceFilter.filter(_.contains("xiao")).collect() 结果:res10: Array[String] = Array(xiaoli, xiaotian)
- sample(withReplacement,function,seed)案例
作用: 以指定的随机种子随机抽样出数量为 fraction 的数据, withReplacement 表示是抽 出的数据是否放回, true 为有放回的抽样, false 为无放回的抽样, seed 用于指定随机数生成 器种子。 需求:创建一个 RDD(1-10),从中选择放回和不放回抽样 val rdd = sc.parallelize(1 to 10) //放回抽样 var sample1 = rdd.sample(true,0.4,2).collect() //不放回抽样 var sample2 = rdd.sample(false,0.2,3)。collect()
- distinct([numTasks])案例
作用: 对源 RDD 进行去重后返回一个新的 RDD。 默认情况下,只有 8 个并行任务来操 作,但是可以传入一个可选的 numTasks (并行度)参数改变它。 val distinctRdd = sc.parallelize(List(1,2,1,5,2,9,6,1)) val unionRDD = distinctRdd.distinct()。collect()
- coalesce(numPartitions)案例
作用: 缩减分区数,用于大数据集过滤后,提高小数据集的执行效率。 需求:创建一个 4 个分区的 RDD,对其缩减分区 val rdd = sc.parallelize(1 to 16,4) rdd.partitions.size val coalesceRDD = rdd.coalesce(3) rdd.partitions.size
-
repartition(numPartitions)案例(与上一个作用类似)
区别:
- coalesce 重新分区,可以选择是否进行 shuffle 过程。由参数 shuffle: Boolean = false/true 决
定。 - repartition 实际上是调用的 coalesce,默认是进行 shuffle 的。
- coalesce 重新分区,可以选择是否进行 shuffle 过程。由参数 shuffle: Boolean = false/true 决
-
sortBy(func,[ascending],[numTasks])案例
1. 作用;使用 func 先对数据进行处理,按照处理后的数据比较结果排序,默认为正序。 2. 需求:创建一个 RDD,按照不同的规则进行排序 val rdd = sc.parallelize(List(2,1,3,4,5)) 按照自身大小排序 rdd.sortBy(x=>x).collect() 按照与 3 余数的大小排序 rdd.sortBy(x=>x%3).collect()
- pipe(command,[envVars])案例
1. 作用:管道,针对每个分区,都执行一个 shell 脚本,返回输出的 RDD。 注意:脚本需要放在 Worker 节点可以访问到的位置