Spark的轉換操作基礎知識和一些使用技巧!!!

在閱讀完最早之前的帖子(點擊打開鏈接)說了如何理解RDD和什麼是RDD和對一些基礎的術語的解讀示例,然後我又發了一份如何創建RDD(點擊打開鏈接)我們這節課來學學習火花的一些對RDD的轉換操作,轉換操作就是不會真的進行分佈式計算,而是將RDD從一種狀態轉換到另外一種狀態,延遲計算,當一個RDD轉換成另一個RDD時並沒有立即進行轉換,僅僅是記住了數據集的邏輯操作,轉換操作大致分爲以下兩種形式我們着重介紹第一種

(1)非KV轉換操作即基礎轉換操作        

1.map(FUNC):數據集中的每個元素經過用戶自定義的函數轉換形成一個新的RDD 

對應圖解析

object Map {
  def main(args: Array[String]) {
    val conf = new SparkConf().setMaster("local").setAppName("map")
    val sc = new SparkContext(conf)
    val rdd = sc.parallelize(1 to 10)  //創建RDD
    val map = rdd.map(_*2)             //對RDD中的每個元素都乘於2
    map.foreach(x => print(x+" "))
    sc.stop()
  }
}

 

 

 

輸出結果:

2 4 6 8 10 12 14 16 18 20

2 .flatMap(func)與地圖類似,但每個元素輸入項都可以被映射到0個或多個的輸出項,最終將結果“扁平化”後輸出個人覺得所謂的扁平化處理就是對地圖之後的的單個集合在進行一次分散把RDD的數據變成不存在

對應圖解析:

實列

object Map {
  def main(args: Array[String]) {
    val conf = new SparkConf().setMaster("local").setAppName("map")
    val sc = new SparkContext(conf)
      val rdd = sc.parallelize(1 to 5)
   val fm = rdd.flatMap(x => (1 to x)).collect()
   fm.foreach( x => print(x + " ")))
    sc.stop()
  }
}    

輸出:
1 1 2 1 2 3 1 2 3 4 1 2 3 4 5
如果是map那麼他的輸出應該是:
Range(1) Range(1, 2) Range(1, 2, 3) Range(1, 2, 3, 4) Range(1, 2, 3, 4, 5)


 

3. mapPartitions(func):類似與地圖,地圖作用於每個分區的每個元素,但mapPartitions作用於每個分區工

func的類型:Iterator [T] =>迭代器[U]

假設有Ñ個元素,有中號個分區,那麼地圖的函數的將被調用Ñ次,而mapPartitions被調用中號次,當在映射的過程中不斷的創建對象時就可以使用mapPartitions比地圖的效率要高很多,比如當向數據庫寫入數據時,如果使用地圖就需要爲每個元素創建連接對象,但使用mapPartitions的話就需要爲每個分區創建connetcion對象

圖解:

實例

object MapPartitions {
//定義函數 
  def partitionsFun(/*index : Int,*/iter : Iterator[(String,String)]) : Iterator[String] = {
    var woman = List[String]()
    while (iter.hasNext){
      val next = iter.next()
      next match {
        case (_,"female") => woman = /*"["+index+"]"+*/next._1 :: woman
        case _ =>
      }
    }
    return  woman.iterator
  }
 
  def main(args: Array[String]) {
    val conf = new SparkConf().setMaster("local").setAppName("mappartitions")
    val sc = new SparkContext(conf)
    val l = List(("kpop","female"),("zorro","male"),("mobin","male"),("lucy","female"))
    val rdd = sc.parallelize(l,2)
    val mp = rdd.mapPartitions(partitionsFun)
    /*val mp = rdd.mapPartitionsWithIndex(partitionsFun)*/
    mp.collect.foreach(x => (print(x +" ")))   //將分區中的元素轉換成Aarray再輸出
  }
}

結果:

kpop lucy

4.union(ortherDataset):將兩個RDD中的數據集進行合併,最終返回兩個RDD的並集,若RDD中存在相同的元素也不會去重

 

示例

 

object Map {
  def main(args: Array[String]) {
    val conf = new SparkConf().setMaster("local").setAppName("map")
    val sc = new SparkContext(conf)
   val rdd1 = sc.paralleliz(1 to 3)
   val rdd2 = sc.parallelize(3 to 5)
   val unionRDD = rdd1.union(rdd2)
   unionRDD.collect.foreach(x => print(x + " "))
   sc.stop 
   
  }
}

結果:

1 2 3 3 4 5

5.intersection(otherDataset):返回兩個RDD的交集

實例:

object Map {
  def main(args: Array[String]) {
    val conf = new SparkConf().setMaster("local").setAppName("map")
    val sc = new SparkContext(conf)
    val rdd1 = sc.parallelize(1 to 3)
    val rdd2 = sc.parallelize(3 to 5)
    val unionRDD = rdd1.intersection(rdd2)
    unionRDD.collect.foreach(x => print(x + " "))
    sc.stop 

輸出

3

6.distinct([numTasks]):對RDD中的元素進行去重

實例:

object Map {
  def main(args: Array[String]) {
    val conf = new SparkConf().setMaster("local").setAppName("map")
    val sc = new SparkContext(conf)
val list = List(1,1,2,5,2,9,6,1)
val distinctRDD = sc.parallelize(list)
val unionRDD = distinctRDD.distinct()
unionRDD.collect.foreach(x => print(x + " ")) 

結果:

1 6 9 5 2

7.cartesian(otherDataset):對兩個RDD中的所有元素進行笛卡爾積操作

圖解:

實例:

object Map {
  def main(args: Array[String]) {
    val conf = new SparkConf().setMaster("local").setAppName("map")
    val sc = new SparkContext(conf)
val rdd1 = sc.parallelize(1 to 3)
val rdd2 = sc.parallelize(2 to 5)
val cartesianRDD = rdd1.cartesian(rdd2)
cartesianRDD.foreach(x => println(x + " "))       

結果:

(1,2)
(1,3)
(1,4)
(1,5)
(2,2)
(2,3)
(2,4)
(2,5)
(3,2)
(3,3)
(3,4)
(3,5)

7.coalesce(numPartitions,洗牌):對RDD的分區進行重新分區,洗牌默認值爲假,當洗牌=假時,不能增加分區數目,但不會報錯,只是分區個數還是原來的,所以就是這個方法適合將分區數減小

洗牌= FALSE

val rdd = sc.parallelize(1 to 16,4)
val coalesceRDD = rdd.coalesce(3) //當suffle的值爲false時,不能增加分區數(即分區數不能從5->7)
println("重新分區後的分區個數:"+coalesceRDD.partitions.size) 

結果:

重新分區後的分區個數:3
//分區後的數據集
List(1, 2, 3, 4)
List(5, 6, 7, 8)
List(9, 10, 11, 12, 13, 14, 15, 16) 

8.repartition(numPartition):是函數聚結(numPartition,真)的實現,效果和聚結(numPartition,真)的一樣


(2)KV轉換操作即鍵值轉換     

 

星火爲包含鍵值對類型的RDD提供了一些專有的操作。這些RDD被稱爲pairRDD。提供並行操作各個節點或跨界點重新進行數據分組的操作接口。

 

1,聚合操作
對RDD上選優相應的針對鍵的轉化操作
.Scala中使用mapValues()和reduceByKey()計算每個鍵對應的平均值:

2,並行度調優
火花提供了repartion()函數。他會把數據通過網絡進行混洗。並創建出新的分區集合。對數據分區是代價比較大。
優化版的repartion()函數叫做聚結( ).java或者Scala可以使用rdd.partitions.size查看RDD的分區數。並確保調用coalesce()時將RDD合併到比現在的分區更少的分區中
.3,數據
分組groupByKey()使用RDD中的鍵對數據進行分組對於一個由類型ķ的鍵和類型v的值組成的RDD,所得到的結果RDD類型會是[K,可迭代[V]]; groupByKey可以用於未成對的數據上,也可以根據除鍵相同以外的條件進行分組。它可以接受一個個數,對源RDD中的每個元素使用該函數,將返回結果作爲鍵在進行分組.cogroup
()函數對多個共享同一個鍵的RDD進行分組。對兩個鍵類型均爲ķ而值的類型分別爲V和W ^的RDD進行協同組()時,得到的結果RDD類型爲[(K,(可迭代[V],可迭代[W]) )]。
4,連接
普通的join連接是內鏈接,只有在兩個對RDD中都存在的鍵菜叫輸出。當一個輸入對應的某個鍵有多個值時生成的對RDD會包括來自兩個輸入RDD每個組相對應的記錄
.leftOuterJoin()源RDD的每一個鍵都有對應的記錄。每個鍵相對應的值是由一個源RDD的值與一個包含第二個RDD的值的選項對象組成的二元數組。而rightOuterJoin()的結果與其相反
.5,數據排序
使用sortByKey()函數接受一個參數,表示是否讓結果按升序排列(默認是true)

 

 

 

 

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