1.RDD类由SparkContext进行创建。
2.我们总是说RDD是lazy的,并不是说RDD类中定义了lazy的方法,RDD对应的数据是存在BlockStore的子类中的,说RDD是lazy的,意思是RDD在调用BlockStore,使用数据的时候,BlockStore中,初始化数据块的操作是lazy的.
RDD基本转换操作(Transformation):
map[U:ClassTag](f:T=>U):RDD[U] | map函数将RDD中类型为T的元素,一对一的转化成类型为U的元素。 |
distinct():RDD[T] | distinct函数返回RDD中所有不一样的元素 |
flatMap[U:ClassTag](f:T=>TraversableOnce[U]):RDD[U] | flatMap函数则是将RDD中的每一个元素进行一对多的转换。 |
repartition(numPartition:Int):RDD[T] coalesce(numPartition:Int,shuffle:Boolean=false):RDD[T] | 对RDD进行重新分区 |
randomSplit(weight:Array[Double],seed:Long=System.nanoTime):Array[RDD[T]] | 根据weight权重将一个RDD切分成多个RDD |
glom() | 将RDD中每一个分区中类型为T的元素转换成数组Array[T],这样每一个分区就只有一个数组元素 |
union(other:RDD[T]):RDD[T] | 并集 |
intersection(other:RDD[T]):RDD[T] | 交集 |
subtract(other:RDD[T]):RDD[T] | 差集 |
mapPartitions[U:ClassTag](f:Iterator[T]=>Iterator[U],preservesPartitioning:Boolean=False):RDD[U] mapPartitionsWithIndex[U:ClassTag](f:(Int,Iterator[T])=>Iterator[U],preservesPartitioning:Boolean=False):RDD[U] | 这两个函数的作用和map差不多,但是如果在映射过程中需要频繁的创建额外的对象,那么map函数的效率就不是很高了,这时使用mapPartitions和mapPartitionsWithIndex效果会比较好 |
zip[U:ClassTag](other:RDD[U]):RDD[(T,U)] zipPartitions[B:ClassTag,V;ClassTag](rdd2:RDD[B],preservesPartitioning)(f:(Iterator[T],Iterator[B])=>Iterator[V]):RDD[V] .... | zip用来将两个RDD组合成Key/Value形式的RDD,这里默认分区个数和元素数量相同。 zipPartitions是将多个RDD按照partition组合成新的RDD,需要组合的RDD具有相同的分区数。 例子: val rdd = sc.makeRDD(1 to 5, 2) val rdd1 = sc.makeRDD(Array("1","2","3", "4", "5","6"),2) val zipPartitionsRDD=rdd.zipPartitions(rdd1)((i:Iterator[Int],Iterator[String])=>{Iterator(i.toArrray.size,s.to.Array.size)}) zipPartitionsRDD.collect() 输出: Array(2,3,3,3) |
zipWithIndex():RDD[(T,Long)] zipWithUniqueId():RDD[(T,Long)] | 将RDD中的元素和这个元素的ID组成键/值对,zipWithIndex和zipWithUniqueId有一个主要的区别,zipWithIndex需要启动一个Spark作业来计算每一个分区的开始索引号,一边能顺序索引。而zipWithUniqueId不需要这样一个额外作业。 索引号从0开始。 |
sample(withReplacement,frac,seed) | (作用待定)根据给定的随机种子seed,随机抽样出数量为frac的数据。是否在样本中重复抽取由withReplacement决定。 |
pipe(command,[envVars]) | 通过管道的方式对RDD的每个分区使用shell命令进行操作,返回相应的结果 |
groupBy | 可以指定分组的列 |
键值RDD转换操作(Transformation):RDD[(K,V)]
这些方法主要使用到隐式转换PairRDDFunctions
partitionBy(p:Partitioner):RDD[(K,V)] | 根据p函数生成新的ShuffledRDD,将原RDD重新分区,输入的参数使用到Partitioner的子类,HashPartitioner和RangePartitioner |
mapValue[U](f:V=>U):RDD[(K,U)] | 针对V进行map操作 |
flatMapValues[U](f:V=>TraversableOnce[U]):RDD[(K,U)] | 针对V进行flatMap操作 |
combineByKey foldByKey reduceByKey groupBykey | 这四种键值对转换操作都是针对RDD[K,V]本身,不涉及与其他RDD的组合操作,四种操作最终都会归结为对combineByKey的调用。将RDD[K,V]转化为RDD[K,C]。 例子: val pairs=sc.parallelize(Array((1,1),(1,2),(1,3),(2,1),(1,1))) val bufs= pairs.mapValues(v=>HashSet(v)) val sums=bufs.foldByKey(new HashSet[Int])(_++=_) //以下输出Array((2,Set(1)),(1,Set(1,2,3))) sums.collect() val reduceByKeyRDD=pairs.reduceByKey(_+_) //以下输出Array((2,1),(1,7)) reduceByKeyRDD.collect() val groupByKeyRDD=pairs.groupByKey() //以下输出Array((2,ArrayBuffer(1)),(1,ArrayBuffer(1,2,3,1))) groupByKeyRDD.collect() |
cogroup join leftOuterJoin rightOuterJoin subtractByKey | 针对RDD[K,V]中的K值进行相等连接操作,都是调用cogroup来实现,很容易用。打几个例子看以下就知道了。 例子: val rdd1=sc.parallelize(Array((1,1),(1,2),(2,1),(3,1)),1) val rdd2=sc.parallelize(Array((1,'x'),(2,'y'),(2,'z'),(4,'w')),1) val cogroupRDD=rdd1.cogroup(rdd2)//外链接 val joinRDD=rdd1.join(rdd2) val leftOuterJoinRDD=rdd1.leftOuterJoin(rdd2) val rightOuterJoinRDD=rdd1.rightOuterJoin(rdd2) val subtractByKeyRDD=rdd1.subtractByKey(rdd2) |
sortByKey | 根据值排序 |
cartesian(otherDataset) |
笛卡尔积。在数据集T和U上调用时,返回一个(T,U)对。
这个函数不当当会把集合T和U合起来,连两则在hdfs中执行的task数都会乘起来,例如T有20个task,U有20个task,那么使用cartesian后,会有400个task在运行
|
控制操作:
cache():RDD[T] | 在action后,将RDD对应的Data存放在内存中 |
persist():RDD[T] | 同上 |
persist(level:StorageLevel):RDD[T]
|
这个persist可以设置RDD在action之后存放的级别(内存,磁盘。。。)
|
checkpoint()
|
checkpoint接口是将RDD持久化在HDFS中,其与persist的一个区别是checkpoint将会切断此RDD之前的依赖关系,而persist接口依然保留着RDD的依赖关系.在checkpoint之前要用sc.setCheckpointDir(path),设置checkpoint后RDD的持久化地址。checkpoint比persist更安全
|
行动操作(Action):
first | 返回RDD中的第一个元素 |
count | 返回RDD中元素的个数 |
reduce(f:(T,T)=>T) | 对RDD中的元素进行二元计算,返回计算结果 |
collect()/toArray() | 以集合的形式返回RDD的元素 |
take(num:Int) | (作用待定)将RDD作为集合,返回集合中[0,num-1]下标的元素 |
top(num:Int) | 按照默认的或者是指定的排序规则,返回前num个元素 |
takeOrdered(num:Int) | 以与top相反的排序规则,返回前num个元素 |
aggregate[U](zeroValue:U)(seqOp:(U,T)=>U,combOp(U,U)=>U) | aggregate行动操作中主要提供两个函数,一个是seqOp函数,将RDD中的每一个分区的数据聚合成类型为U的值。另一个函数combOp将各个分区聚合起来的值合并在一起得到最终类型为U的返回值。 |
fold(zeroValue:T)(op:(T,T)=>T) | fold是aggregate的便利接口,其中op操作及时seqOp也是combOp操作。 |
lookup(key:K):Seq[V] | 针对(K,V)类型RDD的行动操作,对于给定的键值,返回与此键值相对应的所有值。 |
takeSample(withReplacement,frac,seed ) | |
saveAsTextFile(path) | |
saveAsSequenceFile(path) | |
saveAsObjectFile(path) | 使用java的系列化方法保存到本地文件,可以被SparkContext.objectFile()加载 |
countByKey() | 对(K,V)l类型的RDD有效 |
foreach(func) |
在数据集上的每一个元素上,运算函数func,通常用于一个更新累加器变量或者和外部存储系统进行交互.
foreach操作有一个问题,在foreach中改变全局变量的值,不能在foreach外观察得到,
例如:
val testrdd = sc.parallelize(1 to 4)
var a = 0
//以下操作过后,a的值还是0
testrdd.foreach(x=>a+=x)
//只有通过以下操作才可以改变a的值
testrdd.collect.foreach(x=>a+=x)
|
collect() | 查看当前转换结果 |
collectPartitions() | 查看每个分区中的结果 |
其他操作
getStorageLevel() | 获取当前RDD的存储级别 |
getDependencies | |
getPartitions |