spark Transformations & Actions

本文例子部分从网上搜集,搜集的网址如下:

http://lxw1234.com/

https://my.oschina.net/scipio/blog/284957#OSC_h5_7

http://blog.csdn.net/guotong1988/article/details/50556871

http://blog.csdn.net/jewes/article/details/39896301

Transformations

map

将一个RDD中的每个数据项,通过map中的函数映射变为一个新的元素。 输入分区与输出分区一对一,即:有多少个输入分区,就有多少个输出分区。

例子:

hadoop fs -cat /tmp/lxw1234/1.txt
hello world
hello spark
hello hive

//读取HDFS文件到RDD
scala> var data = sc.textFile("/tmp/lxw1234/1.txt")
data: org.apache.spark.rdd.RDD[String] = MapPartitionsRDD[1] at textFile at :21
 
//使用map算子
scala> var mapresult = data.map(line => line.split("\\s+"))
mapresult: org.apache.spark.rdd.RDD[Array[String]] = MapPartitionsRDD[2] at map at :23
 
//运算map算子结果
scala> mapresult.collect
res0: Array[Array[String]] = Array(Array(hello, world), Array(hello, spark), Array(hello, hive))
 

filter

将RDD中的符合过滤条件(返回true的数据留下,返回false的数据抛弃)的数据构造成一个新的RDD返回

scala> val filterRdd = sc.parallelize(List(1,2,3,4,5)).map(_*2).filter(_>5)
filterRdd: org.apache.spark.rdd.RDD[Int] = FilteredRDD[13] at filter at <console>:12

scala> filterRdd.collect
14/06/28 12:27:45 INFO SparkContext: Job finished: collect at <console>:15, took 0.056086178 s
res5: Array[Int] = Array(6, 8, 10)

flatMap

属于Transformation算子,第一步和map一样,最后将所有的输出分区合并成一个。 例子:

/使用flatMap算子
scala> var flatmapresult = data.flatMap(line => line.split("\\s+"))
flatmapresult: org.apache.spark.rdd.RDD[String] = MapPartitionsRDD[3] at flatMap at :23
 
//运算flagMap算子结果
scala> flatmapresult.collect
res1: Array[String] = Array(hello, world, hello, spark, hello, hive)

mapPartitions

完整定义为 def mapPartitions[U](f: (Iterator[T]) => Iterator[U], preservesPartitioning: Boolean = false)(implicit arg0: ClassTag[U]): RDD[U]

该函数和map函数类似,只不过映射函数的参数由RDD中的每一个元素变成了RDD中每一个分区的迭代器。如果在映射的过程中需要频繁创建额外的对象,使用mapPartitions要比map高效的过。

比如,将RDD中的所有数据通过JDBC连接写入数据库,如果使用map函数,可能要为每一个元素都创建一个connection,这样开销很大,如果使用mapPartitions,那么只需要针对每一个分区建立一个connection。

参数preservesPartitioning表示是否保留父RDD的partitioner分区信息。 例子:

var rdd1 = sc.makeRDD(1 to 5,2)
//rdd1有两个分区
scala> var rdd3 = rdd1.mapPartitions{ x => {
     | var result = List[Int]()
     |     var i = 0
     |     while(x.hasNext){
     |       i += x.next()
     |     }
     |     result.::(i).iterator
     | }}
rdd3: org.apache.spark.rdd.RDD[Int] = MapPartitionsRDD[84] at mapPartitions at :23
 
//rdd3将rdd1中每个分区中的数值累加
scala> rdd3.collect
res65: Array[Int] = Array(3, 12)
scala> rdd3.partitions.size
res66: Int = 2

mapPartitionsWithIndex

完整定义为 def mapPartitionsWithIndex[U](f: (Int, Iterator[T]) => Iterator[U], preservesPartitioning: Boolean = false)(implicit arg0: ClassTag[U]): RDD[U] 函数作用同mapPartitions,不过提供了两个参数,第一个参数为分区的索引。 例子:

var rdd1 = sc.makeRDD(1 to 5,2)
//rdd1有两个分区
var rdd2 = rdd1.mapPartitionsWithIndex{
        (x,iter) => {
          var result = List[String]()
            var i = 0
            while(iter.hasNext){
              i += iter.next()
            }
            result.::(x + "|" + i).iterator
           
        }
      }
//rdd2将rdd1中每个分区的数字累加,并在每个分区的累加结果前面加了分区索引
scala> rdd2.collect
res13: Array[String] = Array(0|3, 1|12)

sample

对RDD中的集合内元素进行采样,第一个参数withReplacement是true表示有放回取样,false表示无放回。第二个参数表示比例,第三个参数是随机种子。 例子:

scala> import scala.util.Random
import scala.util.Random

scala> val rdd1 = sc.makeRDD(1 to 10)
rdd1: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[3] at makeRDD at <console>:27

scala> rdd1.collect
res4: Array[Int] = Array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

scala> rdd1.sample(true, 0.3, Random.nextInt()).collect  #为true时,表示放回抽样,所以抽到的数据可能重复
res19: Array[Int] = Array(1, 4, 4, 10)

scala> rdd1.sample(false, 0.3, Random.nextInt()).collect  #为false,表示不放回抽样,所以抽到的数据不会重复
res11: Array[Int] = Array(2, 4, 5)

union

定义: def union(other: RDD[T]): RDD[T]

该函数比较简单,就是将两个RDD进行合并,不去重

例子:

scala> var rdd1 = sc.makeRDD(1 to 2,1)
rdd1: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[45] at makeRDD at :21
 
scala> rdd1.collect
res42: Array[Int] = Array(1, 2)
 
scala> var rdd2 = sc.makeRDD(2 to 3,1)
rdd2: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[46] at makeRDD at :21
 
scala> rdd2.collect
res43: Array[Int] = Array(2, 3)
 
scala> rdd1.union(rdd2).collect
res44: Array[Int] = Array(1, 2, 2, 3)

intersection

定义: def intersection(other: RDD[T]): RDD[T] def intersection(other: RDD[T], numPartitions: Int): RDD[T] def intersection(other: RDD[T], partitioner: Partitioner)(implicit ord: Ordering[T] = null): RDD[T]

该函数返回两个RDD的交集,并且去重。 参数numPartitions指定返回的RDD的分区数。 参数partitioner用于指定分区函数

例子:

scala> var rdd1 = sc.makeRDD(1 to 2,1)
rdd1: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[45] at makeRDD at :21
 
scala> rdd1.collect
res42: Array[Int] = Array(1, 2)
 
scala> var rdd2 = sc.makeRDD(2 to 3,1)
rdd2: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[46] at makeRDD at :21
 
scala> rdd2.collect
res43: Array[Int] = Array(2, 3)
 
scala> rdd1.intersection(rdd2).collect
res45: Array[Int] = Array(2)
 
scala> var rdd3 = rdd1.intersection(rdd2)
rdd3: org.apache.spark.rdd.RDD[Int] = MapPartitionsRDD[59] at intersection at :25
 
scala> rdd3.partitions.size
res46: Int = 1
 
scala> var rdd3 = rdd1.intersection(rdd2,2)
rdd3: org.apache.spark.rdd.RDD[Int] = MapPartitionsRDD[65] at intersection at :25
 
scala> rdd3.partitions.size
res47: Int = 2

subtract(补充)

定义: def subtract(other: RDD[T]): RDD[T] def subtract(other: RDD[T], numPartitions: Int): RDD[T] def subtract(other: RDD[T], partitioner: Partitioner)(implicit ord: Ordering[T] = null): RDD[T]

该函数类似于intersection,但返回在RDD中出现,并且不在otherRDD中出现的元素,不去重。 参数含义同intersection

例子:

scala> var rdd1 = sc.makeRDD(Seq(1,2,2,3))
rdd1: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[66] at makeRDD at :21
 
scala> rdd1.collect
res48: Array[Int] = Array(1, 2, 2, 3)
 
scala> var rdd2 = sc.makeRDD(3 to 4)
rdd2: org.apache.spark.rdd.RDD[Int] = ParallelCollectionRDD[67] at makeRDD at :21
 
scala> rdd2.collect
res49: Array[Int] = Array(3, 4)
 
scala> rdd1.subtract(rdd2).collect
res50: Array[Int] = Array(1, 2, 2)

distinct

对RDD中的元素进行去重操作。

scala> data.flatMap(line => line.split("\\s+")).collect
res61: Array[String] = Array(hello, world, hello, spark, hello, hive, hi, spark)
 
scala> data.flatMap(line => line.split("\\s+")).distinct.collect
res62: Array[String] = Array(hive, hello, world, spark, hi)

groupByKey

当对一个(K,V)键值对组成的dataset使用groupByKey操作,返回一个新的(K, Iterable)键值对组成的dataset。 另外:如果要对每个key做聚合操作,比如sum或average的时候,使用reduceByKey或combineByKey会更高效。分片数取决于父RDD的分片数,但是也可以指定一个新的numTasks参数 例子:

scala> val a = sc.parallelize(List("dog", "dog", "tiger", "lion", "cat", "spider", "eagle"), 2)
a: org.apache.spark.rdd.RDD[String] = ParallelCollectionRDD[16] at parallelize at <console>:28

scala> val b = a.keyBy(_.length)  #给value加上key,key为对应string的长度
b: org.apache.spark.rdd.RDD[(Int, String)] = MapPartitionsRDD[17] at keyBy at <console>:30

scala> b.groupByKey.collect
res20: Array[(Int, Iterable[String])] = Array((4,CompactBuffer(lion)), (6,CompactBuffer(spider)), (3,CompactBuffer(dog, dog, cat)), (5,CompactBuffer(tiger, eagle)))#注意dog出现了两次,这个方法只是简单的group,不进行去重

groupBy (补充)

groupBy(function) function返回key,传入的RDD的各个元素根据这个key进行分组

val a = sc.parallelize(1 to 9, 3)
a.groupBy(x => { if (x % 2 == 0) "even" else "odd" }).collect//分成两组
/*结果 
Array(
(even,ArrayBuffer(2, 4, 6, 8)),
(odd,ArrayBuffer(1, 3, 5, 7, 9))
)
*/
val a = sc.parallelize(1 to 9, 3)
def myfunc(a: Int) : Int =
{
  a % 2//分成两组
}
a.groupBy(myfunc).collect
/* 
结果 
Array( 
(0,ArrayBuffer(2, 4, 6, 8)), 
(1,ArrayBuffer(1, 3, 5, 7, 9)) 
) 
*/

reduceByKey

定义: reduceByKey(func, [numTasks])

在一个(K,V)对的数据集上使用,返回一个(K,V)对的数据集,key相同的值,都被使用指定的reduce函数聚合到一起。func函数类型必须是(V,V) => V.和groupbykey类似,任务的个数是可以通过第二个可选参数来配置的。

例子:

scala> val rdd = sc.parallelize(Array(("a", 1), ("b", 1), ("a", 1))) 
rdd: org.apache.spark.rdd.RDD[(String, Int)] = ParallelCollectionRDD[19] at parallelize at <console>:28

scala> rdd.reduceByKey(_ + _).collect
res21: Array[(String, Int)] = Array((b,1), (a,2))

aggregateByKey

定义: aggregateByKey(zeroValue)(seqOp, combOp,[numTasks]) 实现:

def aggregateByKey[U: ClassTag](zeroValue: U)(seqOp: (U, V) => U,
    combOp: (U, U) => U): RDD[(K, U)] = self.withScope {
  aggregateByKey(zeroValue, defaultPartitioner(self))(seqOp, combOp)
}

这个函数比较复杂,其实他是对groupByKey与reduceByKey一种更加灵活的补充。 首先zeroValue用来定义一个初始值,以及通过zeroValue的类型确定最终返回的键值对的U的类型 seqOp函数,它作用于每个单独的分区中,用来合并相同key的,只是合并的时候给了一个初始化值zeroValue进行合并 combOp函数,它作用于所有的分区,针对第一步seqOp合并好的数据,进一步通过combOp进行合并,它没有初始化值

具体还是看例子: 以下例子来自于http://www.cnblogs.com/one--way/p/6006296.html 例子:

import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkContext, SparkConf}

/**
  * Created by Edward on 2016/10/27.
  */
object AggregateByKey {
  def main(args: Array[String]) {
    val sparkConf: SparkConf = new SparkConf().setAppName("AggregateByKey")
      .setMaster("local")
    val sc: SparkContext = new SparkContext(sparkConf)

    val data = List((1, 3), (1, 2), (1, 4), (2, 3))
    var rdd = sc.parallelize(data,2)//数据拆分成两个分区

    //合并在不同partition中的值,a,b的数据类型为zeroValue的数据类型
    def comb(a: String, b: String): String = {
      println("comb: " + a + "\t " + b)
      a + b
    }
    //合并在同一个partition中的值, a的数据类型为zeroValue的数据类型,b的数据类型为原value的数据类型
    def seq(a: String, b: Int): String = {
      println("seq: " + a + "\t " + b)
      a + b
    }

    rdd.foreach(println)
    
    //zeroValue 中立值,定义返回value的类型,并参与运算
    //seqOp 用来在一个partition中合并值的
    //comb 用来在不同partition中合并值的
    val aggregateByKeyRDD: RDD[(Int, String)] = rdd.aggregateByKey("100")(seq,comb)

    //打印输出
    aggregateByKeyRDD.foreach(println)
  

    sc.stop()
  }
}

输出说明:

 /*
将数据拆分成两个分区

//分区一数据
(1,3)
(1,2)
//分区二数据
(1,4)
(2,3)

//分区一相同key的数据进行合并
seq: 100     3   //(1,3)开始和中立值进行合并  合并结果为 1003
seq: 1003     2   //(1,2)再次合并 结果为 10032

//分区二相同key的数据进行合并
seq: 100     4  //(1,4) 开始和中立值进行合并 1004
seq: 100     3  //(2,3) 开始和中立值进行合并 1003

将两个分区的结果进行合并
//key为2的,只在一个分区存在,不需要合并 (2,1003)
(2,1003)

//key为1的, 在两个分区存在,并且数据类型一致,合并
comb: 10032     1004
(1,100321004)

* */

sortByKey

对(K,V)键值对的datadaset进行排序,这里K必须实现Ordered特质(这样的话K可以重写排序规则) 降序,sortByKey(false) 升序,sortByKey(true)

例子:

scala> val rdd = sc.parallelize(Array("hello","this","is","sort","test"))
rdd: org.apache.spark.rdd.RDD[String] = ParallelCollectionRDD[21] at parallelize at <console>:28

scala> val rdd2 = rdd.map(x => (x.length, x))
rdd2: org.apache.spark.rdd.RDD[(Int, String)] = MapPartitionsRDD[22] at map at <console>:30

scala> rdd2.collect
res22: Array[(Int, String)] = Array((5,hello), (4,this), (2,is), (4,sort), (4,test))

scala> rdd2.sortByKey(true)   #升序
res23: org.apache.spark.rdd.RDD[(Int, String)] = ShuffledRDD[25] at sortByKey at <console>:33

scala> rdd2.sortByKey(true).collect
res24: Array[(Int, String)] = Array((2,is), (4,sort), (4,test), (4,this), (5,hello))

scala> rdd2.sortByKey(false).collect   #降序
res25: Array[(Int, String)] = Array((5,hello), (4,sort), (4,test), (4,this), (2,is))

sortBy (补充)

对(K,V)键值对的dataset进行排序,可以对V进行排序 降序,sortBy(false) 升序,sortBy(true)

scala> val rdd = sc.parallelize(Array("hello","this","is","sort","test"))
rdd: org.apache.spark.rdd.RDD[String] = ParallelCollectionRDD[21] at parallelize at <console>:28

scala>  val rdd2 = rdd.map(x => (x, x.length))  #注意,这里跟上面的例子不一样,长度作为V而不是K了
rdd2: org.apache.spark.rdd.RDD[(String, Int)] = MapPartitionsRDD[32] at map at <console>:30

scala> rdd2.collect   #注意,这里跟上面的例子不一样,长度作为V而不是K了
res26: Array[(String, Int)] = Array((hello,5), (this,4), (is,2), (sort,4), (test,4))

scala> rdd2.sortBy(_._2,true).collect  #根据V升序排列
res28: Array[(String, Int)] = Array((is,2), (sort,4), (test,4), (this,4), (hello,5))

scala> rdd2.sortBy(_._2,false).collect   #根据V降序排列
res29: Array[(String, Int)] = Array((hello,5), (sort,4), (test,4), (this,4), (is,2))

join

对(K,V)键值对的dataset和(K, W)键值对的data进行join操作,返回一个(K, (V, W))键值对的dataset 相当于inner join。对两个需要连接的RDD进行cogroup,然后对每个key下面的list进行笛卡尔积的操作,输出两两相交的两个集合作为value。 相当于sql中where a.key=b.key。

例子:

scala> val rdd1 = sc.parallelize(Array((1,"a"),(2,"b"),(3,"c")))
rdd1: org.apache.spark.rdd.RDD[(Int, String)] = ParallelCollectionRDD[48] at parallelize at <console>:28

scala> val rdd2 = sc.parallelize(Array((2,"d"),(3,"e"),(4,"f")))
rdd2: org.apache.spark.rdd.RDD[(Int, String)] = ParallelCollectionRDD[49] at parallelize at <console>:28

scala> rdd1.join(rdd2).collect   #inner join
res30: Array[(Int, (String, String))] = Array((2,(b,d)), (3,(c,e)))

scala> rdd1.leftOuterJoin(rdd2).collect  #补充,leftOuterJoin
res31: Array[(Int, (String, Option[String]))] = Array((2,(b,Some(d))), (1,(a,None)), (3,(c,Some(e))))

scala> rdd1.rightOuterJoin(rdd2).collect   #补充,rightOuterJoin
res32: Array[(Int, (Option[String], String))] = Array((4,(None,f)), (2,(Some(b),d)), (3,(Some(c),e)))

cogroup

当对(K, V) 和 (K, W)的两个dataset进行cogroup,返回(K, Iterable,Iterable) tuples的dataset,相同的key被合并在一起,也叫做groupWith 例子:

scala> val rdd1 = sc.parallelize(Array((1,"a"),(2,"b"),(3,"c")))
rdd1: org.apache.spark.rdd.RDD[(Int, String)] = ParallelCollectionRDD[48] at parallelize at <console>:28

scala> val rdd2 = sc.parallelize(Array((2,"d"),(3,"e"),(3,"x"),(4,"f")))
rdd2: org.apache.spark.rdd.RDD[(Int, String)] = ParallelCollectionRDD[61] at parallelize at <console>:28

scala> rdd1.cogroup(rdd2).collect   # rdd1 和 rdd2的数据都出来的,同时相同的key的value被封装在一个CompactBuffer中
res34: Array[(Int, (Iterable[String], Iterable[String]))] = Array((4,(CompactBuffer(),CompactBuffer(f))), (2,(CompactBuffer(b),CompactBuffer(d))), (1,(CompactBuffer(a),CompactBuffer())), (3,(CompactBuffer(c),CompactBuffer(e, x))))

cartesian

相当于笛卡尔积

scala> val rdd1 = sc.parallelize(Array((1,"a"),(2,"b"),(3,"c")))
rdd1: org.apache.spark.rdd.RDD[(Int, String)] = ParallelCollectionRDD[48] at parallelize at <console>:28

scala> val rdd2 = sc.parallelize(Array((2,"d"),(3,"e"),(3,"x"),(4,"f")))
rdd2: org.apache.spark.rdd.RDD[(Int, String)] = ParallelCollectionRDD[61] at parallelize at <console>:28

scala> rdd1.cartesian(rdd2).collect  #返回12个元素,就是rdd1的3个乘以rdd2的4个
res36: Array[((Int, String), (Int, String))] = Array(((1,a),(2,d)), ((1,a),(3,e)), ((1,a),(3,x)), ((1,a),(4,f)), ((2,b),(2,d)), ((2,b),(3,e)), ((3,c),(2,d)), ((3,c),(3,e)), ((2,b),(3,x)), ((2,b),(4,f)), ((3,c),(3,x)), ((3,c),(4,f)))

pip

pipe(command, [envVars]) 通过管道将rdd的数据写入到一个shell 的命令中,返回一个RDD的字符串,通常是调用第三方的脚本。

coalesce

定义: def coalesce(numPartitions: Int, shuffle: Boolean = false)(implicit ord: Ordering[T] = null): RDD[T]

该函数用于将RDD进行重分区,使用HashPartitioner。

第一个参数为重分区的数目,第二个为是否进行shuffle,默认为false;

例子:

scala> var data = sc.textFile("/tmp/lxw1234/1.txt")
data: org.apache.spark.rdd.RDD[String] = MapPartitionsRDD[53] at textFile at :21
 
scala> data.collect
res37: Array[String] = Array(hello world, hello spark, hello hive, hi spark)
 
scala> data.partitions.size
res38: Int = 2  //RDD data默认有两个分区
 
scala> var rdd1 = data.coalesce(1)
rdd1: org.apache.spark.rdd.RDD[String] = CoalescedRDD[2] at coalesce at :23
 
scala> rdd1.partitions.size
res1: Int = 1   //rdd1的分区数为1
 
 
scala> var rdd1 = data.coalesce(4)
rdd1: org.apache.spark.rdd.RDD[String] = CoalescedRDD[3] at coalesce at :23
 
scala> rdd1.partitions.size
res2: Int = 2   //如果重分区的数目大于原来的分区数,那么必须指定shuffle参数为true,//否则,分区数不便
 
scala> var rdd1 = data.coalesce(4,true)
rdd1: org.apache.spark.rdd.RDD[String] = MapPartitionsRDD[7] at coalesce at :23
 
scala> rdd1.partitions.size
res3: Int = 4

repartition

定义: def repartition(numPartitions: Int)(implicit ord: Ordering[T] = null): RDD[T]

该函数其实就是coalesce函数第二个参数为true的实现

scala> var rdd2 = data.repartition(1)
rdd2: org.apache.spark.rdd.RDD[String] = MapPartitionsRDD[11] at repartition at :23
 
scala> rdd2.partitions.size
res4: Int = 1
 
scala> var rdd2 = data.repartition(4)
rdd2: org.apache.spark.rdd.RDD[String] = MapPartitionsRDD[15] at repartition at :23
 
scala> rdd2.partitions.size
res5: Int = 4

repartitionAndSortWithinPartitions

使用repartitionAndSortWithinPartitions替代repartition与sort类操作 repartitionAndSortWithinPartitions是Spark官网推荐的一个算子,官方建议,如果需要在repartition重分区之后,还要进行排序,建议直接使用repartitionAndSortWithinPartitions算子。因为该算子可以一边进行重分区的shuffle操作,一边进行排序。shuffle与sort两个操作同时进行,比先shuffle再sort来说,性能可能是要高的。

scala> val data = sc.parallelize(List((1,3),(1,2),(5,4),(1, 4),(2,3),(2,4)),3)
data: org.apache.spark.rdd.RDD[(Int, Int)] = ParallelCollectionRDD[3] at parallelize at <console>:21

scala> data.repartitionAndSortWithinPartitions(new HashPartitioner(3)).collect
res3: Array[(Int, Int)] = Array((1,4), (1,3), (1,2), (2,3), (2,4), (5,4))

Actions

reduce

reduce将RDD中元素两两传递给输入函数,同时产生一个新的值,新产生的值与RDD中下一个元素再被传递给输入函数直到最后只有一个值为止。

例子:

scala> val c = sc.parallelize(1 to 10)
scala> c.reduce((x, y) => x + y)
res4: Int = 55

collect

将rdd作为一个Array返回到driver端,注意:rdd如果太大会造成内存溢出问题

例子: rdd.collect

count

统计dataset的个数

例子: rdd.count

first

返回dataset的第一个元素,类似于take(1)

例子:

scala> rdd1.first
res44: (Int, String) = (1,a)

take

返回前n个元素的列表

例子:

scala> rdd1.take(1)   #这里返回的是一个数组,跟first有点区别
res45: Array[(Int, String)] = Array((1,a))

scala> rdd1.take(2)
res46: Array[(Int, String)] = Array((1,a), (2,b))

takeSample

取样,跟sample类似

takeSample函数类似于sample函数,该函数接受三个参数,第一个参数withReplacement ,表示采样是否放回,true表示有放回的采样,false表示无放回采样;第二个参数num,表示返回的采样数据的个数,这个也是takeSample函数和sample函数的区别;第三个参数seed,表示用于指定的随机数生成器种子。另外,takeSample函数先是计算fraction,也就是采样比例,然后调用sample函数进行采样,并对采样后的数据进行collect(),最后调用take函数返回num个元素。注意,如果采样个数大于RDD的元素个数,且选择的无放回采样,则返回RDD的元素的个数。

例子:

scala> rdd1.takeSample(false, 4, Random.nextInt())
res47: Array[(Int, String)] = Array((2,b), (3,c), (1,a))

takeOrdered

定义: def takeOrdered(num: Int): JList[T] def takeOrdered(num: Int, comp: Comparator[T]): JList[T]

takeOrdered函数用于从RDD中,按照默认(升序)或指定排序规则,返回前num个元素。 从源码分析可以看出,利用mapPartitions在每个分区里面进行分区排序,每个分区局部排序只返回num个元素,这里注意返回的mapRDDs的元素是BoundedPriorityQueue优先队列,再针对mapRDDs进行reduce函数操作,转化为数组进行全局排序。

例子:

//注意comparator需要序列化
public static class TakeOrderedComparator implements Serializable,Comparator<Integer>{    
    @Override    
    public int compare(Integer o1, Integer o2) {        
      return -o1.compareTo(o2);    
    }
}
List<Integer> data = Arrays.asList(5, 1, 0, 4, 4, 2, 2);
JavaRDD<Integer> javaRDD = javaSparkContext.parallelize(data, 3);
System.out.println("takeOrdered-----1-------------" + javaRDD.takeOrdered(2));
List<Integer> list = javaRDD.takeOrdered(2, new TakeOrderedComparator());
System.out.println("takeOrdered----2--------------" + list);

saveAsTextFile

把dataset写成一个textFile,可以是在本地,hdfs,等hadoop支持的文件系统。会对dataset的每一个元素调用toString方法来写成一行行数据

例子:

#注意,这里指定的path是一个文件夹,每个partition会在path下生成一个文件
scala> rdd.saveAsTextFile("/tmp/spark") # 默认写在hdfs上,可以不加hdfs://
                                                                                
scala> rdd.saveAsTextFile("file:///tmp/spark") # 写本地,要加上file://不过是生成在运行container的机器上

saveAsSequenceFile

跟saveAsTextFile类似,把dataset写成hadoop的SequenceFile文件,注意,这里必须的KV对必须都是实现了hadoop 的 Writable接口的。另外spark已经隐式转换了一些基础类型为Writable类型的,比如Int, Double, String 等,所以这些是不需要手动实现Writable了

saveAsObjectFile

类似saveAsTextFile,写成一个java序列化后的文件,可以通过SparkContext.objectFile()来反序列化得到rdd

countByKey

只在K,V类型的RDD使用,返回一个(K,Int)的map,表示每个Key的个数

例子:

scala> rdd1.collect
res54: Array[(Int, String)] = Array((1,a), (2,b), (3,c))                          

scala> rdd1.countByKey
res55: scala.collection.Map[Int,Long] = Map(2 -> 1, 1 -> 1, 3 -> 1)   

foreach

对dataset的每个元素进行循环,调用自定义的func

例子:

scala> rdd.collect
res59: Array[String] = Array(hello, this, is, sort, test)

scala> rdd.collect.foreach(println)
hello
this
is
sort
test

转载于:https://my.oschina.net/OttoWu/blog/855499

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值