[英]Spark 2.0 Dataset vs DataFrame
從 spark 2.0.1 開始我有一些問題。 我閱讀了很多文檔,但到目前為止找不到足夠的答案:
df.select("foo")
df.select($"foo")
myDataSet.map(foo.someVal)
是類型安全的,不會轉換為RDD
而是保留在 DataSet 表示中/沒有額外的開銷(2.0.0 的性能明智)df.select("foo")
類型安全?
df.select("foo")
和df.select($"foo")
之間的df.select("foo")
是簽名。 前一個需要至少一個String
,后一個需要零個或多個Columns
。 除此之外沒有任何實際區別。 myDataSet.map(foo.someVal)
類型檢查,但由於任何Dataset
操作都使用對象的RDD
,並且與DataFrame
操作相比,有很大的開銷。 我們來看一個簡單的例子:
case class FooBar(foo: Int, bar: String) val ds = Seq(FooBar(1, "x")).toDS ds.map(_.foo).explain
== Physical Plan == *SerializeFromObject [input[0, int, true] AS value#123] +- *MapElements <function1>, obj#122: int +- *DeserializeToObject newInstance(class $line67.$read$$iw$$iw$FooBar), obj#121: $line67.$read$$iw$$iw$FooBar +- LocalTableScan [foo#117, bar#118]
如您所見,此執行計划需要訪問所有字段,並且必須是DeserializeToObject
。
不。一般來說,其他方法不是語法糖,會生成明顯不同的執行計划。 例如:
ds.select($"foo").explain
== Physical Plan == LocalTableScan [foo#117]
與之前顯示的計划相比,它可以直接訪問列。 這與其說是 API 的限制,不如說是操作語義差異的結果。
如果沒有 map 語句,我怎么能 df.select("foo") 類型安全?
沒有這樣的選擇。 類型列允許您將靜態Dataset
轉換為另一個靜態類型Dataset
:
ds.select($"bar".as[Int])
沒有類型安全。 還有一些其他嘗試包括類型安全的優化操作,比如類型化聚合,但是這個實驗性的 API。
為什么我應該使用 UDF / UADF 而不是地圖
這完全取決於你。 Spark 中的每個分布式數據結構都有自己的優點和缺點(例如,參見Spark UDAF with ArrayType as bufferSchema performance issues )。
就我個人而言,我發現靜態類型的Dataset
是最沒用的:
不要提供與Dataset[Row]
相同范圍的優化(盡管它們共享存儲格式和一些執行計划優化,但它並沒有完全受益於代碼生成或堆外存儲),也不要訪問DataFrame
所有分析功能.
類型轉換是黑盒,有效地為優化器創建分析障礙。 例如選擇(過濾器)不能被推到類型轉換上:
ds.groupBy("foo").agg(sum($"bar") as "bar").as[FooBar].filter(x => true).where($"foo" === 1).explain
== Physical Plan == *Filter (foo#133 = 1) +- *Filter <function1>.apply +- *HashAggregate(keys=[foo#133], functions=[sum(cast(bar#134 as double))]) +- Exchange hashpartitioning(foo#133, 200) +- *HashAggregate(keys=[foo#133], functions=[partial_sum(cast(bar#134 as double))]) +- LocalTableScan [foo#133, bar#134]
相比:
ds.groupBy("foo").agg(sum($"bar") as "bar").as[FooBar].where($"foo" === 1).explain
== Physical Plan == *HashAggregate(keys=[foo#133], functions=[sum(cast(bar#134 as double))]) +- Exchange hashpartitioning(foo#133, 200) +- *HashAggregate(keys=[foo#133], functions=[partial_sum(cast(bar#134 as double))]) +- *Filter (foo#133 = 1) +- LocalTableScan [foo#133, bar#134]
這會影響謂詞下推或投影下推等功能。
不像RDDs
那樣靈活,只有一小部分本地支持的類型。
as
方法轉換Dataset
時, Encoders
“類型安全”是有爭議的。 因為數據形狀不是使用簽名編碼的,所以編譯器只能驗證Encoder
的存在。相關問題:
Spark Dataset
比 Spark Dataframe
強大得多。 小例子 - 您只能創建Row
、 Tuple
或任何原始數據類型的Dataframe
,但Dataset
使您能夠創建任何非原始類型的Dataset
。 即您可以從字面上創建對象類型的Dataset
。
例如:
case class Employee(id:Int,name:String)
Dataset[Employee] // is valid
Dataframe[Employee] // is invalid
DATAFRAME:DataFrame 是一種抽象,它允許數據的模式視圖。
case class Person(name: String, age: Int, address: String)
定義類 Person
scala > val df = List ( Person ( “Sumanth”, 23, “BNG”)
DATASET:Data Set 是 Dataframe API 的擴展,它是最新的抽象,它試圖提供 RDD 和 Dataframe 的最佳功能。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.