如何理解spark中RDD和DataFrame的結構?

之前對RDD的理解是,用戶自己選定要使用spark處理的數據,然後這些數據經過transaction後會被賦予彈性,分布特性的特點,具備這樣特點的數據集,英文縮寫就是RDD。但RDD再怎麼有特性,還是數據集,在我的理解里就像關係型資料庫里的表,裡面是存儲的數據,抓來就用。

但之後看到dataframe和下面這張圖之後,我迷惑了。。

感覺似乎dataframe的結構才更符合我對rdd的理解。。好像transaction在賦予數據集彈性,分布特性的同時,還順帶把數據變成對象然後序列化存儲了?如果是,那麼是按照什麼樣的標準進行對象化的呢,是按照行,還是按照欄位呢,還是按照非關係型資料庫里的rowkey呢。。那麼這些對象化的數據都是怎麼進行後續處理然後參與運算的呢。。

徹底困惑了,求大神們指點一下,幫助我理解RDD還有dataframe。。謝謝了!


這篇 blog 可能可以回答你的疑問: A Tale of Three Apache Spark APIs: RDDs, DataFrames, and Datasets

哈,突然想起來這張圖是我在《平易近人、兼容並蓄——Spark SQL 1.3.0概覽》一文中畫的插圖。這篇文章應該也有助於理解 RDD 和 DataFrame 的區別。


你對RDD的理解是對的,RDD就是一個分散式的無序的列表。

RDD中可以存儲任何的單機類型的數據,但是,直接使用RDD在欄位需求明顯時,存在運算元難以復用的缺點。

例如,現在RDD存的數據是一個Person類型的數據,現在要求所有每個年齡段(10年一個年齡段)的人中最高的身高與最大的體重。

使用RDD介面,因為RDD不了解其中存儲的數據的具體結構,數據的結構對它而言是黑盒,於是這就需要用戶自己去寫一個很特化的聚合的函數來完成這樣的功能。

而有了DataFrame,則框架會去了解RDD中的數據是什麼樣的結構的,用戶可以說清楚自己對每一列進行什麼樣的操作,這樣就有可能可以實現一個運算元,用在多個列上,比較容易進行運算元的復用。甚至,未來又要同時求出每個年齡段內不同的姓氏有多少個,則使用RDD介面,之前的函數需要改動很大才能滿足需求,而使用DataFrame介面,則只需要添加對這一個列的處理,原來的max/min的相關列處理都可保持不變。

總而言之,DataFrame相關介面就是RDD的一個擴展,讓RDD了解了RDD中存儲的數據包含哪些列,並可以在列上進行操作。

另外,DataFrame基本上快要被Dataset介面取代了,你可以再去了解下Dataset介面。

最後,打個廣告:如果是百度內部的同學看到我的答案,有類似需求時,歡迎使用我們的Bigflow項目,API設計得比Spark更簡單易用,且用戶代碼可復用性更強。我們的Schema相關介面在代碼可復用程度上要遠超DataFrame/Dataset——廠外同學聽我在這兒「吹」不信就罷了,直接忽略即可,咱們也不用爭辯,短期內暫無法給你證明。


我感覺,你把MapReduce的例子弄懂了,你就明白RDD是什麼了

MapReduce兩個操作的定義如下:

Map(k1,v1) → list(k2,v2)

Reduce(k2, list (v2)) → list(v3)

mapreduce處理的是非結構化數據,也就是key和value,至於value是一個字元串,還是一個數組,還是一個鍵值對,完全沒有定義。

再看看Spark示例:

val spark = new SparkContext(master, appName, [sparkHome], [jars])
val file = spark.textFile("hdfs://...")
val counts = file.flatMap(line =&> line.split(" "))
.map(word =&> (word, 1))
.reduceByKey(_ + _)
counts.saveAsTextFile("hdfs://...")

其中的file是根據HDFS上的文件創建的RDD,後面的flatMap,map,reduceByKe都創建出一個新的RDD,琢磨下每個RDD的key和value都是什麼。

Spark Core引人RDD的概念更多的是把數據處理步驟組成的有向無環圖(DAG)抽象成類似函數式編程中的集合的概念,而把分散式數據處理的過程隱藏在這個抽象後面,比如劃分stage,劃分task,shuffle,調度這些task,保證data locality等等。

至於DataFrame,是為Spark SQL引人的結構化數據抽象,其官方定義:

A DataFrame is a distributed collection of data organized into named columns. It is conceptually equivalent to a table in a relational database or a data frame in R/Python, but with richer optimizations under the hood.

(來源:Spark SQL and DataFrames)

DataFrame就是組織成有名字的列的分散式數據集合,概念上等同於關係型資料庫的表。拋開分散式,很好理解。


旅行中無意看到這個問題,最近的項目和spark dataframe相關,也來談談自己的理解啦

Spark RDD是分散式彈性數據集,一個比較核心的是粗粒度的分散式計算,粗粒度是指用戶不用關心太多的分散式細節,用聲明式的API就能完成分散式計算,比如Word Count用一行就能寫完。RDD易用性很好,那Spark為啥還要有Dataframe呢?

DataFrame的從API上借鑒了R和pandas的DataFRame的概念,是業界標準結化數據處理API。DataFrame的數據抽象是命名元組,代碼里是Row類型,Dataframe結合了過程化編程和聲名式的API,讓用戶能用過程化編程的方法處理結構化數據。

Dataframe比RDD多了限制,帶來了更多的優化,基於Spark Catalyst優化器,提供如列裁剪,謂詞下推,map join等優化。同時,採用code generation ,動態編譯表達式,提升性能,比用rdd的自定義函數性能高5倍左右。

舉個例子,

rdd.map(lambda line: line.split(" "))
.map(lambda items: (items[0], items[1], items[2], items[3]))
.filter(lambda items: int(items[2]) &>= 19)
.select(lambda items: (items[0], items[1]))

sqlContext.table("people")
.filter(col("age") &>= 19)
.select("id", "name")

用rdd讀結構化文本要用map函數,需要按位置獲取數據,沒有schema,性能和可讀性都不好。

而用dataframe可以直接通過sede讀取結構化數據,性能比RDD高2到3倍左右,比MR高5倍左右,同時,具有結構化的數據,可讀性更好。

DataFrame具有很好的易用性,支持多種語言,在一個上下文可以寫udf,具有部署一致性,以前寫HQL Transform的用戶可以試試Dataframe,在複雜統計分析中,有dataframe可以過程化編程,模塊化會更好,可讀性強。

Dataframe可以用df.rdd等方式轉化為RDD,處理更多靈活的操作。

Spark2.0推出DataSet,是更加強類型的API,用了scala的泛型,能在編譯是發現更多的編譯問題DataFrame是DataSet〈Row〉類型,DS在介面上和DataFrame很相似。感覺是為了和structured streaming 統一做鋪墊。

另外,看到Apache Beam這個google的開源項目正在用flume java的API統一google cloud api ,spark和flink這個和bigflow很像。

從用過dataframe的同事反饋,dataframe的易用性、性能都挺好。


通過這張圖已經能夠比較清晰的了解rdd和dataframe的基本特性,spark 1.6又引入了dateset的概念,這三者的特點如下:

rdd的優點:

1.強大,內置很多函數操作,group,map,filter等,方便處理結構化或非結構化數據

2.面向對象編程,直接存儲的java對象,類型轉化也安全

rdd的缺點:

1.由於它基本和hadoop一樣萬能的,因此沒有針對特殊場景的優化,比如對於結構化數據處理相對於sql來比非常麻煩

2.默認採用的是java序列號方式,序列化結果比較大,而且數據存儲在java堆內存中,導致gc比較頻繁

dataframe的優點:

1.結構化數據處理非常方便,支持Avro, CSV, elastic search, and Cassandra等kv數據,也支持HIVE tables, MySQL等傳統數據表

2.有針對性的優化,由於數據結構元信息spark已經保存,序列化時不需要帶上元信息,大大的減少了序列化大小,而且數據保存在堆外內存中,減少了gc次數。

3.hive兼容,支持hql,udf等

dataframe的缺點:

1.編譯時不能類型轉化安全檢查,運行時才能確定是否有問題

2.對於對象支持不友好,rdd內部數據直接以java對象存儲,dataframe內存存儲的是row對象而不能是自定義對象

dataset的優點:

1.dataset整合了rdd和dataframe的優點,支持結構化和非結構化數據

2.和rdd一樣,支持自定義對象存儲

3.和dataframe一樣,支持結構化數據的sql查詢

4.採用堆外內存存儲,gc友好

5.類型轉化安全,代碼友好

6.官方建議使用dataset


RDD可以看成能封裝任何數據類型的一個對象,有transform和action兩種方法。transform得到RDD,action得到計算結果。拿wordcount舉例,RDD可以用一個文本初始化,map之後變成另一個RDD,這個map屬於spark里的transform操作,這裡RDD封裝的key,value對再reduce就得到了結果,reduce屬於action操作。

Dataframe設計初衷應該也是提供更高層的抽象。之前接觸過spark的機器學習庫,是有mllib和ml兩個。mllib基於RDD運算,後來有了ml庫是基於Dataframe的,這樣感覺與以前單機python的sklearn加pandas的工作流更接近。Dataframe也是pandas的一個基本數據類型。


額,我才了解竟然還有這個東東,那趕緊用上,多謝


個人理解就是,rdd可以看做是一個數組,然后里面的每一個元素可能會被執行一樣的獨立的操作。。我理解的rdd其實可以看做是一種抽象,或者是一個協議,你和spark負責不同的工作,你的工作是把你想做的事情轉化成對於一大堆元素的相同的獨立的操作,spark就會幫你解決比如把數據分到不同的node上啊分配資源啊之類的各種並行具體的細節,你就不用操心這些底層的事情了。。

dataframe我感覺就是一行就是rdd里的一個元素。


推薦閱讀:

用什麼軟體可以切割10個G的txt數據?
為什麼學校里學習雲計算或者大數據都要從hadoop開始?
matlab將多個文件夾下的,多個txt中的行數據合併,速度慢,怎麼優化代碼?(並行計算已測試也很慢)
大數據培訓出來就業情況如何?
有沒有data science博士專業,哪個學校比較好,不限國別?

TAG:Hadoop | 大數據 | Spark |