Spark之RDD使用詳解

一、創建

1.外部數據源

(1)讀取win讀取win (讀取多個文件)

val conf=new SparkConf().setAppName("New Test").setMaster("local")
val sc=new SparkContext(conf)

val readText=sc.textFile("D:\\example\\1.txt,D:\\example\\2.txt")
val result=readText.saveAsTextFile("D:\\all\\result")

(2)加載HDFS保存Linux (含通配符的路徑)

  val conf=new SparkConf().setAppName("wordcount")
  val sc=new SparkContext(conf)

  val input=sc.textFile("hdfs://master:9000/hive/*.txt")
  val lines=input.flatMap(line=>line.split(" "))
  val count=lines.map(word=>(word,1)).reduceByKey{case (x,y)=>x+y}
  val output=count.saveAsTextFile("file:///data1/test/result")

(3)加載HDFS保存HDFS

  val conf=new SparkConf().setAppName("cal_wel")
  val sc=new SparkContext(conf)

  val rdd=sc.textFile("hdfs://master:9000/hive/order_20200105.txt");
  val rdd1=rdd.map(line=>(line.split("\t")(1),1)).reduceByKey((x,y)=>x+y)
  rdd1.repartition(1).saveAsTextFile("hdfs://master:9000/tmp/result")

二、算子

1.Transformation

map(func) 返回一個新RDD。該RDD由每一個輸入元素經過func函數轉換後組成
filter(func) 返回一個新RDD。該RDD由經過func函數計算後返回值爲true的輸入元素組成
flatMap(func) 類似map,但每一個輸入元素可以被映射爲0或多個輸出元素

distinct([numTasks])

對源RDD進行去重後返回一個新RDD
union(otherDataset) 對源RDD和參數RDD求並集後返回一個新RDD
join(otherDataset,[numTasks]) 在類型爲(K,V)和(K,W)的RDD上調用,返回一個相同key對應的所有元素對在一起的(K,(V,W))的RDD,相當於內連接
leftOuterJoin 類上,左連接
rightOuterJoin 類上,右連接
groupByKey([numTasks]) 在一個(K,V)的RDD上調用,返回一個(K,Iterator[V])的RDD
reduceByKey(func,[numTasks]) 在一個(K,V)的RDD上調用,返回一個(K,V)的RDD,使用指定迭代reduce函數,將相同key的值聚合到一起,與groupBy類似。reduce任務的個數可以通過第2個可選參數來設置
sortByKey([ascending],[numTasks]) 在一個(K,V)的RDD上,K必須實現Ordered接口,返回一個按照key進行排序的(K,V)的RDD
combineByKey 合併相同的key值,將RDD[K,V]轉化爲RDD[K,C]
mapValues(func) 在一個(K,V)的RDD上,key不變,對每個value都應用func函數
persist RDD緩存,可避免重複計算從而減少時間,可選擇緩存級別
cache RDD緩存,可避免重複計算從而減少時間,cache內部調用了persist算子,cache摩恩只有一個緩存級別MEMORY-ONLY
sample(withReplacement,fraction,seed) 根據fraction指定的比例對數據進行採樣,可以選擇是否使用隨機數進行替換,seed用於指定隨機數生成器種子
coalesce(numPartitions,shuffle) 重新分區。第1個參數分爲多少區,第2個參數是否shuffle
repartition(numPartitions) 重新分區,調用coalesce且第2個參數爲true的實現

2.Action

collect 返回RDD中的所有元素 rdd.collect()
foreach(func) 對RDD中的每個元素使用給定的函數 rdd.foreach(func)
count RDD中的元素個數 rdd.count()
reduce(func) 並行整合RDD中所有元素 rdd.reduce((x,y)=>x+y)
take(num) 從RDD中返回前num個元素 rdd.take(2)
takeSample(withReplacement, num, [seed]) 從RDD返回任意一些元素 rdd.takeSample(false, 1)
top(num) 從RDD中返回最前面的num個元素 rdd.top(2)
countByValue 各元素在RDD中出現的次數  rdd.countByValue()
takeOrdered(num) 從RDD中按照提供的順序返回最前面的num個元素 rdd.takeOrdered(2)
fold(0)(func) 和reduce一樣,但需要提供初始值 rdd.fold(0)((x,y)=> x+y)
aggregate(zeroValue)(seqOp, combOp) 類似reduce,但通常返回不同類型函數 rdd.aggregate((0,0))(      (x,y)=>(x._1+y,x._2+1),      (x,y)=>(x._1+y._1,x._2+y._2))
first 返回第1個元素 rdd.first()
sum 總和 rdd.sum()

三、應用

1.map

       對RDD中的每個元素都執行一個指定的函數來產生一個新的RDD。

       返回值:RDD

  • 示例
  def map1(sc:SparkContext):Unit={
     val rdd=sc.parallelize(List(1,2,3,4))
     val rdd1=rdd.map(line=>line+1)
     rdd1.foreach(println)
  }

  def map2(sc:SparkContext):Unit={
     val rdd=sc.parallelize(List(("spark",0),("hadoop",10),("hadoop",4),("spark",4)))
     val mapRdd=rdd.map(line=>(line,1))
     mapRdd.foreach(println)
  }

  def map3(sc:SparkContext):Unit={
     val rdd=sc.textFile("E:\\data\\spark\\rdd\\test\\read\\movies.csv")
     val arr=rdd.map(line=>line.split(",")).collect()
     for(i <- 0 to 2){
       for(j <- 0 to 2){
          print(arr(i)(j)+"\t")
       }
       println()
     }
  }

2.filter

       對RDD元素進行過濾,返回一個新的數據集。(經過func函數後返回值爲true的原元素組成)

       返回值:RDD

  • 示例
  def filter1(sc:SparkContext):Unit={
     val rdd=sc.textFile("E:\\data\\spark\\rdd\\test\\read\\movies.csv")
     val filterRdd=rdd.filter(line=>line.contains("Drama"))
     filterRdd.foreach(println)
  }

  def filter2(sc:SparkContext):Unit={
    val rdd=sc.parallelize(List(1,2,3,7,4,5,8))
    val filterRdd=rdd.filter(x=>x>=4)
    filterRdd.foreach(println)
  }

3.flatMap

        類似map,但對每一個輸入元素,會被映射爲0到多個輸出元素

        而mapPartitions的輸入函數是每個分區的數據,也就是把每個 分區的內容作爲整體來處理的。

  • 示例
​
  def flatMap1(sc:SparkContext):Unit={
    val rdd=sc.parallelize(1 to 10,3)
    rdd.foreach(println)
  }


  def flatMap2(sc:SparkContext):Unit={
    val rdd=sc.parallelize(Array(("A",1),("B",2),("C",3)))
    rdd.flatMap(x=>(x._1+x._2)).foreach(println)
  }

4.mapPartitions

        mapPartitions是map的一個變種。可看作先對RDD進行partition,再把每個partition進行map函數。

        map的輸入函數是應用於RDD中每個元素,而mapPartitions的輸入函數是每個分區的數據。

        即把每個分區中的內容作爲整體來處理的

  • 應用場景
當數據量不太大的時候,可以用mapPartitions,可以提高運行效率;
當數據量太大的時候,有可能會發生oom
  • 示例
  def mapPartitions1(sc:SparkContext):Unit={
    val rdd=sc.parallelize(Array(1,2,3,4,5,6), 2)
    val mapPartitionsRdd=rdd.mapPartitions(_.map(_+1))
    mapPartitionsRdd.foreach(println)
  }

  
  def doubleFunc(iter:Iterator[Int]): Iterator[(Int,Int)]={
    var res=List[(Int,Int)]()
    while(iter.hasNext){
      val cur=iter.next
      res.::=(cur, cur*2)
    }
    res.iterator
  }
  def mapPartitions2(sc:SparkContext):Unit={
    val rdd=sc.parallelize(1 to 9, 3)
    val mapPartitionsRdd=rdd.mapPartitions(doubleFunc)
    println(mapPartitionsRdd.collect().mkString)
  }

  
  def menaFunc(iter:Iterator[Int]):Iterator[(Int,Int)]={
    var x,y=0
    var res=List[(Int,Int)]()
    while(iter.hasNext){
      val cur=iter.next
      x+=cur
      y+=1
    }
    res.::=(x,y)
    res.iterator
  }
  def reduceFunc(x:(Int,Int),y:(Int,Int)):(Int,Int)={
    (x._1+y._1, x._2+y._2)
  }
  def mapPartitions3(sc:SparkContext):Unit={
    val rdd=sc.parallelize(List(1,2,3,4),3)
    val sum=rdd.mapPartitions(menaFunc).reduce(reduceFunc)
    println(sum._1/sum._2.asInstanceOf[Float])
  }

5.mapPartitionsWithIndex

        mapPartitionsWithSplit與mapPartitions的功能類似,只是多傳入split index而已。

        所有func函數必須是(Int,Iterator<T>)=>Iterator<U>類型

  • 示例
  def func(index:Int, it:Iterator[Int]):Iterator[String]={
    it.map(x=>s"part:$index, ele:$x")
  }
  def mapPartitionsWithIndex1(sc:SparkContext):Unit={
    val rdd=sc.parallelize(List(1,2,3,4,5,6),2)
    val mapPartitionsWithIndexRdd=rdd.mapPartitionsWithIndex(func)
    mapPartitionsWithIndexRdd.foreach(println)
  }

  def mapPartitionsWithIndex2(sc:SparkContext):Unit={
    val rdd=sc.parallelize(Array("tom1","tom2","tom3","tom4","tom5","tom6"),3)
    val mapPartitionsWithIndexRdd=rdd.mapPartitionsWithIndex((index,x)=>{
      val list=ListBuffer[String]()
      while(x.hasNext){
        list+="part:"+index+", ele:"+x.next
      }
      list.iterator
    })
    mapPartitionsWithIndexRdd.foreach(println)
  }

6.sample

        sample (withReplacement,fraction,seed)是根據給定的隨機種子seed,隨機抽樣出數量爲frac的數據。

        withReplacement:是否放回抽樣

        fraction:比例。比如0.1表示10%

        seed:隨機種子

        返回值:RDD

  • 示例
  def sample1(sc:SparkContext):Unit={
    val rdd=sc.parallelize(List(2,3,7,4,8))
    val sampleRdd=rdd.sample(false,0.5)
    sampleRdd.foreach(println)
  }

  def sample2(sc:SparkContext):Unit={
    val rdd=sc.parallelize(List(2,3,7,4,8))
    val sampleRdd=rdd.sample(true,2)
    sampleRdd.foreach(println)
  }

  def sample3(sc:SparkContext):Unit={
    val rdd=sc.makeRDD(List(1,2,3,7,4,5,8))
    val sampleRdd=rdd.sample(false,0.25,System.currentTimeMillis())
    sampleRdd.foreach(println)
  }

7.union

        union(otherDataset)是數據合併,返回一個新的數據集,又原數據集和otherDataset聯合而成。

        返回值:RDD

  • 示例
  def union1(sc:SparkContext):Unit={
    val rdd1=sc.makeRDD(List("張三","李四"))
    val rdd2=sc.makeRDD(List("tom","marry"))
    val unionRdd=rdd1.union(rdd2)
    unionRdd.foreach(println)
  }

8.intersection

        intersection(otherDataset)是數據交集,返回一個新的數據集。(兩個數據集的交集數據)。

        返回值:RDD

  • 示例
  def intersection1(sc:SparkContext):Unit={
    val rdd1=sc.makeRDD(List("張三","李四","王五","tom"))
    val rdd2=sc.makeRDD(List("tom","lilei"))
    val intersectionRdd=rdd1.intersection(rdd2)
    intersectionRdd.foreach(println)
  }

9.distinct

        distinct([numTasks])是數據去重,返回一個數據集,是對連個數據集去除重複數據

        numTasks是設置任務並行數量

  • 示例
  def distinct1(sc:SparkContext):Unit={
    val rdd=sc.parallelize(List("張三","李四","王五","李四","王五"))
    val distinctRdd=rdd.distinct()
    distinctRdd.foreach(println)
  }

10.groupByKey

          groupByKey([numTasks])是數據分組操作,在一個由(K,V)對組成的數據集上調用,返回一個(K,Seq[V])對的數據集。

          返回值:RDD[ Tuple2[K,Iterable[V]] ]

  • 示例
def groupByKey1(sc:SparkContext):Unit={
    val rdd=sc.parallelize(Array("one","two","three","three","three","one"))
    val mapRdd=rdd.map(line=>(line,1))
    val groupByKeyRdd=mapRdd.groupByKey()
    groupByKeyRdd.foreach(println)
  }

  def groupByKey2(sc:SparkContext):Unit={
    val rdd=sc.parallelize(Array(("A",0),("A",2),("B",1),("B",8),("C",3)))
    val groupByKeyRdd=rdd.groupByKey()
    groupByKeyRdd.foreach(println)
  }

11.reduceByKey

         reduceByKey(func,[numTasks])是一個(K,V)對的數據集上使用,返回一個(K,V)的數據集。

         key相同的值,都被使用指定的reduce函數聚合到一起。

         返回值:RDD[ Tuple2[K, V] ]

  • 示例
  def reduceByKey1(sc:SparkContext):Unit={
    val rdd=sc.makeRDD(Array(("A",0),("A",2),("B",3),("B",4),("C",6)))
    val reduceByKeyRdd=rdd.reduceByKey((x,y)=>x+y)
    reduceByKeyRdd.foreach(println)
  }

  def reduceByKey2(sc:SparkContext):Unit={
    val rdd=sc.textFile(Constant.LoCAL_FILE_PREX+"/data/rdd/wordData.log")
    println(Constant.LoCAL_FILE_PREX)
    val reduceByKeyRdd=rdd.flatMap(line=>line.split("\\s+")).map(x=>(x,1)).reduceByKey((x,y)=>x+y)
    reduceByKeyRdd.foreach(println)
  }

12.aggreateByKey

        aggreateByKey和reduceByKey的不同之處在於,reduceByKey輸入輸出都是(K,V),而aggreateByKey輸出是(K,U)

        aggreateByKey的3個參數:

            zeroValue:U,初始值,比如空列表{}

            seqOp:(U,T)=>U,seq操作符,描述如何將T合併如U,比如如何將item合併到列表

            combOp:(U,T)=>U,comb操作符,描述如何合併兩個U,比如合併兩個列表

        所以aggreateByKey可以看成更高抽象的,更靈活的reduce或group

  • 示例
  def aggregateByKey1(sc:SparkContext):Unit={
    val rdd=sc.parallelize(List(("cat",3), ("cat", 1), ("mouse", 4), ("dog", 9), ("mouse", 2)),2)
    val aggregateByKeyRdd=rdd.aggregateByKey(100)(_+_, _+_)
    aggregateByKeyRdd.foreach(println)
  }

  def combOp(a:List[Int], b:List[Int]):List[Int]={
    a.:::(b)
  }
  def seqOp(a:List[Int], b:Int):List[Int]={
    a.::(b)
  }
  def aggregateByKey2(sc:SparkContext):Unit={
    val rdd=sc.parallelize(List((1,3),(1,2),(1,4),(2,3)))
    val aggregateByKeyRdd=rdd.aggregateByKey(List[Int]())(seqOp,combOp)
    aggregateByKeyRdd.foreach(println)
  }

13.combineByKey

       對RDD中的數據集按照Key進行聚合操作,聚合操作的邏輯是通過自定義函數提供給combineByKey。

  • 參數
combineByKey[C](createCombiner: (V) ⇒ C, mergeValue: (C, V) ⇒ C, mergeCombiners: (C, C) ⇒ C, numPartitions: Int):RDD[(K, C)]


(1) combinByKey會遍歷rdd中每一個(k,v)數據對,對該數據對中的k進行判斷,判斷該(k,v)對中的k是否在之前出現過,如果是第一次出現,則調用createCombiner函數,對該k對應的v進行初始化操作

(2)作用在每一個分區內部,將V合併到之前(createCombiner)的元素上

(3)當所有的分區內的數據計算完成之後,開始調用mergeCombiners函數,對每個分區的數據進行合併
  • 示例
  def combineByKey1(sc:SparkContext):Unit={
    val rdd=sc.makeRDD(Array(("A",1),("A",2),("B",3),("B",4),("C",6)))
    val combineByKeyRdd=rdd.combineByKey((v:Int)=>v+"-",(c:String,v:Int)=>c+"@"+v,(c1:String,c2:String)=>c1+"$"+c2)
    combineByKeyRdd.foreach(println)
  }

  def combineByKey2(sc:SparkContext):Unit={
    val rdd=sc.parallelize(Array((1, 1.0), (1, 2.0), (1, 3.0), (2, 4.0), (2, 5.0), (2, 6.0)))
    val combineByKeyRdd=rdd.combineByKey((v:Double)=>(v,1), (c:(Double,Int),v:Double)=>(c._1+v,c._2+1),(c1:(Double,Int),c2:(Double,Int))=>(c1._1+c2._1, c1._2+c2._2))
    combineByKeyRdd.foreach(println)
  }

  def combineByKey3(sc:SparkContext):Unit={
    val rdd=sc.parallelize(List(("A", 3), ("A", 9), ("A", 12),("B", 4), ("B", 10), ("B", 11)), 2)
    val combineByKeyRdd=rdd.combineByKey(
      (x:Int)=>(x,1),
      (acc:(Int,Int), x)=>(acc._1+x, acc._2+1),
      (p1:(Int,Int), p2:(Int,Int))=> (p1._1+p2._1, p1._2+p2._2)
    )
    combineByKeyRdd.foreach(println)
  }

  def combineByKey4(sc:SparkContext):Unit={
    val rdd=sc.parallelize(Array(("coffee",1), ("coffee",2), ("panda",3), ("coffee",9)))
    val combineByKeyRdd=rdd.combineByKey(score=>(1,score), (c:(Int,Int),newScore:Int)=>(c._1+1,c._2+newScore), (c1:(Int,Int),c2:(Int,Int))=>(c1._1+c2._1,c1._2+c2._2))
    val averageRdd=combineByKeyRdd.map{
      //case(key,value)=>(key,value._2/value._1)
      case(name,(num,score))=>(name,score/num)
    }
    averageRdd.foreach(println)
  }

  def combineByKey5(sc:SparkContext):Unit={
    val rdd=sc.parallelize(Array((("1","011"),1), (("1","012"),1), (("2","011"),1), (("2","013"),1), (("2","014"),1)))
    val combineByKeyRdd=rdd.map(x=>(x._1._1, (x._1._2,1))).combineByKey(
      (v:(String,Int))=> (v:(String,Int)),
      (acc:(String,Int), v:(String,Int))=> (acc._1+":"+v._1, acc._2+v._2),
      (p1:(String,Int), p2:(String,Int))=> (p1._1+":"+p2._1, p1._2+p2._2)
    )
    combineByKeyRdd.foreach(println)
  }

14.sortByKey

       sortByKey([ascending],[numTasks])是排序操作,對(K,V)類型的數據按照K進行排序,其中K需要實現Ordered方法

       返回值:RDD[ Tuple2[K, V] ]

  • 示例
  def sortByKey1(sc:SparkContext):Unit={
    val rdd=sc.makeRDD(List((60,"張三"), (70,"李四"), (80,"王五"), (55,"趙六"), (45,"郭七"), (75,"林八")))
    val sortByKeyRdd=rdd.sortByKey()
    sortByKeyRdd.foreach(println)
  }

  def sortByKey2(sc:SparkContext):Unit={
    val rdd=sc.makeRDD(List((60,"張三"), (70,"李四"), (80,"王五"), (55,"趙六"), (45,"郭七"), (75,"林八")))
    val sortByKeyRdd=rdd.sortByKey(false) //降序
    sortByKeyRdd.foreach(println)
  }

15.join

        join(otherDataset,[numTasks])是連接操作,講那個輸入數據集(K,V)和另外一個(K,W)進行join,得到(K,(V,W)

        該操作是對於相同K的V和W集合進行笛卡爾積操作,即V和W的所有組合

        連接操作除了join外,還有左連接leftOuterJoin、右連接rightOuterJoin、全連接fullOuterJoin

  • 示例
  def join1(sc:SparkContext):Unit={
    val productRdd=sc.parallelize(List((1,"蘋果"),(2,"梨"),(3,"香蕉"),(4,"石榴")))
    val countRdd=sc.parallelize(List((1,7),(2,3),(3,8),(4,3),(5,9)))
    val joinRdd=productRdd.join(countRdd)
    joinRdd.foreach(println)
  }

  def leftOuterJoin1(sc:SparkContext):Unit={
    val productRdd=sc.parallelize(List((1,"蘋果"),(2,"梨"),(3,"香蕉"),(4,"石榴")))
    val countRdd=sc.parallelize(List((1,7),(2,3),(3,8),(4,3),(5,9)))
    val joinRdd=productRdd.leftOuterJoin(countRdd)
    joinRdd.foreach(println)
  }

  def rightOuterJoin1(sc:SparkContext):Unit={
    val productRdd=sc.parallelize(List((1,"蘋果"),(2,"梨"),(3,"香蕉"),(4,"石榴")))
    val countRdd=sc.parallelize(List((1,7),(2,3),(3,8),(4,3),(5,9)))
    val joinRdd=productRdd.rightOuterJoin(countRdd)
    joinRdd.foreach(println)
  }

16.cogroup

        cogroup(otherDataset,[numTasks])是將輸入數據集(K,V)和另外一個數據集(K,W)進行congroup,得到一個格式爲(K,Seq[V],Seq[V])的數據集。

        返回值:RDD[ Tuple2[K, Tuple2[ Iterable[V], Iterable[W] ] ] ]

  • 示例
  def cogroup1(sc:SparkContext):Unit={
    val rdd1=sc.parallelize(Array((1,"a"),(2,"b"),(3,"c"),(4,"d")))
    val rdd2=sc.parallelize(Array((1,4),(2,5),(3,6)))
    val cogroupRdd=rdd1.cogroup(rdd2)
    cogroupRdd.foreach(println)
  }

17.cartesian

         cartesian(otherDataset)是做笛卡爾積:對於數據集T和U進行笛卡爾積操作,得到(T,U)格式的數據集

         返回值:RDD[ Tuple2[T, U] ]

  • 示例
  def cartesian1(sc:SparkContext):Unit={
    val rdd1=sc.parallelize(1 to 3)
    val rdd2=sc.parallelize(4 to 6)
    val cartesianRdd=rdd1.cartesian(rdd2)
    cartesianRdd.foreach(println)
  }

18.coalesce

       將RDD進行重分區

  • 示例
  /*
    def coalesce(numPartitions: Int, shuffle: Boolean = false)(implicit ord: Ordering[T] = null): RDD[T]
    參數1:重分區數目
    參數2: 是否進行shuffle,默認false
    功能:將RDD進行重分區,使用HashPartitioner
   */


  def coalesce1(sc:SparkContext):Unit={
    val rdd=sc.textFile("E:\\data\\spark\\rdd\\test\\read\\ml-25m\\genome-scores.csv")
    println("分區數:"+rdd.partitions.size) //13
    val coalesceRdd=rdd.coalesce(2)//減少分區數
    println("新分區數:"+coalesceRdd.partitions.size) //2
    coalesceRdd.saveAsTextFile("E:\\data\\spark\\rdd\\test\\write\\ml-25m")//2
  }

  def coalesce2(sc:SparkContext):Unit={
    val rdd=sc.textFile("E:\\data\\spark\\rdd\\test\\read\\ml-25m\\genome-scores.csv")
    println("分區數:"+rdd.partitions.size) //13
    val coalesceRdd=rdd.coalesce(20,true)//將shuffle設爲true,增加分區數到200
    println("新分區數:"+coalesceRdd.partitions.size) //20
    coalesceRdd.saveAsTextFile("E:\\data\\spark\\rdd\\test\\write\\ml-25m")//20
  }

19.repartition

        將RDD進行重分區,即coalesce函數第2個參數爲true的實現

  • 示例
  def repartition1(sc:SparkContext):Unit={
    val rdd=sc.textFile("E:\\data\\spark\\rdd\\test\\read\\ml-25m\\genome-scores.csv")
    println(rdd.getNumPartitions)
    rdd.repartition(1).saveAsTextFile("E:\\data\\spark\\rdd\\test\\read\\ml-25m\\genome-scores")
  }

20.persist

       將RDD進行緩存(持久化),可避免重複計算從而減少時間

  • 源碼
def persist(newLevel: StorageLevel): this.type = {
  if (storageLevel != StorageLevel.NONE && newLevel != storageLevel) {
    throw new UnsupportedOperationException(
      "Cannot change storage level of an RDD after it was already assigned a level")
  }
  sc.persistRDD(this)
  sc.cleaner.foreach(_.registerRDDForCleanup(this))
  storageLevel = newLevel
  this
}
  • 緩存級別
參數1:useDisk   使用硬盤
參數2:useMemory 使用內存
參數3:useOffHeap使用堆外內存
參數4:反序列化
參數5:備份數

object StorageLevel {
  val NONE = new StorageLevel(false, false, false, false)
  val DISK_ONLY = new StorageLevel(true, false, false, false)
  val DISK_ONLY_2 = new StorageLevel(true, false, false, false, 2)
  val MEMORY_ONLY = new StorageLevel(false, true, false, true)
  val MEMORY_ONLY_2 = new StorageLevel(false, true, false, true, 2)
  val MEMORY_ONLY_SER = new StorageLevel(false, true, false, false)
  val MEMORY_ONLY_SER_2 = new StorageLevel(false, true, false, false, 2)
  val MEMORY_AND_DISK = new StorageLevel(true, true, false, true)
  val MEMORY_AND_DISK_2 = new StorageLevel(true, true, false, true, 2)
  val MEMORY_AND_DISK_SER = new StorageLevel(true, true, false, false)
  val MEMORY_AND_DISK_SER_2 = new StorageLevel(true, true, false, false, 2)
  val OFF_HEAP = new StorageLevel(false, false, true, false)
  ......
}

示例:
val MEMORY_AND_DISK_SER_2=new StorageLevel(true,true,false,false,2)
使用該緩存級別的RDD將存儲在硬盤以及內存中,使用序列化(在硬盤中),並且在多個節點上備份2份(正常的RDD只有1份)
  • 示例
  def persist1(sc:SparkContext):Unit={
    val rdd=sc.textFile("E:\\data\\spark\\rdd\\test\\read\\ml-25m\\genome-scores.csv")
    rdd.persist(StorageLevel.MEMORY_AND_DISK)
    val count1=rdd.count
    println("count1:"+count1) //耗時10636
    
    val count2=rdd.count
    println("count2:"+count2) //耗時279
    
    val count3=rdd.count
    println("count3:"+count3) //耗時264
  }

21.cache

        將RDD進行緩存(持久化)。內部調用persist,只有一個默認緩存級別MEMORY_ONLY

  • 示例
  def cache1(sc:SparkContext):Unit={
    val rdd=sc.textFile("E:\\data\\spark\\rdd\\test\\read\\ml-25m\\genome-scores.csv")
    rdd.cache()
    val count1=rdd.count
    println("count1:"+count1) //耗時10575
    
    val count2=rdd.count
    println("count2:"+count2) //耗時411
    
    val count3=rdd.count
    println("count3:"+count3) //耗時273
  }

三、Action操作

1.reduce

        reduce(func)是對數據集的所有元素執行聚集func函數,該函數必須是可交換的

        將RDD中元素兩兩傳遞給輸入函數,同時產生一個新值,新值與RDD中下一個元素再被傳遞給輸入函數直到最後一個值爲止

        返回值:T

  • 示例
  def reduce1(sc:SparkContext):Unit={
    val rdd=sc.makeRDD(List("a","ab","abc","abcd","abcde"))
    val reduceNum=rdd.map(x=>x.length).reduce((x,y)=>x+y)
    println(reduceNum)
  }

  def reduce2(sc:SparkContext):Unit={
    val rdd=sc.textFile("E:\\data\\spark\\rdd\\test\\read\\app1.log")
    val reduceNum=rdd.map(line=>line.split(" ").size).reduce((a,b)=> if(a>b) a else b)
    println(reduceNum)
  }

2.collect

      將一個RDD轉換爲數組

       返回值:Array[T]

  • 示例
  def collect1(sc:SparkContext):Unit={
    val rdd=sc.makeRDD(1 to 5,4)
    val collectArr=rdd.collect
    for(i <- collectArr)
      println(i)
  }

3.count

      返回數據集中元素的個數

      返回值:Long

  • 示例
  def count1(sc:SparkContext):Unit={
    val rdd=sc.parallelize(1 to 5)
    println(rdd.count())
  }

  def count2(sc:SparkContext):Unit={
    val rdd=sc.parallelize(Array(("A","1"),("B",2),("C",3)))
    val countNum=rdd.count
    println(countNum)
  }

4.first

      返回數據集中的第一個元素,類似take(1)

      返回值:T

  • 示例
  def first1(sc:SparkContext):Unit={
    val rdd=sc.parallelize(Array(5,4,8,3,0))
    println(rdd.first())
  }

  def first2(sc:SparkContext):Unit={
    val rdd=sc.parallelize(Array("a","ab","abc","abcd"))
    val firstMap=rdd.map(line=>(line,line.length)).first
    println(firstMap)
  }

5.take

      返回一個包含數據集中前n個元素的數組,當前該操作不能並行

      返回值:Array[T]

  • 示例
  def take1(sc:SparkContext):Unit={
    val rdd=sc.parallelize(Array(4,8,3,0,1,9))
    val takeRdd=rdd.take(2)
    takeRdd.foreach(println)
  }

  def take2(sc:SparkContext):Unit={
    val rdd=sc.parallelize(Array("a","ab","abc","abcd"))
    val takeRdd=rdd.map(line=>(line,line.length)).take(3)
    takeRdd.foreach(println)
  }

6.takeOrdered

     takeOrdered(n,[ordering])將RDD中的每個元素進行升序排序後取topN

     返回值:Array[T]

  • 示例
  def takeOrderedTest(sc:SparkContext):Unit={
    val rdd=sc.makeRDD(Seq(10,4,2,12,3,1))
    val takeOrderedRdd=rdd.takeOrdered(2)
    takeOrderedRdd.foreach(println)
  }

7.top

    將RDD中的每個元素進行降序排序後取topN

def top(num: Int)(implicit ord: Ordering[T]): Array[T] = withScope {
    takeOrdered(num)(ord.reverse)
}
  • 示例
  def top1(sc:SparkContext):Unit={
    val rdd=sc.makeRDD(Seq(10,4,2,12,3,1))
    val topRdd=rdd.top(2)
    topRdd.foreach(println)
  }

8.takeSample

     takeSample(withReplacement,num,[seed])返回包含隨機的num個元素的數組

     和Sample不同,takeSample是Action操作,因此返回的是數組而不是RDD

     withReplacement:是否有抽樣放回

     num:抽取多少個

     返回值:Array[T]

  • 示例
  def takeSample1(sc:SparkContext):Unit={
    val rdd=sc.makeRDD(1 to 10)
    val sampleRdd=rdd.takeSample(true,4) //有放回抽樣,採取數量4
    sampleRdd.foreach(println)
  }

9.saveAsTextFile

     把數據集中的元素寫到一個文本文件,Spark會對每個元素調用toString()方法把每個元素存成文本文件的一行

  • 示例
  def saveAsTextFile1(sc:SparkContext):Unit={
    val rdd=sc.makeRDD(Seq(("A",1),("B",2),("C",3),("D",4),("E",5),("F",6)),4)
    rdd.saveAsTextFile("E:\\data\\spark\\rdd\\test\\write\\saveAsTextFile")
  }

10.countByKey

      對於(K,V)類型的RDD,返回一個(K,Int)的map,Int爲K的個數

  • 示例
  def countByKey2(sc:SparkContext):Unit={
    val rdd=sc.parallelize(Array(("A","1"),("B",2),("C",3),("A",5)))
    val countByKeyRdd=rdd.countByKey
    countByKeyRdd.foreach(println)
  }

11.foreach

      foreach(func)是對數據集中的每個元素都執行func函數

  • 示例
  def foreach1(sc:SparkContext):Unit={
    val rdd=sc.parallelize(Array(("A","1"),("B",2),("C",3),("A",5)))
    rdd.foreach(println)
  }

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章