RDD:彈性分佈式數據集(ResilientDistributed Dataset),是Spark對數據的核心抽象。RDD其實是分佈式的元素集合。當Spark對數據操作和轉換時,會自動將RDD中的數據分發到集羣,並將操作並行化執行。
Spark中的RDD是一個不可變的分佈式對象集合。每個RDD都倍分爲多個分區,這些分區運行在集羣中的不同節點。RDD可以包含Python、Java、Scala中任意類型的對象,甚至可以包含用戶自定義對象,本文主要通過Java實現相關示例。
Spark程序或shell會話工作流程
1. 從外部數據創建出輸入RDD;
2. 使用諸如filter()等這樣的轉化操作對RDD進行轉化,以定義新的RDD;
3. 告訴Spark對需要被重用的中間結果RDD執行persist()操作;
4. 使用諸如first()等這樣的行動操作來觸發一次並行計算,Spark會對計算進行優化後再執行。
一. 創建RDD
Spark提供了兩種創建RDD方式:
1. 讀取外部數據集,如文件,hive數據庫等;
2. 在驅動器程序中對一個集合進行並行化,如list,set等。
方法1是常用方法,其從外部存儲中讀取數據來創建RDD,如讀取文件
方法2其實使用較少,畢竟它需要把整個數據集先放在一臺機器的內存中。實現也簡單,就是把程序中一個已有集合傳給SparkContext的parallelize()方法。二.RDD操作
二. RDD操作
1. RDD支持兩種操作
(1) 轉化操作,RDD的轉化操作是返回一個新的RDD的操作,比如map()和filter。
(2) 行動操作,RDD的行動操作則是向驅動器程序返回結果或把結果寫入外部系統的操作,會觸發實際的計算,比如count()和first()。
惰性求值:RDD的轉化操作是惰性求值的,即在被調用行動操作之前Spark不會開始計算,相反,Spark會在內部記錄下索要求執行的操作的相關信息。例如,當我們調用jsc.textFile()時,數據並沒有讀取進來,而是在必要時纔會讀取。Spark使用惰性求值,就可以把一些操作合併到一起來減少計算數據的步驟。
2. RDD的基本轉化操作
函數名 |
目的 |
示例 |
結果 |
map() |
將函數應用於RDD的每一元素, |
rdd.map(x=>x+1) |
{2,3,4,4} |
flatMap() |
將函數應用於RDD的每一元素, |
rdd.flatMap(x=>x.to(3)) |
{1,2,3,2,3,3,3} |
filter() |
返回一個由通過傳給filter()的函數 |
rdd.filter(x=>x!=1) |
{2,3,3} |
distinct() |
去重 |
rdd.distinct() |
{1,2,3) |
sample(withReplacement, |
對RDD採用,以及是否替換 |
rdd.sample(false,0.5) |
非確定的 |
對一個數據爲{1,2,3,3}的RDD進行基本的RDD轉化操作
函數名 |
目的 |
示例 |
結果 |
union() |
生成一個包含兩個RDD 中所有元素的RDD |
rdd.union(other) |
{1, 2, 3, 3, 4, 5} |
intersection() |
求兩個RDD 共同的元素的RDD |
rdd.intersection(other) |
{3} |
subtract() |
移除一個RDD 中的內容(例如移除訓練數據) |
rdd.subtract(other) |
{1, 2} |
cartesian() |
與另一個RDD 的笛卡兒積 |
rdd.cartesian(other) |
{(1, 3), (1, 4), ...(3, 5)} |
對數據分別爲{1, 2,3}和{3, 4, 5}的RDD進行鍼對兩個RDD的轉化操作
3. RDD的基本執行操作
函數名 |
目的 |
示例 |
結果 |
collect() |
返回RDD 中的所有元素 |
rdd.collect() |
{1, 2, 3, 3} |
count() |
RDD 中的元素個數 |
rdd.count() |
4 |
countByValue() |
各元素在RDD 中出現的次數 |
rdd.countByValue() |
{(1, 1),(2, 1),(3, 2)} |
take(num) |
從RDD 中返回num 個元素 |
rdd.take(2) |
{1, 2} |
top(num) |
從RDD 中返回最前面的num個元素 |
rdd.top(2) |
{3, 3} |
takeOrdered(num) |
從RDD 中按照提供的順序返回最前面的num 個元素 |
rdd.takeOrdered(2)(myOrdering) |
{3, 3} |
takeSample(withReplacement, |
從RDD 中返回任意一些元素 |
rdd.takeSample(false, 1) |
非確定的 |
reduce(func) |
並行整合RDD 中所有數據(例如sum) |
rdd.reduce((x, y) => x + y) |
9 |
fold(zero)(func) |
和reduce() 一樣, 但是需要提供初始值 注意:不重複元素加初始值,重複元素只加一個 |
rdd.fold(0)((x, y) => x + y) |
9 |
aggregate(zeroValue) |
和reduce() 相似, 但是通常返回不同類型的函數 注意:不重複元素加初始值,重複元素只加一個 |
rdd.aggregate((0, 0))((x, y) => |
(9,4) |
foreach(func) 對RDD |
中的每個元素使用給定的函數 |
rdd.foreach(func) |
無 |
對一個數據爲{1, 2,3, 3}的RDD進行基本的RDD行動操作
4. 標準Java函數接口
在Java中,函數需要作爲實現了Spark的org.apache,spark.api.java.function包中的任一函數接口的對象傳遞。
函數名 |
實現的方法 |
用途 |
Function<T, R> |
R call(T) |
接收一個輸入值並返回一個輸出值,用於類似map() 和filter() 等操作中 |
Function2<T1, T2, R> |
R call(T1, T2) |
接收兩個輸入值並返回一個輸出值,用於類似aggregate()和fold() 等操作中 |
FlatMapFunction<T, R> |
Iterable<R> call(T) |
接收一個輸入值並返回任意個輸出,用於類似flatMap()這樣的操作中 |
標準Java函數接口
5. Java中針對專門類型的函數接口
函數名 |
等價函數 |
用途 |
DoubleFlatMapFunction<T> |
Function<T, Iterable<Double>> |
用於flatMapToDouble,以生成DoubleRDD |
DoubleFunction<T> |
Function<T, Double> |
用於mapToDouble,以生成DoubleRDD |
PairFlatMapFunction<T, K, V> |
Function<T, Iterable<Tuple2<K, V>>> |
用於flatMapToPair,以生成PairRDD<K, V> |
PairFunction<T, K, V> |
Function<T, Tuple2<K, V>> |
用於mapToPair, 以生成PairRDD<K, V> |
Java中針對專門類型的函數接口
三. 示例
本節將通過示例的方式驗證第二節中相關的轉化操作和行動操作。
代碼地址:http://download.csdn.net/detail/a123demi/9837375
參考文獻:
王道遠 《Spark 快速大數據分析》