spark RDD常用操作

Spark常用算子分析與應用

1、算子概述

  • 什麼是算子
    • 英文翻譯爲:Operator(簡稱op)
    • 狹義:指從一個函數空間到另一個函數空間(或它自身)的映射。
    • 廣義:指從一個空間到另一個空間的映射
    • 通俗理解:指事物(數據或函數)從一個狀態到另外一個狀態的過程抽象。
    • 實質就是映射,就是關係,就是變換。
  • 算子的重要作用
    • 算子越少,靈活性越低,則實現相同功能的編程複雜度越高,算子越多則反之。
      • 老手機與智能手機
      • 老電腦與新電腦之HDMI (跟VGA是對等的)
    • 算子越少,表現力越差,面對複雜場景則易用性較差。算子越多的則反之。
      • 黑白彩電與彩色電視
      • 彩色電視和智能電視
  • MapReduce 與 Spark算子比較
    • MapReduce只有2個算子,Map和Reduce,絕大多數應用場景下,均需要複雜編碼才能達到用戶需求。
    • Spark有80多個算子,進行充分的組合應用後,能滿足絕大多數的應用場景。

2、Spark算子介紹與應用

2.1 算子分類

1 轉換算子(Transformation)

此種算子不觸發提交作業,只有作業被提交後纔會真正啓動轉換計算。

  • Value型轉換算子:其處理的數據項是Value型
    • 輸入分區與輸出分區一對一型
      • map算子
      • flatMap算子
      • mapPartitions算子
      • glom算子
    • 輸入分區與輸出分區多對一型
      • union算子
      • cartesian算子
    • 輸入分區與輸出分區多對多型
      • groupBy算子
    • 輸出分區爲輸入分區子集型
      • filter算子
      • distinct算子
      • subtract算子
      • sample算子
      • takeSample算子
    • Cache型
      • cache算子
      • persist算子
  • Key-Value型轉換算子:其處理的數據是Key-Value型
    • 輸入分區與輸出分區一對一
      • mapValues算子
    • 對單個RDD聚集
      • combineByKey算子
      • reduceByKey算子
      • partitionBy算子
    • 對兩個RDD聚集
      • cogroup算子
    • 連接
      • join算子
      • leftOutJoin算子
      • rightOutJoin算子

2 行動算子(Action)

此種算子會觸發SparkContext提交作業。

  • 無輸出(是指不輸出hdfs、本地文件當中)
    • foreach算子
  • HDFS
    • saveAsTextFile算子
    • saveAsObjectFile算子
  • Scala集合和數據類型
    • collect算子
    • collectAsMap算子
    • reduceByKeyLocally算子
    • lookup算子
    • count算子
    • top算子
    • reduce算子
    • fold算子
    • aggregate算子

2.2 常用算子分析與應用

2.2.1 Value型轉換算子

  • 1) map
    • 類比於mapreduce中的map操作,給定一個輸入通過map函數映到成一個新的元素輸出
      • case_1

val first = sc.parallelize(List("Hello","World","天亮教育","大數據"),2)

val second= first.map(_.length)

second.collect

      • case_2

val first = sc.parallelize(1 to 5,2)

first.map(1 to _).collect

  • 2) flatMap
    • 給定一個輸入,將返回的所有結果打平成一個一維集合結構
      • case_1

val first = sc.parallelize(1 to 5,2)

first.flatMap(1 to _).collect

      • case_2

val first = sc.parallelize(List("one","two","three"),2)

first.flatMap(x => List(x,x,x)).collect

      • case_3

val first = sc.parallelize(List("one","two","three"),2)

first.flatMap(x => List(x+"_1",x+"_2",x+"_3")).collect

  • 3) mapPartitions
    • 以分區爲單位進行計算處理,而map是以每個元素爲單位進行計算處理。
    • 當在map過程中需要頻繁創建額外對象時,如文件輸出流操作、jdbc操作、Socket操作等時,當用mapPartitions算子
      • case_1

val rdd=sc.parallelize(Seq(1,2,3,4,5),3)

var rdd2=rdd.mapPartitions(partition=>{

       partition.map(num => num * num)

    }

)

rdd2.max

      • case_2

val rdd=sc.parallelize(Seq(1,2,3,4,5),3)

var rdd2=rdd.mapPartitions(partition=>{

       partition.flatMap(1 to _)

    }

)

rdd2.count

  • 4) glom

以分區爲單位,將每個分區的值形成一個數組

val a = sc.parallelize(Seq("one","two","three","four","five","six","seven"),3)

a.glom.collect

  • 5) union算子
    • 將兩個RDD合併成一個RDD,並不去重
    • 會發生多分區合併成一個分區的情況

val a = sc.parallelize(1 to 4, 2)

val b = sc.parallelize(3 to 6, 2)

a.union(b).collect

(a ++ b).collect

(a union b).collect

  • 6) groupBy算子

輸入分區與輸出分區多對多型

val a = sc.parallelize(Seq(1,3,4,5,9,100,200), 3)

a.groupBy(x => { if (x > 10) ">10" else "<=10" }).collect

  • 7) filter算子

輸出分區爲輸入分區子集型

val a = sc.parallelize(1 to 21, 3)

val b = a.filter(_ % 4 == 0)

b.collect

  • 8 ) distinct算子

輸出分區爲輸入分區子集型,全局去重

      • case_1

val a = sc.parallelize(1 to 4, 2)

val b = sc.parallelize(3 to 6, 2)

a.union(b).distinct().collect

      • case_2

val c = sc.parallelize(List("張三", "李四", "李四", "王五"), 2)

c.distinct.collect

  • 9) cache算子
    • cache 將 RDD 元素從磁盤緩存到內存。 相當於 persist(MEMORY_ONLY) 函數的功能。
    • 主要應用在當RDD數據反覆被使用的場景下
      • case_1

val a = sc.parallelize(1 to 4, 2)

val b = sc.parallelize(3 to 6, 2)

 

a.union(b).count

a.union(b).distinct().collect

      • case_2

val a = sc.parallelize(1 to 4, 2)

val b = sc.parallelize(3 to 6, 2)

val c=a.union(b).cache

c.count

c.distinct().collect

2.2.2 Key-Value型轉換算子

其處理的數據是Key-Value型

  • 1)mapValues算子
    • 輸入分區與輸出分區一對一
    • 針對(Key,Value)型數據中的 Value 進行 Map 操作,而不對 Key 進行處理。

val first = sc.parallelize(List(("張一",1),("張二",2),("張三",3),("張四",4)),2)

val second= first.mapValues(x=>x+1)

second.collect

  • 2)combineByKey算子
    • 定義

def combineByKey[C](

createCombiner: (V) => C,

mergeValue: (C, V) => C,

mergeCombiners: (C, C) => C): RDD[(String, C)]

  1. createCombiner:對每個分區內的同組元素如何聚合,形成一個累加器
  2.  mergeValue:將前邊的累加器與新遇到的值進行合併的方法
  3.  mergeCombiners:每個分區都是獨立處理,故同一個鍵可以有多個累加器。如果有兩個或者更多的分區都有對應同               一個鍵的累 加器,用方法將各個分區的結果進行合併。
  • case_1

val first = sc.parallelize(List(("張一",1),("李一",1),("張一",2),("張一",3),("李一",3),("李三",3),("張四",4)),2)

val second= first.combineByKey(List(_), (x:List[Int], y:Int) => y :: x, (x:List[Int], y:List[Int]) => x ::: y)

second.collect

  • 3)reduceByKey算子
    • 按key聚合後對組進行歸約處理,如求和、連接等操作

val first = sc.parallelize(List("小米", "華爲", "小米", "小米", "華爲", "蘋果"), 2)

val second = first.map(x => (x, 1))

second.reduceByKey(_ + _).collect

  • 4)join算子
    • 對Key-Value結構的RDD進行按Key的join操作,最後將V部分做flat打平操作。

val first = sc.parallelize(List(("張一",11),("李二",12)),2)

val second = sc.parallelize(List(("張一",21),("李二",22),("王五",23)),2)

first.join(second).collect

2.2.3 行動算子(Action)

  • 此種算子會觸發SparkContext提交作業。觸發了RDD DAG 的執行。
  • 1) 無輸出型:不落地到文件或是hdfs的作用
    • foreach算子

val first = sc.parallelize(List("小米", "華爲", "小米", "小米", "華爲", "蘋果"), 2)

first.foreach(println _)

  • 2) HDFS輸出型
    • saveAsTextFile算子

val first = sc.parallelize(List("小米", "華爲", "小米", "小米", "華爲", "蘋果"), 2)

//指定本地保存的目錄

first.saveAsTextFile("file:///home/spark/text")    

//指定hdfs保存的目錄,默認亦保存在hdfs中

first.saveAsTextFile("spark_shell_output_1")    

  • Scala集合和數據類型
    • 3) collect算子
      • 相當於toArray操作,將分佈式RDD返回成爲一個scala array數組結果,實際是Driver所在的機器節點,再針對該結果操作

val first = sc.parallelize(List("小米", "華爲", "小米", "小米", "華爲", "蘋果"), 2)

first.collect

  • 4) collectAsMap算子
    • 相當於toMap操作,將分佈式RDD的kv對形式返回成爲一個的scala map集合,實際是Driver所在的機器節點,再針對該結果操作

val first = sc.parallelize(List(("張一",1),("李一",1),("張一",2),("張一",3),("李一",3),("李三",3),("張四",4)),2)

first.collectAsMap

  • 5)lookup算子
    • 對(Key,Value)型的RDD操作,返回指定Key對應的元素形成的Seq。

val first = sc.parallelize(List("小米", "華爲", "華米", "大米", "蘋果","米老鼠"), 2)

val second=first.map(x=>({if(x.contains("米")) "有米" else "無米"},x))

second.lookup("有米")

  • 6) reduce算子
    • 先對兩個元素進行reduce函數操作,然後將結果和迭代器取出的下一個元素進行reduce函數操作,直到迭代器遍歷完所有元素,得到最後結果。

//求value型列表的和

val a = sc.parallelize(1 to 10, 2)

a.reduce(_ + _)

//求key-value型列表的value的和

val a = sc.parallelize(List(("one",1),("two",2),("three",3),("four",4)), 2)

a.reduce((x,y)=>("sum",x._2 + y._2))._2

  • 7) fold算子
    • fold算子簽名:  def fold(zeroValue: T)(op: (T, T) => T): T
    • 其實就是先對rdd分區的每一個分區進行op函數,在調用op函數過程中將zeroValue參與計算,最後在對所有分區的結果調用op函數,同理此處zeroValue再次參與計算。

//和是41,公式=(1+2+3+4+5+6+10)+10

sc.parallelize(List(1, 2, 3, 4, 5, 6), 1).fold(10)(_+_)

//和是51,公式=(1+2+3+10)+(4+5+6+10)+10=51

sc.parallelize(List(1, 2, 3, 4, 5, 6), 2).fold(10)(_+_)

//和是61,公式=(1+2+10)+(3+4+10)+(5+6+10)+10=61

sc.parallelize(List(1, 2, 3, 4, 5, 6), 3).fold(10)(_+_)

 

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