1.RDD是一个基本的抽象,操作RDD就像操作一个本地集合一样,降低了编程的复杂度
RDD里面并不存储真正要计算的数据,你对RDD进行操作,他会在Driver端转换成task,下发到Executor计算分散在多台集群上的数据
RDD的算子分为两类,一类是Transformation(lazy),一类是Action(触发任务执行)
RDD不存真正要计算的数据,而是记录了RDD的转换关系(调用了什么方法,传入什么函数)
* - A function for computing each split (每一个切片都会有一个函数作业在上面用于对数据进行处理)
* - A list of dependencies on other RDDs (RDD和RDD之间存在依赖关系)
* - Optionally, a Partitioner for key-value RDDs (e.g. to say that the RDD is hash-partitioned)
(可选,key value类型的RDD才有RDD[(K,V)])如果是kv类型的RDD,会一个分区器,默认是hash-partitioned
* - Optionally, a list of preferred locations to compute each split on (e.g. block locations for
* an HDFS file)
(可以,如果是从HDFS中读取数据,会得到数据的最优位置(向Namenode请求元数据))
创建RDD有哪些中方式呢?
1.通过外部的存储系统创建RDD(一般是从hdfs系统中读取文件,或者读取外部文件)
2.将Driver的Scala集合(Java中的集合不能)通过并行化的方式编程RDD(试验、测验)
3.调用一个已经存在了的RDD的Transformation,会生成一个新的RDD
RDD的Transformation的特点
1.lazy
2.生成新的RDD
spark中join操作,只能按照key来join,并且是等值join
RDD分区的数据取决于哪些因素?
1.如果是将Driver端的Scala集合并行化创建RDD,并且没有指定RDD的分区,RDD的分区就是为该app分配的中的核数cores(--total-executor-cores),可以充分利用计算资源,提高效率
2.如果是从hdfs中读取数据创建RDD,并且设置了最新分区数量是1,那么RDD的分区数据就是输入切片的数据,如果不设置最小分区的数量,即spark调用textFile时会默认传入2,那么RDD的分区数量会大于等于输入切片的数量
RDD的map方法,是Executor中执行时,是一条一条的将数据拿出来处理
mapPartitionsWithIndex 一次拿出一个分区(分区中并没有数据,而是记录要读取哪些数据,真正生成的Task会读取多条数据),并且可以将分区的编号取出来
功能:取分区中对应的数据时,还可以将分区的编号取出来,这样就可以知道数据是属于哪个分区的(哪个区分对应的Task的数据)
//该函数的功能是将对应分区中的数据取出来,并且带上分区编号
val func = (index: Int, it: Iterator[Int]) => {
it.map(e => s"part: $index, ele: $e")
}
aggregateByKey 是Transformation
reduceByKey 是Transformation
filter 是Transformation
flatMap 是Transformation
map 是ransformation
mapPartition 是ransformation
mapPartitionWithIndex 是ransformation
collect 是Action
aggregate 是Action
saveAsTextFile 是Action
foreach 是Action
foreachPartition 是Action