文章目錄
1.常用的rdd
函數 | 說明 |
---|---|
map(func) | 返回一個新的分佈式數據集,由每個原元素經過func函數轉換後組成 |
filter(func) | 返回一個新的數據集,由經過func函數後返回值爲true的原元素組成 |
flatMap(func) | 類似於map,但是每一個輸入元素,會被映射爲0到多個輸出元素(因此,func函數的返回值是一個Seq,而不是單一元素) |
sample(withReplacement, frac, seed) | 根據給定的隨機種子seed,隨機抽樣出數量爲frac的數據 |
union(otherDataset) | 返回一個新的數據集,由原數據集和參數聯合而成 |
groupByKey([numTasks]) | 在一個由(K,V)對組成的數據集上調用,返回一個(K,Seq[V])對的數據集。注意:默認情況下,使用8個並行任務進行分組,你可以傳入numTask可選參數,根據數據量設置不同數目的Task |
reduceByKey(func, [numTasks]) | 在一個(K,V)對的數據集上使用,返回一個(K,V)對的數據集,key相同的值,都被使用指定的reduce函數聚合到一起。和groupbykey類似,任務的個數是可以通過第二個可選參數來配置的。 |
join(otherDataset, [numTasks]) | 在類型爲(K,V)和(K,W)類型的數據集上調用,返回一個(K,(V,W))對,每個key中的所有元素都在一起的數據集 |
reduce(func) | 通過函數func聚集數據集中的所有元素。Func函數接受2個參數,返回一個值。這個函數必須是關聯性的,確保可以被正確的併發執行 |
collect() | 在Driver的程序中,以數組的形式,返回數據集的所有元素。這通常會在使用filter或者其它操作後,返回一個足夠小的數據子集再使用,直接將整個RDD集Collect返回,很可能會讓Driver程序OOM |
count() | 返回數據集的元素個數 |
take(n) | 返回一個數組,由數據集的前n個元素組成。注意,這個操作目前並非在多個節點上,並行執行,而是Driver程序所在機器,單機計算所有的元素(Gateway的內存壓力會增大) |
first() | 返回數據集的第一個元素(類似於take(1)) |
saveAsTextFile(path) | 將數據集的元素,以textfile的形式,保存到本地文件系統,hdfs或者任何其它hadoop支持的文件系統。Spark將會調用每個元素的toString方法,並將它轉換爲文件中的一行文本 |
saveAsSequenceFile(path) | 將數據集的元素,以sequencefile的格式,保存到指定的目錄下,本地系統,hdfs或者任何其它hadoop支持的文件系統。RDD的元素必須由key-value對組成,並都實現了Hadoop的Writable接口,或隱式可以轉換爲Writable(Spark包括了基本類型的轉換,例如Int,Double,String等等) |
foreach(func) | 在數據集的每一個元素上,運行函數func。這通常用於更新一個累加器變量,或者和外部存儲系統做交互 |
rdd的輸入和輸出,scala版,java版
scala版本:
https://github.com/zhouyang-bigdata/SparkCommonRdd
java版本:
https://github.com/zhouyang-bigdata/SparkCommonRddJava
每個rdd函數的使用場景
spark 默認提供的rdd多達幾十個,其中有與外部連接相關的,比如kafkaRdd,也有專門處理數據的。這裏介紹的是專門處理數據的。
spark rdd適合的場景有:
- 轉換
- 過濾
- 計數
- 排序
- 分類
- 統計
轉換:
Map,最有用的轉換函數。map() 接收一個函數,把這個函數用於 RDD 中的每個元素,將函數的返回結果作爲結果RDD
mapPartition可以倒過來理解,先partition,再把每個partition進行map函數
map,mapToPair:一對一轉換。
flatMap,flatMapToPair:一對多轉換。
過濾:
filter,這通常用於規則校驗,條件查詢中。條件查詢通常有:等於、小於、大於、小於等於、大於等於、模糊匹配,區間等。對於複雜條件,涉及到多個實體對象,需要注意序列化問題。
計數:
reduceByKey,reduce,count,accumulator
計數有2種,一種是對值本身累加,一種是對值的數量計數。
reduceByKey接收一個函數,按照相同的key進行reduce操作。
累加器也可以作爲計數工具,累加器本身用處是統計程序執行次數,做一些處理,也可以做對值的數量計數。
排序:
sortByKey
用於對pairRDD按照key進行排序,第一個參數可以設置true或者false,默認是true。true是升序。
這裏有個問題,就是爲什麼沒有sort。也就是對非鍵值對排序,沒有對應的rdd。實際上,可以通過其它rdd去實現。
分類:
groupByKey
Cogroup
Reduce
Countbykey
groupByKey會將RDD[key,value] 按照相同的key進行分組,形成RDD[key,Iterable[value]]的形式
cogroup
groupByKey是對單個 RDD 的數據進行分組,還可以使用一個叫作 cogroup() 的函數對多個共享同一個鍵的 RDD 進行分組 。
分類通常以某個對象爲依據。按這個概念,它的用途非常廣泛。
統計:
統計比較複雜,幾乎沒有算子單獨實現需求。常見的統計有:max,min,avg,sum,趨勢。
實際的例子:
- 條件查詢
查詢包含等於、小於、大於、小於等於、大於等於、模糊匹配,區間等條件的數據。
使用map,filter。 - 求最值
求max,min,avg,sum等數據。
具體可參見:
https://github.com/zhouyang-bigdata/SparkRddRealExamples
特殊rdd的使用選擇
特殊rdd,對筆者而言,比較特別的rdd跟以下幾個方面有聯繫:
- shuffle操作
- 在driver上還是在executor上執行
- partition的意義
- Union,join,aggregate
(1)shuffle操作
我們知道,reducebykey,groupbykey是會發生shuffle操作的。事實上,repartition,join,cogroup,和任何的By或ByKey轉換可以導致洗牌。 Shuffle操作,會把轉換的中間數據進行分割,然後臨時存到磁盤。直到下一次轉換,需要從磁盤讀取數據。這個操作很低效,而且帶來大量內存消耗。爲什麼會消耗大量內存呢?因爲,對於map,filter等操作,從磁盤讀取數據也好,還是處理上一步操作的中間數據,數據本身是一個抽象的rdd數據集,數據是以流的形式,小批次的放入內存,在一個時間點,內存消耗並不是很高。而這裏的讀磁盤數據,是一次性的讀取大量數據到內存,內存消耗大。
除此之外,這2個操作,都是寬依賴,同時會產生網絡io,io大小與數據量和partition的數量有關。
(2)在driver上還是在executor上執行
這是一個容易犯錯的問題。比如foreachRDD,是在driver端執行。foreach,foreachPartition在executor上執行。對於面向外部連接,比如mysql連接,redis連接,hbase連接,我們不想要都在driver端創建,因爲這樣,每個executor端都從driver端拿數據。這裏面有個情況容易混淆,就是:
數據是都在driver端處理還是僅彙總到driver端?
這個區別,直接將Action算子分爲2類。
(3)partition的意義
Partition的思路,是把數據分成一塊一塊的,再使用task並行計算。一般推薦每個真核分2-4partition。Partition與task的關係?
可參見:
https://blog.csdn.net/cafebar123/article/details/79684596
我們知道mappartition在處理外部連接的時候,比map更有效,比如mysql,redis。
使用map與mapPartition,本質區別,是每次載入內存的數據的大小,越大,則函數執行次數越少,綜合來說,執行次數越少越好,原因有二:
-
函數每執行一次,jvm就需分析一次;次數越少,jvm分析的總時間就越少。
-
對於建立外部連接時,比如讀取mysql,kafka數據,建立的連接越少越高效。
但每次載入內存的數據大小,也不能過大。個人建議應不大於每個task分配的內存的1/3。