章节目录
Spark RDD概念
- 1、简单的解释
RDD是将数据项拆分为多个分区的集合,存储在集群的工作节点上的内存中,并执行正确的操作 - 2、复杂的解释
RDD是用于数据转换的接口
RDD指向了存储在HDFS、Cassandra、HBase等、或缓存(内存、内存+磁盘、仅磁盘等),或在故障或缓存收回时重新计算其他RDD分区中的数据 - 3、RDD是弹性分布式数据集(Resilient Distributed Datasets)
a)分布式数据集
RDD是只读的、分区记录的集合,每个分区分布在集群的不同节点上
RDD并不存储真正的数据,只是对数据和操作的描述
b)弹性
RDD默认存放在内存中,当内存不足,Spark自动将RDD写入磁盘
c)容错性
根据数据血统,可以自动从节点失败中恢复分区
RDD与DAG对比
1、两者是Spark提供的核心抽象
2、DAG(有向无环图)反映了RDD之间的依赖关系

RDD的特性
1、一系列的分区(分片)信息,每个任务处理一个分区
2、每个分区上都有compute函数,计算该分区中的数据
3、RDD之间有一系列的依赖
4、分区函数决定数据(key-value)分配至哪个分区
5、最佳位置列表,将计算任务分派到其所在处理数据块的存储位置
RDD编程流程

RDD的创建
一、使用内存集合创建RDD

注意:
1、Spark默认会根据集群的情况来设置分区的数量,也可以通过parallelize()第二参数来指定
2、Spark会为每一个分区运行一个任务进行处理
二、通过加载文件产生RDD
1、加载本地文件

注意:加载“file://……”时,以local运行仅需一份本地文件,以Spark集群方式运行,应保证每个节点均有该文件的本地副本
2、加载HDFS文件

注:支持目录、压缩文件以及通配符


三、其他创建RDD的方法
-
1、SparkContext.wholeTextFiles():可以针对一个目录中的大量小文件返回<filename,fileContent>作为PairRDD
a)普通RDD:org.apache.spark.rdd.RDD[data_type]
b)PairRDD:org.apache.spark.rdd.RDD[(key_type,value_type)]
注意:Spark 为包含键值对类型的 RDD 提供了一些专有的操作,比如:reduceByKey()、groupByKey()……也可以通过键值对集合创建PairRDD: sc.parallelize(List((1,2),(1,3)) -
2、SparkContext.sequenceFileK,V
Hadoop SequenceFile的读写支持 -
3、SparkContext.hadoopRDD()、newAPIHadoopRDD()
从Hadoop接口API创建 -
4、SparkContext.objectFile()
RDD.saveAsObjectFile()的逆操作
RDD创建方式的最佳实战
- 1、测试环境
使用内存集合创建RDD
使用本地文件创建RDD - 2、生产环境
使用HDFS文件创建RDD
RDD分区
分区是RDD被拆分并发送到节点的不同块之一
- 我们拥有的分区越多,得到的并行性就越强
- 每个分区都是被分发到不同Worker Node的候选者
- 每个分区对应一个Task

RDD的操作
分为lazy与non-lazy两种
- 1、Transformation(lazy):也称转换操作、转换算子
- 2、Actions(non-lazy):立即执行,也称动作操作、动作算子
RDD转换算子
对于转换操作,RDD的所有转换都不会直接计算结果
- 1、仅记录作用于RDD上的操作
- 2、当遇到动作算子(Action)时才会进行真正计算
RDD常用的转换算子
map
1、对RDD中的每个元素都执行一个指定的函数来产生一个新的RDD
2、任何原RDD中的元素在新的RDD中都有且只有一个元素与之对应
3、输入分区与输出分区一一对应
def main(args: Array[String]): Unit = {
val conf: SparkConf = new SparkConf().setMaster("local[2]").setAppName("mapdemo")
val sc: SparkContext = SparkContext.getOrCreate(conf)
val rdd1: RDD[Int] = sc.makeRDD(1 to 9,3)
val rdd2: RDD[Int] = rdd1.map(_*2)
rdd2.collect.foreach(println)
println("-------------------------------------")
val strRdd1 = sc.parallelize(List("kb02","kb05","kb07","kb09","spark","study"),2)
val strRdd2: RDD[(String,Int)] = strRdd1.map(x=>(x,1))
strRdd2.collect.foreach(println)
}

filter
对元素进行过滤,对每个元素应用指定函数,返回值为true的元素保留在新的RDD中
val conf: SparkConf = new SparkConf().setMaster("local[2]").setAppName("mapdemo")
val sc: SparkContext = SparkContext.getOrCreate(conf)
val filterRdd1 = sc.makeRDD(List(1,2,3,4,5,6,7,8,9,10),3)
val filterRdd2 = filterRdd1.filter(_%2==0)
filterRdd2.collect.foreach(println)

mapValues
原RDD中的Key保持不变,与新的Value一起组成新的RDD中的元素,仅适用于PairRDD
val conf: SparkConf = new SparkConf().setMaster("local[2]").setAppName("mapdemo")
val sc: SparkContext = SparkContext.getOrCreate(conf)
val mapValuesRdd1 = sc.parallelize(List("dog","tiger","cat","lion","eagle","panther"))
val mapValuesRdd2 = mapValuesRdd1.map(x=>(x.length,x))
// mapValuesRdd2.collect.foreach(println)
val mapValuesRdd3 = mapValuesRdd2.mapValues(x=>"_"+x+"_")
mapValuesRdd3.collect.foreach(println)

reduceByKey
println("---------------reduceByKey算子---------------")
val reduceByKeyRdd1 = mapValuesRdd2.reduceByKey((a,b)=>a+" "+b)
reduceByKeyRdd1.collect.foreach(println)

groupByKey
println("---------------groupByKey算子---------------")
val groupByKeyRdd = mapValuesRdd2.groupByKey()
groupByKeyRdd.collect.foreach(println)

sortByKey
println("---------------sortByKey算子---------------")
val sortByKeyRdd = mapValuesRdd2.sortByKey()
sortByKeyRdd.collect.foreach(println)

distinct
val conf = new SparkConf().setMaster("local[3]").setAppName("rdddemo")
val sc = SparkContext.getOrCreate(conf)
println("-----------distinct算子---------------")
val rdd1 = sc.parallelize(List(1,2,3,4,5,6,7,8,9,9,2,6))
val rdd2 = rdd1.distinct
println("rdd1的分区数:"+rdd1.partitions.length)
println("rdd2的分区数:"+rdd2.partitions.length)
rdd2.collect.foreach(println)
val rdd3 = rdd1.distinct(2)
println("rdd3的分区数:"+rdd3.partitions.length)

union
println("-----------union算子(并集)---------------")
val u1 = sc.parallelize(1 to 3)
val u2 = sc.parallelize(3 to 4)
val unionRdd = u1.union(u2)
unionRdd.collect.foreach(println)
println("------------- ++形式 ----------------")
//++形式
val u3 = u1 ++ u2
u3.collect.foreach(println)

intersection
println("-----------intersection算子(交集)---------------")
val list1 = sc.parallelize(List(1,2,3,4,5,6))
val list2 = sc.parallelize(List(4,5,6,7,8,9))
val intersectionRdd = list1.intersection(list2)
intersectionRdd.collect.foreach(println)

join
println("---------------join算子-----------------")
val j1 = sc.parallelize(List("abc","abby","apple")).map(a=>(a,1))
val j2 = sc.parallelize(List("aplle","beatty","beatrice")).map(a=>(a,1))
val joinRdd = j1.join(j2)
joinRdd.collect.foreach(println)
println("---------------leftOutJoin------------")
val leftOutJoinRdd = j1.leftOuterJoin(j2)
leftOutJoinRdd.collect.foreach(println)
println("---------------rightOutJoin------------")
val rightOutJoinRdd = j1.rightOuterJoin(j2)
rightOutJoinRdd.collect.foreach(println)

RDD动作算子
本质上动作算子通过SparkContext执行提交作业操作,触发RDD DAG(有向无环图)的执行
所有的动作算子都是急迫型(non-lazy),RDD遇到Action就会立即计算
RDD常用动作算子
count
返回的是数据集中的元素的个数
println("------------count算子-----------------")
val rdd1 = sc.parallelize(List(1,2,3,4,5,6))
val countRdd = rdd1.count
println("集合元素个数:"+countRdd)

collect
以Array返回RDD的所有元素。一般在过滤或者处理足够小的结果的时候使用
注意:前面所有转换操作都结合了collect动作算子进行计算输出
println("------------collect算子-------------")
val rdd1 = sc.parallelize(List(1,2,3,4,5,6))
val collectRdd = rdd1.collect
collectRdd.foreach(println)

take
返回前n个元素
println("------------take算子-------------")
val rdd1 = sc.parallelize(List(1,2,3,4,5,6))
val takeRdd = rdd1.take(3)
takeRdd.foreach(println)

first
返回RDD第一个元素
println("------------first算子-------------")
val rdd1 = sc.parallelize(List(1,2,3,4,5,6))
println(rdd1.first)

reduce
根据指定函数,对RDD中的元素进行两两计算,返回计算结果
val conf = new SparkConf().setMaster("local[2]").setAppName("actionrdddemo")
val sc = SparkContext.getOrCreate(conf)
println("-----------reduce算子--------------")
val rdd1 = sc.parallelize(1 to 100)
val sum = rdd1.reduce((x,y)=>{println(x,y);x+y})
//等同于:
// val sum1 = rdd1.reduce(_+_)
println("总和:"+sum)

foreach
对RDD中的每个元素都使用指定函数,无返回值
lookup
用于PairRDD,返回K对应的所有V值
println("------------lookup算子-------------")
val rdd1 = sc.parallelize(List(('a',1),('a',2),('b',3),('c',4)))
val lookupRdd = rdd1.lookup('a')
lookupRdd.foreach(println)

最值
返回最大值(max)、最小值(min)
println("------------最值-------------")
val rdd1 = sc.parallelize(10 to 30)
println("最大值:"+rdd1.max)
println("最小值"+rdd1.min)

saveAsTextFile
保存RDD数据至文件系统
println("-----------saveAsTextFile算子--------------")
//保存RDD数据至本地文件系统
rdd1.saveAsTextFile("in/rdd1.txt")
//保存RDD数据至HDFS文件系统
rdd1.saveAsTextFile("hdfs://hadoop001:9000/data/spark/rdd1.txt")

需要赋权:hdfs dfs -chmod -R 777 /data/spark/

本文深入探讨了Spark的RDD(弹性分布式数据集)概念,包括其分布式、弹性和容错性的特性。介绍了RDD的创建方法,如内存集合、文件加载和其他高级方式。详细讲解了RDD的编程流程,转换算子如map、filter和reduceByKey,以及动作算子如count、collect和saveAsTextFile。此外,还讨论了RDD分区和操作的执行过程。
3406

被折叠的 条评论
为什么被折叠?



