spark編程模型(十三)之RDD鍵值轉換操作(Transformation Operation)——combineByKey、foldByKey

combineByKey()

  • def combineByKey[C](createCombiner: (V) => C, mergeValue: (C, V) => C, mergeCombiners: (C, C) => C): RDD[(K, C)]

  • def combineByKey[C](createCombiner: (V) => C, mergeValue: (C, V) => C, mergeCombiners: (C, C) => C, numPartitions: Int): RDD[(K, C)]

  • def combineByKey[C](createCombiner: (V) => C, mergeValue: (C, V) => C, mergeCombiners: (C, C) => C, partitioner: Partitioner, mapSideCombine: Boolean = true, serializer: Serializer = null): RDD[(K, C)]

  • 該函數用於將RDD[K,V]轉換成RDD[K,C],這裏的V類型和C類型可以相同也可以不同
參數 參數說明
createCombiner 組合器函數,用於將V類型轉換成C類型,輸入參數爲RDD[K,V]中的V,輸出爲C
mergeValue 合併值函數,將一個C類型和一個V類型值合併成一個C類型,輸入參數爲(C,V),輸出爲C
mergeCombiners 合併組合器函數,用於將兩個C類型值合併成一個C類型,輸入參數爲(C,C),輸出爲C
numPartitions 結果RDD分區數,默認保持原有的分區數
partitioner 分區函數,默認爲HashPartitioner
mapSideCombine 是否需要在Map端進行combine操作,類似於MapReduce中的combine,默認爲true
  • createCombiner: combineByKey() 會遍歷分區中的所有元素,因此每個元素的鍵要麼還沒有遇到過,要麼就
    和之前的某個元素的鍵相同。如果這是一個新的元素, combineByKey() 會使用一個叫作 createCombiner() 的函數來創建
    那個鍵對應的累加器的初始值

  • mergeValue: 如果這是一個在處理當前分區之前已經遇到的鍵, 它會使用 mergeValue() 方法將該鍵的累加器對應的當前值與這個新的值進行合併

  • mergeCombiners: 由於每個分區都是獨立處理的, 因此對於同一個鍵可以有多個累加器。如果有兩個或者更
    多的分區都有對應同一個鍵的累加器, 就需要使用用戶提供的 mergeCombiners() 方法將各個分區的結果進行合併

    scala> var rdd1 = sc.makeRDD(Array(("A",1),("A",2),("B",1),("B",2),("C",1)))
    rdd1: org.apache.spark.rdd.RDD[(String, Int)] = ParallelCollectionRDD[54] at makeRDD at <console>:26
    
    scala> rdd1.partitions.size
    res40: Int = 1
    
    scala> rdd1.combineByKey(
             | (v) => (v + "_"),
             | (c:String, v:Int) => (c + "@" + v),
             | (c1: String, c2 : String) => (c1 + "$" + c2)).collect
    res41: Array[(String, String)] = Array((B,1_@2), (A,1_@2), (C,1_))
    
    scala> var rdd1 = sc.makeRDD(Array(("A",1),("A",2),("C", 3),("B",1),("B",2),("C",1)), 2)
    rdd1: org.apache.spark.rdd.RDD[(String, Int)] = ParallelCollectionRDD[60] at makeRDD at <console>:26
    
    scala> rdd1.partitions.size
    res46: Int = 2
    
    scala> rdd1.glom().collect
    res47: Array[Array[(String, Int)]] = Array(Array((A,1), (A,2), (C,3)), Array((B,1), (B,2), (C,1)))
    
    scala> rdd1.combineByKey(
        | (v) => (v + "_"),
        | (c:String, v:Int) => (c + "@" + v),
        | (c1: String, c2 : String) => (c1 + "$" + c2)).collect
    res48: Array[(String, String)] = Array((B,1_@2), (A,1_@2), (C,3_$1_))
    

foldByKey

  • def foldByKey(zeroValue: V)(func: (V, V) => V): RDD[(K, V)]

  • def foldByKey(zeroValue: V, numPartitions: Int)(func: (V, V) => V): RDD[(K, V)]

  • def foldByKey(zeroValue: V, partitioner: Partitioner)(func: (V, V) => V): RDD[(K, V)]

  • 該函數用於RDD[K,V]根據K將V做摺疊、合併處理,其中的參數zeroValue表示先根據映射函數將zeroValue應用於V,進行初始化V,再將映射函數應用於初始化後的V
  • 在使用foldByKey算子時候,要特別注意映射函數及zeroValue的取值

    scala> var rdd1 = sc.makeRDD(Array(("A",0),("A",2),("B",1),("B",2),("C",1)))
    
    scala> rdd1.foldByKey(0)(_+_).collect
    res75: Array[(String, Int)] = Array((A,2), (B,3), (C,1)) 
    //將rdd1中每個key對應的V進行累加,注意zeroValue=0,需要先初始化V,映射函數爲+操
    //作,比如("A",0), ("A",2),先將zeroValue應用於每個V,得到:("A",0+0), ("A",2+0),即:
    //("A",0), ("A",2),再將映射函數應用於初始化後的V,最後得到(A,0+2),即(A,2)
    
    scala> rdd1.foldByKey(2)(_+_).collect
    res76: Array[(String, Int)] = Array((A,6), (B,7), (C,3))
    //先將zeroValue=2應用於每個V,得到:("A",0+2), ("A",2+2),即:("A",2), ("A",4),再將映射函
    //數應用於初始化後的V,最後得到:(A,2+4),即:(A,6)
    
    scala> rdd1.foldByKey(0)(_*_).collect
    res77: Array[(String, Int)] = Array((A,0), (B,0), (C,0))
    //先將zeroValue=0應用於每個V,注意,這次映射函數爲乘法,得到:("A",0*0), ("A",2*0),
    //即:("A",0), ("A",0),再將映射函//數應用於初始化後的V,最後得到:(A,0*0),即:(A,0)
    //其他K也一樣,最終都得到了V=0
    
    scala> rdd1.foldByKey(1)(_*_).collect
    res78: Array[(String, Int)] = Array((A,0), (B,2), (C,1))
    //映射函數爲乘法時,需要將zeroValue設爲1,才能得到我們想要的結果。
    
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章