Spark算子

++

函数签名:def ++(other:RDD[T]):RDD[T]
函数说明:将两个RDD的数据内容合并,返回合并后的RDD,作用与union相同
案例:

val rdd1 = sc.makeRDD(Array(1,2,3))
val rdd2 = sc.makeRDD(Array(11,12,13))
val rdd3 = rdd1 ++ rdd2
println(rdd3.collect().mkString(","))
/*
输出结果:
1,2,3,11,12,13
*/

aggregate

函数签名:def aggregate[U:ClassTag](zeroValue:U)(seqOp:(U,T)=>U,combOp:(U,U)=>U):U
函数说明:和scala集合函数中的aggregate相同,第一个参数为初始值,第二个参数中分别传入分组内和分组间的操作
案例:

val rdd = sc.makeRDD(Array(1, 2, 3, 4, 5, 6, 7, 8, 9))
rdd.aggregate(0)(
  (m, n) => {
    println(s"seqOp=>m:$m n:$n")
    m + n
  },
  (m, n) => {
    println(s"combOp=>m:$m n:$n")
    m + n
  }
)
/*
输出结果:
seqOp=>m:0 n:9
seqOp=>m:0 n:6
seqOp=>m:0 n:8
seqOp=>m:0 n:4
seqOp=>m:0 n:1
seqOp=>m:0 n:5
seqOp=>m:0 n:7
seqOp=>m:0 n:3
seqOp=>m:0 n:2
combOp=>m:0 n:8
combOp=>m:8 n:3
combOp=>m:11 n:9
combOp=>m:20 n:5
combOp=>m:25 n:7
combOp=>m:32 n:6
combOp=>m:38 n:1
combOp=>m:39 n:0
combOp=>m:39 n:0
combOp=>m:39 n:4
combOp=>m:43 n:0
combOp=>m:43 n:2
combOp=>m:45 n:0
combOp=>m:45 n:0
combOp=>m:45 n:0
combOp=>m:45 n:0
*/

cache

函数签名:def cache():this.type
函数说明:将当前RDD保存在内存中,当后续RDD数据发生错误丢失后或者从当前RDD重复计算时,可以从内存中恢复数据
案例:

val sc = SparkContext.getOrCreate(
  new SparkConf().setMaster("local[*]").setAppName("demo0508"))
val rdd1 = sc.textFile("in/users.csv")
rdd1.cache() // 设置缓存
var start = System.currentTimeMillis()
println(rdd1.count())
var end = System.currentTimeMillis()
println("时间差1:" + (end - start))

start = System.currentTimeMillis()
println(rdd1.count())
end = System.currentTimeMillis()
println("时间差2:" + (end - start))
/*
输出结果:(可以看到第二次的运行时间明显小于第一次的运行时间)
38210
时间差1:319
38210
时间差2:20
*/

cartesian

函数签名:def cartesian[U:ClassTag](other:RDD[U]):RDD[(T,U)]
函数说明:传入一个RDD,返回两个RDD组成的笛卡尔积
案例:

val rdd1 = sc.makeRDD(Array(1, 2, 3))
val rdd2 = sc.makeRDD(Array(11, 12, 13))
val rdd3 = rdd1.cartesian(rdd2)
println(rdd3.collect().mkString(","))
/*
输出结果
(1,11),(1,12),(1,13),(2,11),(2,12),(2,13),(3,11),(3,12),(3,13)
*/

checkpoint

函数签名:def checkpoint():Unit=RDDCheckpointData.synchronized
函数说明:将当前RDD状态保存到检查点,当后续RDD数据错误或丢失时,可以从检查点恢复数据
cache的区别:cache()是将数据保存到内存,读取速度会更快,checkpoint是保存到磁盘,数据安全性更高
案例:

val sc = SparkContext.getOrCreate(new SparkConf().setMaster("local[*]").setAppName("RDDDemo0508-2"))
sc.setCheckpointDir("file:///d://")
val rdd = sc.parallelize(Array(("a", 1), ("b", 2), ("c", 3)))
rdd.checkpoint()
rdd.collect()
println(rdd.isCheckpointed)
println(rdd.getCheckpointFile)
/*
输出结果:(成功保存了RDD,并且可以获取保存路径)
true
Some(file:/d:/2d1d18c8-2f72-44e8-8c1e-829dcacf8043/rdd-0)
*/

coalesce

函数签名def coalesce(numPartitions:Int,shuffle:Boolean=false,partitionCoalescer:Option[PartitionCoalescer]=Option.empty)(implicit ord:Ordering[T]=null):RDD[T]
函数说明:改变分区,第一个参数为目标分区数量,第二个参数设置是否shuffle。需注意的是,当目标分区数高于当前分区数是,必须要将第二个参数设为true才能成功修改分区数量
案例:

val conf = new SparkConf().setMaster("local[*]").setAppName("RDDDemo5")
val sc = SparkContext.getOrCreate(conf)
val rdd = sc.makeRDD(Array(1, 2, 3))
println("初始分区数:" + rdd.getNumPartitions)
println("进行shuffle并减少分区:" + rdd.coalesce(7, false).getNumPartitions)
println("不进行shuffle并减少分区:" + rdd.coalesce(7, true).getNumPartitions)
println("进行shuffle并增加分区:" + rdd.coalesce(23, false).getNumPartitions)
println("不进行shuffle并增加分区:" + rdd.coalesce(23, true).getNumPartitions)
/*
输出结果:(可以看到,仅当设置不进行shuffle并增加分区数时,修改分区数失败了)
初始分区数:16
进行shuffle并减少分区:7
不进行shuffle并减少分区:7
进行shuffle并增加分区:16
不进行shuffle并增加分区:23
*/

collect

函数签名:
def collect():Array[T]
def collect[U:ClassTag](f:PartialFunction[T,U]):RDD[U]
函数说明:返回一个包含当前全部元素的Array,是执行算子;可以传入一个偏函数,输出结果将是原本的元素经过偏函数转换后的元素。
注意:使用该算子的RDD元素数量应较少,因为该算子会将全部元素拉取到Driver端
案例:

val rdd = sc.makeRDD(Array(97, 98, 99))
println(rdd.collect().mkString(","))
rdd.collect{case i:Int=>i.toChar}.foreach(println)
/*
不带参数:97,98,99
带参数:b a c (这里的输出顺序是随机的)
*/

collectAsync

函数签名:def collectAsync():FutureAction[Seq[T]]
函数说明:作用同collect,异步操作

compute

函数签名:def compute(split:Partition,context:TaskContext):Iterator[T]
函数说明:RDD的子类要实现的方法,无论一个RDD的血缘关系多么复杂,最终一定会调用compute方法,可以理解为,compute方法实现了RDD依赖链的递归调用

context

函数签名:def context:SparkContext
函数说明:返回当前RDD的上下文对象
案例:

val sc = SparkContext.getOrCreate(new SparkConf().setMaster("local[*]").setAppName("test"))
val rdd = sc.makeRDD(Array(97, 98, 99))
println(rdd.context == sc)
/*
输出结果:
true
*/

count

函数签名:def count():Long
函数说明:返回当前RDD中的元素个数
案例:

val rdd = sc.makeRDD(Array(97, 98, 99))
println(rdd.count())
/*
输出结果:
3
*/

countApprox

函数签名:def countApprox(timeout:Long,confidence:Double=0.95):PartialResult[BoundedDouble]
函数说明:函数名意为获取大致的数量,实际返回当前RDD中获得数据的个数,第一个参数为超时时间
案例:

val rdd = sc.makeRDD(Array(97, 98, 99))
println(rdd.countApprox(3).getFinalValue().mean)
/*
输出结果:
3.0
*/

BoundedDouble类可以使用mean()方法获取平均值,min()方法获取最小值,max()方法获取最大值

countApproxDistinct

函数签名:def countApproxDistinct(relativeSD:Double=0.05):Long
函数说明:求RDD中不重复数据的个数
案例:

val rdd = sc.makeRDD(Array(97, 98, 99, 97, 99))
println(rdd.countApproxDistinct())
/*
输出结果:
3
*/

countAsync

函数签名:def countAsync():FutureAction[Long]
函数说明:求RDD中元素个数,异步操作

countByValue

函数签名:def countByValue()(implicit ord:Ordering[T]=null):Map[T,Long]
函数说明:求RDD中每个元素的个数,返回一个Map集合,Key为RDD中的元素,Value为对应的个数
案例:

val rdd = sc.makeRDD(Array(97, 98, 99, 97, 99))
println(rdd.countByValue())
/*
输出结果:
Map(97 -> 2, 98 -> 1, 99 -> 2)
*/

countByValueApprox

函数签名:def countByValueApprox(timeout:Long,confidence:Double=0.95)(implicit ord:Ordering[T]=null):PartitionResult[Map[T,BoundedDouble]]
函数说明:求大致结果,结果类似于countByValue,区别在于结果的Value为BoundedDouble类型
案例:

val rdd = sc.makeRDD(Array(97, 98, 99, 97, 99))
rdd.countByValueApprox(1).getFinalValue()
  .foreach(entry =>println(entry._1+"-->"+entry._2.mean))
/*
输出结果:
97-->2.0
98-->1.0
99-->2.0
*/

dependencies

函数签名:final def dependencies:Seq[Dependency[_]]
函数说明:返回当前RDD的血缘关系
案例:

val rdd = sc.makeRDD(Array(97, 98, 99, 97, 99))
val mapRDD = rdd.map(_ - 90)
val groupRDD = mapRDD.groupBy(_ % 3)
println(mapRDD.dependencies)
println(groupRDD.dependencies)
/*
输出结果:
List(org.apache.spark.OneToOneDependency@5bca7664)
List(org.apache.spark.ShuffleDependency@46866946)
*/

distinct

函数签名:def distinct():RDD[T]
函数说明:RDD元素去重
案例:

val rdd = sc.makeRDD(Array(97, 98, 99, 97, 99))
println(rdd.distinct().collect().mkString(","))
/*
输出结果:
97,98,99
*/

filter

函数签名:def filter(f:T=>Boolean):RDD[T]
函数说明:作用同scala集合filter函数,过滤掉不符合传入条件的元素
案例:

val rdd = sc.makeRDD(Array(97, 98, 99, 97, 99))
println(rdd.filter(_ % 3 == 0).collect().mkString(","))
/*
输出结果:
99,99
*/

first

函数签名:def first():T
函数说明:返回集合中第一个元素
案例:

val rdd = sc.makeRDD(Array(97, 98, 99, 97, 99))
println(rdd.first())
/*
输出结果:
97
*/

flatMap

函数签名:def flatMap[U:ClassTag](f:T=>TraversableOnce[U]):RDD[U]
函数说明:作用同scala集合flatMap函数,扁平化操作
案例:

val rdd = sc.makeRDD(Array(Array(1,2),Array(3,4),Array(5,6)))
println(rdd.flatMap(e => e).collect().mkString(","))
/*
输出结果
1,2,3,4,5,6
*/

fold

函数签名:def fold(zeroValue:T)(op:(T,T)=>T):T
函数说明:作用同scala集合fold/foldLeft函数,从左向右折叠操作
案例:

val rdd = sc.makeRDD(Array(1, 2, 3, 4, 5, 6))
val result = rdd.fold(3)(
  (m, n) => {
    println(s"m:$m n:$n")
    m + n
  }
)
println(result)
/*
输出结果
m:3 n:4
m:3 n:1
m:3 n:2
m:3 n:5
m:3 n:3
m:3 n:6
m:3 n:3
m:6 n:3
m:9 n:3
m:12 n:4
m:16 n:7
m:23 n:3
m:26 n:3
m:29 n:3
m:32 n:9
m:41 n:3
m:44 n:3
m:47 n:5
m:52 n:3
m:55 n:8
m:63 n:6
m:69 n:3
72
*/

foreach

函数签名:def foreach(f:T=>Unit):Unit
函数说明:对RDD中每个操作执行传入的操作

foreachAsync

函数签名:def foreachAsync(f:T=>Unit):FutureAction[Unit]
函数说明:同foreach,异步操作

foreachPartition

函数签名:def foreachPartition(f:Iterator[T]=>Unit):Unit
函数说明:对RDD中每个分区执行传入的操作
案例:

val rdd = sc.makeRDD(Array(1, 2, 3, 4, 5, 6))
rdd.groupBy(e => e).foreachPartition(_.foreach(println))

foreachPartitionAsync

函数签名:def foreachPartitionAsync(f:Iterator[T]=>Unit):FutureAction[Unit]
函数说明:同foreachPartition,异步操作

getCheckpointFile

函数签名:def getCheckpointFile:Option[String]
函数说明:获取检查点文件保存路径,返回Option对象
案例:

sc.setCheckpointDir("d://")
val rdd = sc.makeRDD(Array(1, 2, 3, 4, 5, 6))
val mapRDD = rdd.map(_ * 2)
mapRDD.cache()
mapRDD.checkpoint()
val reduceRDD = mapRDD.reduce(_ + _)
println(mapRDD.getCheckpointFile.getOrElse("nothing"))
/*
输出结果:
file:/d:/94a67547-26ea-4fa9-984a-f3ba83c9d13a/rdd-1
*/

getNumPartitions

函数签名:final def getNumPartitions:Int
函数说明:返回RDD当前分区数量,不特殊设置的话为物理机线程数
案例:

// 这里将分区数量设为3个
val rdd = sc.makeRDD(Array(1, 2, 3, 4, 5, 6),3)
println(rdd.getNumPartitions)
// 修改分区数量后重新输出结果
println(rdd.coalesce(5,true).getNumPartitions)
/*
输出结果:
3
5
*/

glom

函数签名:def glom():RDD[Array[T]]
函数说明:将RDD每个分区的全部元素放入一个 集合中
案例:

val rdd = sc.makeRDD(Array(1, 2, 3, 4, 5, 6, 7), 3)
rdd.glom().collect().map(_.toList).foreach(println)
/*
输出结果:
List(1, 2)
List(3, 4)
List(5, 6, 7)
*/

groupBy

函数签名:def groupBy[K](f:T=>K)(implicit kt:ClassTag[K]):RDD[K,Iterable[T]]
函数说明:根据RDD中每个元素执行传入函数后的结果,进行分组,返回一个双值RDD(分组键及对应的元素组成的可迭代对象)
案例:

val rdd = sc.makeRDD(Array(1, 2, 3, 4, 5, 6, 7), 3)
rdd.groupBy(_ / 2).collect().foreach(e => println(e._1 + "->>" + e._2))
/*
输出结果:
0->>CompactBuffer(1)
3->>CompactBuffer(6, 7)
1->>CompactBuffer(2, 3)
2->>CompactBuffer(4, 5)
*/

histogram

函数签名:def histogram(bucketCount:Int):(Array[Double],Array[Long])
函数说明:直方图,传入的参数为分桶数量,分区范围为RDD中数据的最小值到最大值,分隔点按照分桶数量在分区范围内平均分布,每个分区(最后一个除外)区间都是左闭右开的。

最终结果为一个由两个数组组成的二元组,第一项为分隔点组成的集合,第二项的元素个数刚好比第一项的元素个数少一个,代表相邻两个分隔点之间包含的元素个数。

当RDD元素中包含无穷大/小时,会抛出异常,当RDD元素最大值与最小值相等(即全部元素相同)时,会将分桶数量重新设置为1个
案例:

val rdd = sc.makeRDD(Array(1, 2, 3,  5, 6, 8))
val resultRDD = rdd.histogram(2)
println(resultRDD._1.mkString(","))
println(resultRDD._2.mkString(","))
/*
输出结果:
1.0,4.5,8.0
3,3
*/

本函数还包含另一个重载形式:
函数签名:def histogram(buckets:Array[Double],evenBuckets:Boolean=false):Array[Long]
参数说明:

  • 第一个参数为一个Double数组,里面的每个元素视为直方图的一个分隔点,最大值和最小值之间就是直方图横轴范围,相邻两个分隔点之间组成一个分区,分区(除最后一个外)都是左闭右开的,统计RDD处于各个分区内的元素个数,返回个数组成的数组(会比传入的Double数组元素个数小1)
  • 第二个参数默认为false,当RDD元素间差值稳定时,可以将其设为true,提高运算效率

需要注意的是:传入的Double数组需要是单调递增的,如果相邻两个元素相等或者后一个元素小于前一个,那么这两个元素组成的分区中不会统计到元素
案例:

val rdd = sc.makeRDD(Array(1, 2, 3, 5, 6, 8))
val result = rdd.histogram(Array(0.0, 2.0, 7.0, 10.0))
println(result.mkString(","))
/*
输出结果:
1,4,1
*/

id

函数签名:def id:Int
函数说明:当前RDD的ID

intersection

函数签名:def intersection(other:RDD[T]):RDD[T]
函数说明:作用同scala集合intersect函数,求两个RDD数据交集,返回新集合
案例:

val rdd1 = sc.makeRDD(Array(1, 2, 3, 4, 5, 6, 7), 3)
val rdd2 = sc.makeRDD(Array(1, 3, 5, 7, 9), 1)
println(rdd1.intersection(rdd2).collect().mkString(","))
/*
输出结果
3,1,7,5
*/

isCheckpointed

函数签名:def isCheckpointed:Boolean
函数说明:检查当前RDD是否保存了检查点,已保存则返回true,否则返回false
案例:

sc.setCheckpointDir("d://")
val rdd = sc.makeRDD(Array(1, 2, 3, 4, 5, 6, 7), 3)
val mapRDD1 = rdd.map(_ + 1)
val mapRDD2 = mapRDD1.map(_ - 1)
mapRDD1.checkpoint()
//必须有执行算子才会执行前面的转换算子操作,转换算子操作执行之后才能保存检查点
mapRDD2.collect()
println(mapRDD1.isCheckpointed)
println(mapRDD2.isCheckpointed)
/*
输出结果
true
false
*/

isEmpty

函数签名:def isEmpty():Boolean
函数说明:检查当前RDD中是否有数据,如果没有返回true
案例:

val rdd = sc.makeRDD(Array(1, 2, 3, 4, 5, 6, 7), 3)
println(rdd.isEmpty())
println(rdd.filter(_>10).isEmpty())
/*
输出结果
false
true
*/

iterator

函数签名:final def iterator(split:Partition,context:TaskContext):Iterator[T]
函数说明:RDD内部方法,并非用来让开发人员直接调用。

Internal method to this RDD; will read from cache if applicable, or otherwise compute it.
This should ''not'' be called by users directly, but is available for implementors of custom subclasses of RDD.

keyBy

函数签名:def keyBy[K](f:T=>K):RDD[K,T]
函数说明:将RDD中的元素经过传入的操作生成的数据作为key,生成一个(key,value)的键值对,key即为生成的key,value为RDD原数据
案例:

val rdd = sc.makeRDD(Array(1, 2, 3, 4, 5, 6, 7), 3)
println(rdd.keyBy(_ / 2).collect().mkString(","))
/*
输出结果
(0,1),(1,2),(1,3),(2,4),(2,5),(3,6),(3,7)
*/

localCheckpoint

函数签名:def localCheckpoint():this.type
函数说明:
localCheckpoint的作用是标记此RDD使用Spark现有的缓存层进行本地化的checkpointing操作,这对于那些单纯的想要切断RDD的长lineage,又不想使用普通checkpoint将数据保存到高可靠文件系统的开销的场景,尤其是那些需要周期性的truncate长lineage的情形

map

函数签名:def map[U:ClassTag](f:T=>U):RDD[U]
函数说明:作用同scala集合map函数,对RDD每个元素执行传入的操作,返回由结果组成的新的RDD

mapPartitions

函数签名:def mapPartitions[U:ClassTag](f:Iterator[T]=>Iterator[U],preserverPartitioning:Boolean=false):RDD[U]
函数说明:作用类似于map,区别在于传入的参数为对分区整个集合的操作
案例:

val rdd = sc.makeRDD(Array(1, 2, 3, 4, 5, 6, 7), 3)
rdd.groupBy(_ < 5).mapPartitions(
  iter => iter.map(_._2)
).collect().foreach(println)
/*
输出结果:
CompactBuffer(5, 6, 7)
CompactBuffer(1, 2, 3, 4)
*/

mapPartitionsWithIndex

函数签名:def mapPartitionsWithIndex[U:ClassTag](f:(Int,Iterator[T])=>Iterator[U],preserverPartitioning:Boolean=false):RDD[U]
函数说明:类似于mapPartitions,区别在于要传入的函数中,参数由Iterator[T]转换成了(Int,Iterator[T]),即由RDD原本元素的迭代器转换成了索引和迭代器的二元组
案例:

val rdd = sc.makeRDD(Array(1, 2, 3, 4, 5, 6, 7), 3)
rdd.mapPartitionsWithIndex(
  (index,iter)=>iter
).collect().foreach(e => print(e+" "))
/*
输出结果:
1 2 3 4 5 6 7 
*/

max

函数签名:def max()(implicit ord:Ordering[T]):T
函数说明:返回当前RDD中最大的元素
案例:

val rdd = sc.makeRDD(Array(1, 2, 3, 4, 5, 6, 7), 3)
println(rdd.max)
/*
输出结果:
7
*/

mean

函数签名:def mean():Double
函数说明:返回当前RDD中数据的平均值
案例:

val rdd = sc.makeRDD(Array(1, 2, 3, 4, 5, 6, 7), 3)
println(rdd.mean())
/*
输出结果:
4.0
*/

meanApprox

函数签名:def meanApprox(timeout:Long,confidence:Double=0.95):PartialResult[BoundedDouble]
函数说明:求当前RDD中数据的大致平均值

val rdd = sc.makeRDD(Array(1, 2, 3, 4, 5, 6, 7), 3)
println(rdd.meanApprox(3).getFinalValue().mean)
/*
输出结果:
4.0
*/

min

函数签名:def min()(implicit ord:Ordering[T]):T
函数说明:返回当前RDD中数据最小值
案例:

val rdd = sc.makeRDD(Array(1, 2, 3, 4, 5, 6, 7), 3)
println(rdd.min)
/*
输出结果:
1
*/

name

函数(属性)签名:@transient var name: String = _
案例:

val rdd = sc.makeRDD(Array(1, 2, 3, 4, 5, 6, 7), 3)
rdd.setName("numberSet")//不设置的话默认输出为null
println(rdd.name)
/*
输出结果:
numberSet
*/

partitioner:

函数(属性)签名:val partitioner:Option[Partitioner]=None
函数(属性)说明:当前RDD的分区器
案例:

val rdd = sc.makeRDD(Array(1, 2, 3, 4, 5, 6, 7), 3)
println(rdd.groupBy(_ < 5).partitioner)
/*
输出结果:
Some(org.apache.spark.HashPartitioner@3)
*/

partitions

函数签名:final def partitions:Array[Partition]
函数说明:返回RDD总共分区数量(包含空数据分区)
案例:

val rdd = sc.makeRDD(Array(1, 2, 3, 4, 5, 6, 7), 5)
rdd.map(_ * 2).groupBy(_ < 5).partitions.foreach(println)
/*
输出结果:
org.apache.spark.rdd.ShuffledRDDPartition@0
org.apache.spark.rdd.ShuffledRDDPartition@1
org.apache.spark.rdd.ShuffledRDDPartition@2
org.apache.spark.rdd.ShuffledRDDPartition@3
org.apache.spark.rdd.ShuffledRDDPartition@4
*/

persist

函数签名:def persist(): this.type
函数说明:RDD持久化,可以选择持久化级别,设置时传入StorageLevel伴生对象中预设好的持久化级别即可,例如:rdd.persist(StorageLevel.MEMORY_AND_DISK)

持久化级别含义
MEMORY_ONLY使用未序列化的Java对象格式,将数据保存在内存中。如果内存不够存放所有的数据,则数据可能就不会进行持久化。那么下次对这个RDD执行算子操作时,那些没有被持久化的数据,需要从源头处重新计算一遍。这是默认的持久化策略,使用cache()方法时,实际就是使用的这种持久化策略。
MEMORY_AND_DISK使用未序列化的Java对象格式,优先尝试将数据保存在内存中。如果内存不够存放所有的数据,会将数据写入磁盘文件中,下次对这个RDD执行算子时,持久化在磁盘文件中的数据会被读取出来使用。
MEMORY_ONLY_SER基本含义同MEMORY_ONLY。唯一的区别是,会将RDD中的数据进行序列化,RDD的每个partition会被序列化成一个字节数组。这种方式更加节省内存,从而可以避免持久化的数据占用过多内存导致频繁GC。
MEMORY_AND_DISK_SER基本含义同MEMORY_AND_DISK。唯一的区别是,会将RDD中的数据进行序列化,RDD的每个partition会被序列化成一个字节数组。这种方式更加节省内存,从而可以避免持久化的数据占用过多内存导致频繁GC。
DISK_ONLY使用未序列化的Java对象格式,将数据全部写入磁盘文件中。
MEMORY_ONLY_2, MEMORY_AND_DISK_2, 等等.对于上述任意一种持久化策略,如果加上后缀_2,代表的是将每个持久化的数据,都复制一份副本,并将副本保存到其他节点上。这种基于副本的持久化机制主要用于进行容错。假如某个节点挂掉,节点的内存或磁盘中的持久化数据丢失了,那么后续对RDD计算时还可以使用该数据在其他节点上的副本。如果没有副本的话,就只能将这些数据从源头处重新计算一遍了。

pipe

函数签名:
def pipe(command:String):RDD[String]
函数说明:使用spark执行外部shell脚本,传入参数为脚本路径
案例:
在这里插入图片描述
可以执行外部脚本(/opt目录下创建一个test.sh脚本)
在这里插入图片描述
在这里插入图片描述

popStdev

函数签名:def popStdev():Double
函数说明:返回当前RDD数据的标准差
案例:

val rdd = sc.makeRDD(Array(1, 2, 3, 4), 5)
println(rdd.popStdev())
/*
输出结果:
1.118033988749895
*/

popVariance

函数签名:def popVariance():Double
函数说明:返回当前RDD数据的方差
案例:

val rdd = sc.makeRDD(Array(1, 2, 3, 4), 5)
println(rdd.popVariance())
/*
输出结果:
1.2499999999999998
*/

randomSplit

函数签名:def randomSplit(weight:Array[Double],seed:Long=Utils.random.nextLong): Array[RDD[T]]
函数说明:将当前RDD切分为n个RDD,并将切分后的RDD保存到一个数组中返回
参数说明:

  • 第一个参数为一个Double数组,数组元素个数代表切分RDD的个数,每个元素的数值代表对应RDD被分配元素的概率(所以,数组元素总和应为1,总和不为1时会按照比例调整数值)。注意Double数组中的元素仅为被分配元素的概率,当数组值为Array(0.5,0.5)时,并非一定会获得两个拥有相同元素个数的RDD
  • 第二个参数为随机因子

案例:

val rdd = sc.makeRDD(Array(1, 2, 3, 4, 5, 6, 7, 8, 9, 0), 5)
val arr = rdd.randomSplit(Array(1,1))
arr.foreach(splitRDD => println(splitRDD.collect().mkString(",")))
/*
输出结果:
3,4,5,8,9
1,2,6,7,0
*/

reduce

函数签名:def reduce(f:(T,T)=>T):T
函数说明:作用同scala集合reduce函数,无初始值的折叠操作
案例:

val rdd = sc.makeRDD(Array(1, 2, 3, 4, 5, 6, 7, 8, 9, 0), 5)
println(rdd.reduce{
  (m,n)=>{
    println(s"m:$m n:$n")
    m+n
  }
})
/*
输出结果:
m:9 n:0
m:7 n:8
m:3 n:4
m:5 n:6
m:1 n:2
m:11 n:7
m:18 n:9
m:27 n:3
m:30 n:15
45
*/

repartition

函数签名:def repartition(numPartitions:Int)(implicit ord:Ordering[T]=null):RDD[T]
函数说明:RDD重分区,完全等同于coalesce函数中shuffle参数为true时的情况,实际上repartition源码就是调用了coalesce函数,并将shuffle参数赋值为true
案例:

val rdd = sc.makeRDD(Array(1, 2, 3, 4, 5, 6, 7, 8, 9, 0), 5)
println("重分区前分区数:" + rdd.getNumPartitions)
val rePartitionedRDD = rdd.repartition(3)
println("重分区后分区数:" + rePartitionedRDD.getNumPartitions)
/*
输出结果:
重分区前分区数:5
重分区后分区数:3
*/

sample

函数签名:def sample(withRepalcement:Boolean,fraction:Double,seed:Long=Util.random.nextLong):RDD[T]
函数说明:对RDD中的数据取样
参数说明:

  • 第一个参数withReplacement表示是否将取出的数据放回(true表示放回)
  • 第二个参数fraction表示元素被抽取概率
    • 当抽取不放回时,表示每个元素被抽取的可能性
    • 当抽取并放回时,表示每个元素被抽取的期望次数(数值应大于等于0)
  • 第三个参数seed为随机因子
    案例:
val rdd = sc.makeRDD(Array(1, 2, 3, 4, 5, 6, 7, 8, 9, 0), 5)
val result = rdd.sample(false,0.2).collect()
result.foreach(println)
/*
输出结果:
1
5
7
*/

sampleStdev

函数签名:def sampleStdev():Double
函数说明:返回抽样样本标准差

sampleVariance

函数签名:def sampleVariance():Double
函数说明:返回抽样样本方差

saveAsObjectFile

函数签名:def saveAsObjectFile(path:String):Unit
函数说明:将当前RDD数据以ObjectFile形式保存在指定路径(指定的路径不能已存在,否则会报错)
案例:

val rdd = sc.makeRDD(Array(1, 2, 3, 4, 5), 5)
rdd.saveAsObjectFile("d://RDDObjectFile")
rdd.collect()

在这里插入图片描述

saveAsTextFile

函数签名:def saveAsTextFile(path:String):Unit
函数说明:同saveAsObjectFile,以Text格式保存数据
案例:

val rdd = sc.makeRDD(Array(1, 2, 3, 4, 5), 5)
rdd.saveAsTextFile("d://RDDTextFile")
rdd.collect()

在这里插入图片描述

setName

函数签名:def setName(_name:String):this.Type
函数说明:设置RDD名称
案例:

val rdd = sc.makeRDD(Array(1, 2, 3, 4, 5), 5)
println(rdd.name)
rdd.setName("RDD0508")
println(rdd.name)
/*
输出结果:
null
RDD0508
*/

sortBy

函数签名:
def sortBy[K]( f:(T)=>K, ascending:Boolean=true, numPartitions:Int=this.partitions.length)
(implicit ord:Ordering[K],ctag:ClassTag[K]):RDD[T]
函数说明:对RDD中每个元素执行传入的操作,将生成的结果作为Key,根据Key对元素排序
参数说明:

  • f:(T)=>K为生成排序所需Key的操作
  • ascending表示是否为升序排序,默认为true即升序排序
  • numPartitions表示分组数量

案例:

val rdd = sc.makeRDD(Array(1, 2, 3, 4, 5), 5)
val sortedRDD = rdd.sortBy(_ % 3)
println(sortedRDD.collect().mkString(","))
/*
输出结果:
3,1,4,2,5
*/

sparkContext

函数签名:def sparkContext:SparkContext
函数说明:返回当前RDD的上下文对象
案例:

val rdd = sc.makeRDD(Array(1, 2, 3, 4, 5), 5)
println(rdd.sparkContext == sc)
/*
输出结果:(可以证明这里返回的就是创建RDD时使用的SparkContext对象)
true
*/

stats

函数签名:def stats():StatCounter
函数说明:放回当前RDD数据的一个StatCounter对象,通过该对象可以查看当前数据集合的最大值、最小值、总和、方差、标准差等各项数值
案例:

val rdd = sc.makeRDD(Array(1, 2, 3, 4, 5), 5)
val statsCounter = rdd.stats()
println("最大值是:" + statsCounter.max) 
println("最小值是:" + statsCounter.min) 
println("总和是:" + statsCounter.sum) 
println("平均值是:" + statsCounter.mean) 
println("方差是:" + statsCounter.variance) 
println("标准差是:" + statsCounter.stdev) 
/*
输出结果:
最大值是:5.0
最小值是:1.0
总和是:15.0
平均值是:3.0
方差是:2.0
标准差是:1.4142135623730951
*/

stdev

函数签名:def stdev():Double
函数说明:返回RDD数据集的标准差

subtract

函数签名:
def subtract(other:RDD[T]):RDD[T]
def subtract(oterh:RDD[T],numberPartitions:Int):RDD[T]
def subtract(oterh:RDD[T],p:Partitioner)(implicit ord:Ordering[T]=null):RDD[T]
函数说明:求两个RDD元素的差集
参数说明:

  • other:第二个RDD,结果当前RDD对传入RDD的差集
  • numberPartitions:分区数,指定结果RDD的分区数
  • p:分区器,指定分区规则,默认为null

案例:

// 仅指定差集RDD
val rdd1 = sc.makeRDD(Array(1, 2, 3, 4, 5), 5)
val rdd2 = sc.makeRDD(Array(1, 3, 5, 7, 9))
val rdd3 = rdd1.subtract(rdd2)
println(rdd3.collect().mkString(","))
println(rdd3.getNumPartitions)
/*
输出结果:
2,4
5
*/

// 指定分区数量
val rdd1 = sc.makeRDD(Array(1, 2, 3, 4, 5), 5)
val rdd2 = sc.makeRDD(Array(1, 3, 5, 7, 9))
val rdd3 = rdd1.subtract(rdd2,6)
println(rdd3.collect().mkString(","))
println(rdd3.getNumPartitions)
/*
输出结果:
2,4
6
*/

// 指定分区器
class MyPartitioner extends Partitioner {
  override def numPartitions: Int = 10//这里指定了分区数量

  override def getPartition(key: Any): Int = {
    if (key.asInstanceOf[Int] < 3) 0 else 1//这里指定了分区规则
  }
}
def main(args: Array[String]): Unit = {
  val conf = new SparkConf().setMaster("local[*]").setAppName("RDDDemo5")
  val sc = SparkContext.getOrCreate(conf)
  val rdd1 = sc.makeRDD(Array(1, 2, 3, 4, 5), 5)
  val rdd2 = sc.makeRDD(Array(1, 3, 5, 7, 9))
  val rdd3 = rdd1.subtract(rdd2,new MyPartitioner)
  println(rdd3.collect().mkString(","))
  println(rdd3.getNumPartitions)
}
/*
输出结果:
2,4
10
*/

sum

函数签名:def sum():Double
函数说明:返回RDD中数据的总和

sumApprox

函数签名:def sumApprox(timeout:Long,confidence:Double=0.95):PartialResult[BoundedDouble]
函数说明:返回RDD中数据总和的大概值
案例:

val rdd = sc.makeRDD(Array(1, 2, 3, 4, 5), 5)
println(rdd.sumApprox(3).getFinalValue().mean)
/*
输出结果:
15.0
*/

variance

函数签名:def variance():Double
函数说明:返回RDD数据集中的方差

take

函数签名:def take(num:Int):Array[T]
函数说明:取出当前RDD数据中前n个数值
案例:

val rdd = sc.makeRDD(Array(1, 2, 3, 4, 5), 5)
rdd.take(3).foreach(println)
/*
输出结果:
1
2
3
*/

takeAsync

函数签名:def takeAsync(num:Int):FutureAction[Seq[T]]
函数说明:作用同take,异步操作
案例:

val rdd = sc.makeRDD(Array(1, 2, 3, 4, 5), 5)
println(rdd.takeAsync(3).get())
/*
输出结果
ArrayBuffer(1, 2, 3)
*/

takeOrdered

函数签名:def takeOrdered(num:Int)(implicit ord:Ordering[T]):Array[T]
函数说明:取出RDD中元素升序排序后的前n个元素
案例:

val rdd = sc.makeRDD(Array(4, 2, 1, 3, 5), 5)
println(rdd.takeOrdered(3).mkString(","))

takeSample

函数签名:def takeSample(withRepalcement:Boolean,num:Int,seed:Long=Utils.random.nextLong):Array[T]
函数说明:从RDD数据中随机抽取数据样本,返回RDD子集
参数说明:

  • withReplacement:是否允许同一元素被多次抽取
  • num:返回RDD子集的大小
  • seed:随机因子

案例:

val rdd = sc.makeRDD(Array(4, 2, 1, 3, 5), 5)
println(rdd.takeSample(true, 3).mkString(","))
/*
输出结果:
5,3,3
*/

toDebugString

函数签名:def toDebugString:String
函数说明:返回当前RDD的描述和血缘依赖关系,用于程序调试
案例:

val rdd = sc.makeRDD(Array(4, 2, 1, 3, 5), 5)
println(rdd.map(_ * 2).sortBy(e => e).groupBy(_ % 2).toDebugString)
/*
输出结果:
(5) ShuffledRDD[8] at groupBy at Test5.scala:10 []
 +-(5) MapPartitionsRDD[7] at groupBy at Test5.scala:10 []
    |  MapPartitionsRDD[6] at sortBy at Test5.scala:10 []
    |  ShuffledRDD[5] at sortBy at Test5.scala:10 []
    +-(5) MapPartitionsRDD[2] at sortBy at Test5.scala:10 []
       |  MapPartitionsRDD[1] at map at Test5.scala:10 []
       |  ParallelCollectionRDD[0] at makeRDD at Test5.scala:9 []
*/

toJavaRDD

函数签名:def toJavaRDD():JavaRDD[T]
函数说明:将当前RDD转换为JavaRDD

toLocalIterator

函数签名:def toLocalIterator:Iterator[T]
函数说明:将当前RDD的数据放入一个Iterator中返回

top

函数签名:def top(num:Int)(implicit ord:Ordering[T]):Array[T]
函数说明:与takeOrdered()函数相反,返回RDD集合中最大的n个元素。另外,源码提示:仅当RDD数据较少时才可以使用本函数,因为本函数会将全部数据加载到Driver中
案例:

val rdd = sc.makeRDD(Array(4, 2, 1, 3, 6, 5), 5)
println(rdd.top(3).mkString(","))
/*
输出结果:
6,5,4
*/

treeAggregate

函数签名:def treeAggregate[U:ClassTag](zeroValue:U)(seqOp:(U,T)=>U,comOp:(U,U)=>U,depth:Int=2):U
函数说明:aggregate函数的优化版,由于aggregate在分区内操作完后会直接将结果数据发送到Driver端进行最后合并,所以可能导致Driver端数据过多,treeAggregate会在把数据发送的Driver端之前进行合并
参数说明

  • depth:树深度,可以理解为合并次数,默认为2(即相对于aggregate额外一次合并),除本参数外,其余使用方式与aggregate完全相同
    在这里插入图片描述

treeReduce

函数签名:def treeReduce(f:(T,T)=>T,depth:Int=2):T
函数说明:相当于无初始值,且分组间和分组内操作相同的treeAggregate,使用方式类似于reduce,同样是reduce的升级版,会在将数据发送到Driver之前进行聚合

union

函数签名:def union(other:RDD[T]):RDD[T]
函数说明:取当前RDD和传入RDD数据的并集RDD,与++函数完全相同

unpersist

函数签名:def unpersist(blocking:Boolean=true):this.type
函数说明:删除已缓存(cache函数)的数据

zip

函数签名:def zip[U:ClassTag](other:RDD[U]):RDD[(T,U)]
函数说明:拉链操作,将两个RDD视作数组的话,将相同索引位置的数据组成一个二元组,返回包含全部二元组的RDD。需注意的是,不同于scala的zip函数,本函数同时要求两个RDD元素个数相同且分区数相同,否则会抛出异常

val rdd = sc.makeRDD(Array(4, 2, 1, 3, 6, 5), 5)
val zipRDD = rdd.zip(sc.makeRDD(Array('a', 'b', 'c', 'e', 'f', 'g'),5))
println(zipRDD.collect().mkString(","))
/*
输出结果:
(4,a),(2,b),(1,c),(3,e),(6,f),(5,g)
*/

zipPartitions

函数签名:
def zipPartitions[B:ClassTag,V:ClassTag]
(rdd2:RDD[B],preservesPartitioning:Boolean)
(f:(Iterator[T],Iterator[B])=>Iterator[V]):RDD[V]
函数说明:将多个RDD组合,组合逻辑类似于zip。本函数有很多重载函数,包括传入1个到3个RDD以及包含和不包含preservesPartitioning参数的函数,实际返回的结果是根据传入的f函数的返回值决定的。
需要注意的是,本函数要求所有的RDD元素个数相同,且分区数相同,但是不要求每个分区内的元素个数相同
案例:

val rdd1 = sc.makeRDD(Array(4, 2, 1, 3, 6, 5), 5)
val rdd2 = sc.makeRDD(Array('a', 'c', 'b', 'x', 'y', 'z'), 5)
val rdd3 = sc.makeRDD(Array("A", "C", "B", "X", "Y", "Z"), 5)
val resultRDD = rdd1.zipPartitions(rdd2, rdd3, true)((m, n, p) => m.zip(n).zip(p))
println(resultRDD.collect().mkString(","))
println(resultRDD.toDebugString)
/*
输出结果:
((4,a),A),((2,c),C),((1,b),B),((3,x),X),((6,y),Y),((5,z),Z)
(5) ZippedPartitionsRDD3[3] at zipPartitions at Test5.scala:12 []
 |  ParallelCollectionRDD[0] at makeRDD at Test5.scala:9 []
 |  ParallelCollectionRDD[1] at makeRDD at Test5.scala:10 []
 |  ParallelCollectionRDD[2] at makeRDD at Test5.scala:11 []
*/

zipWithIndex

函数签名:def zipWithIndex():RDD[T,Long]
函数说明:将RDD中的数据与其对应的索引组成二元组,返回包含这些二元组的RDD
案例:

val rdd = sc.makeRDD(Array(4, 2, 1, 3, 6, 5), 5)
println(rdd.zipWithIndex().collect().mkString(","))
/*
输出结果:
(4,0),(2,1),(1,2),(3,3),(6,4),(5,5)
*/

zipWithUniqueId

函数签名:def zipWithUniqueId():RDD[T,Long]
函数说明:使用”唯一ID“与RDD元素组成二元组,返回包含这些二元组的RDD
”唯一ID“算法:
每个分区中第一个元素的唯一ID值为:该分区索引号,
每个分区中第N个元素的唯一ID值为:(前一个元素的唯一ID值) + (该RDD总的分区数)
源码中的说明:

   * Zips this RDD with generated unique Long ids. Items in the kth partition will get ids k, n+k,
   * 2*n+k, ..., where n is the number of partitions. So there may exist gaps, but this method
   * won't trigger a spark job, which is different from [[org.apache.spark.rdd.RDD#zipWithIndex]].
   *
   * @note Some RDDs, such as those returned by groupBy(), do not guarantee order of
   * elements in a partition. The unique ID assigned to each element is therefore not guaranteed,
   * and may even change if the RDD is reevaluated. If a fixed ordering is required to guarantee
   * the same index assignments, you should sort the RDD with sortByKey() or save it to a file.

注明了ID序列的计算:k,n+k,2*n+k,…
同时注明了本函数和zipWithIndex函数不同,不会触发spark job。
案例:

val rdd = sc.makeRDD(Array(4, 2, 1, 3, 6, 5, 3), 5)
println(rdd.zipWithUniqueId().collect().mkString(","))
/*
输出结果:
(4,0),(2,1),(1,2),(3,7),(6,3),(5,4),(3,9)
*/
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值