文章目錄
一 彈性分佈式數據集(RDD)
RDD是一個分佈式數據集, 是spark中最基本的數據抽象, 是一個不可變, 可分區, 裏面的元素可以並行計算的集合, 具有高容錯, 位置感知性調度, 可伸縮性的特點
1.1 高容錯
RDD的容錯性其實就是爲了提高計算效率, 如果在shuffle前發生宕機, 只需要把丟失的分區對應的父RDD分區進行重新計算即可, 如果是shuffle後的分區數據丟失, 此時就需要將整個父RDD的分區調用shuffle算子進行重新計算
RDD的容錯性就是指RDD分區的恢復過程, 和Worker宕機無關
1.2 位置感知性調度
位置感知就是把具體的計算邏輯發送到對應的數據節點上, 進行計算, 可以有效避免發生大量網絡IO
如果Worker節點和datanode節點不是一個幾點的話, 這個時候Worker會從datanode節點上拉取數據
如果工作的Worker節點發生了宕機, 這個時候不會重新開啓一個worker, 而是會將宕機的那個節點所執行的任務分配到另一個worker上
1.3 可伸縮性
RDD可以實現自動容錯
二 RDD的屬性
- A list of partitions
- A function for computing each split
- A list of dependencies on other RDDs
- Optionally, a Partitioner for key-value RDDs (e.g. to say that the RDD is hash-partitioned)
- Optionally, a list of preferred locations to compute each split on (e.g. block locations for an HDFS file)
1)一組分片(Partition),即數據集的基本組成單位。對於RDD來說,每個分片都會被一個計算任務處理,並決定並行計算的粒度。用戶可以在創建RDD時指定RDD的分片個數,如果沒有指定,那麼就會採用默認值。默認值就是程序所分配到的CPU Core的數目。
2)一個計算每個分區的函數。Spark中RDD的計算是以分片爲單位的,每個RDD都會實現compute函數以達到這個目的。compute函數會對迭代器進行復合,不需要保存每次計算的結果。
3)RDD之間的依賴關係。RDD的每次轉換都會生成一個新的RDD,所以RDD之間就會形成類似於流水線一樣的前後依賴關係。在部分分區數據丟失時,Spark可以通過這個依賴關係重新計算丟失的分區數據,而不是對RDD的所有分區進行重新計算。
4)一個Partitioner,即RDD的分片函數。當前Spark中實現了兩種類型的分片函數,一個是基於哈希的HashPartitioner,另外一個是基於範圍的RangePartitioner。只有對於key-value的RDD,纔會有Partitioner,非key-value的RDD的Parititioner的值是None。Partitioner函數不但決定了RDD本身的分片數量,也決定了parent RDD Shuffle輸出時的分片數量。
5)一個列表,存儲存取每個Partition的優先位置(preferred location)。對於一個HDFS文件來說,這個列表保存的就是每個Partition所在的塊的位置。按照“移動數據不如移動計算”的理念,Spark在進行任務調度的時候,會盡可能地將計算任務分配到其所要處理數據塊的存儲位置。
三 RDD類型
官網鏈接: https://spark.apache.org/docs/2.2.0/rdd-programming-guide.html#basics
- 帶有By的算子都是發生在shuffle過程
3.1 Transformation
特點: 延遲加載
常用的Transformation
轉換 | 含義 |
---|---|
map(func) | 返回一個新的RDD,該RDD由每一個輸入元素經過func函數轉換後組成 |
filter(func) | 返回一個新的RDD,該RDD由經過func函數計算後返回值爲true的輸入元素組成 |
flatMap(func) | 類似於map,但是每一個輸入元素可以被映射爲0或多個輸出元素(所以func應該返回一個序列,而不是單一元素) |
mapPartitions(func) | 類似於map,但獨立地在RDD的每一個分片上運行,因此在類型爲T的RDD上運行時,func的函數類型必須是Iterator[T] => Iterator[U] |
mapPartitionsWithIndex(func) | 類似於mapPartitions,但func帶有一個整數參數表示分片的索引值,因此在類型爲T的RDD上運行時,func的函數類型必須是(Int, Iterator[T]) => Iterator[U] |
sample(withReplacement, fraction, seed) | 根據fraction指定的比例對數據進行採樣,可以選擇是否使用隨機數進行替換,seed用於指定隨機數生成器種子 |
union(otherDataset) | 對源RDD和參數RDD求並集後返回一個新的RDD |
intersection(otherDataset) | 對源RDD和參數RDD求交集後返回一個新的RDD |
distinct([numTasks])) | 對源RDD進行去重後返回一個新的RDD |
groupByKey([numTasks]) | 在一個(K,V)的RDD上調用,返回一個(K, Iterator[V])的RDD |
reduceByKey(func, [numTasks]) | 在一個(K,V)的RDD上調用,返回一個(K,V)的RDD,使用指定的reduce函數,將相同key的值聚合到一起,與groupByKey類似,reduce任務的個數可以通過第二個可選的參數來設置 |
aggregateByKey(zeroValue)(seqOp, combOp, [numTasks]) | |
sortByKey([ascending], [numTasks]) | 在一個(K,V)的RDD上調用,K必須實現Ordered接口,返回一個按照key進行排序的(K,V)的RDD |
sortBy(func,[ascending], [numTasks]) | 與sortByKey類似,但是更靈活 |
join(otherDataset, [numTasks]) | 在類型爲(K,V)和(K,W)的RDD上調用,返回一個相同key對應的所有元素對在一起的(K,(V,W))的RDD |
cogroup(otherDataset, [numTasks]) | 在類型爲(K,V)和(K,W)的RDD上調用,返回一個(K,(Iterable,Iterable))類型的RDD |
cartesian(otherDataset) | 笛卡爾積 |
pipe(command, [envVars]) | |
coalesce(numPartitions) | 重新分區 |
repartition(numPartitions) | 重新分區 |
repartitionAndSortWithinPartitions(partitioner) | 重新分區 |
3.2 Action
- 立即運行
- 在源碼中Action算子會調用 runJob 方法
- 每調用一個action算子就相當於提交了一個Job
動作 | 含義 |
---|---|
reduce(func) | 通過func函數聚集RDD中的所有元素,這個功能必須是可交換且可並聯的 |
collect() | 在驅動程序中,以數組的形式返回數據集的所有元素 |
count() | 返回RDD的元素個數 |
first() | 返回RDD的第一個元素(類似於take(1)) |
take(n) | 返回一個由數據集的前n個元素組成的數組 |
takeSample(withReplacement,num, [seed]) | 返回一個數組,該數組由從數據集中隨機採樣的num個元素組成,可以選擇是否用隨機數替換不足的部分,seed用於指定隨機數生成器種子 |
takeOrdered(n, [ordering]) | takeOrdered和top類似,只不過以和top相反的順序返回元素 |
saveAsTextFile(path) | 將數據集的元素以textfile的形式保存到HDFS文件系統或者其他支持的文件系統,對於每個元素,Spark將會調用toString方法,將它裝換爲文件中的文本 |
saveAsSequenceFile(path) | 將數據集中的元素以Hadoop sequencefile的格式保存到指定的目錄下,可以使HDFS或者其他Hadoop支持的文件系統。 |
saveAsObjectFile(path) | |
countByKey() | 針對(K,V)類型的RDD,返回一個(K,Int)的map,表示每一個key對應的元素個數。 |
foreach(func) | 在數據集的每一個元素上,運行函數func進行更新。 |
四 創建RDD方式三種方式
1)由一個已經存在的Scala集合創建。
sc.parallelize(Array(1,2,3,4))
2)由外部存儲系統的數據集創建,包括本地的文件系統,還有所有Hadoop支持的數據集,比如HDFS、Cassandra、HBase等
sc.textFile("hdfs://hadoop:8020/word.txt")
3)使用makeRDD函數創建
sc.makeRDD(Array(1,2,3,4))
五 reduceByKey和groupBykey的區別
reduceByKey會先進行局部聚合, 再進行全局聚合, 這樣會大大減少網絡IO, 起到優化作用, 所以在能用到reduceByKey的情況下用reduceByKey
groupByKey
reduceByKey