Apache Spark吸引廣大社區開發者的一個重要原因是:Apache Spark提供極其簡單、易用的APIs,支持跨多種語言(比如:Scala、Java、Python和R)來操作大數據。
本文主要講解Apache Spark 2.0中RDD,DataFrame和Dataset三種API;它們各自適合的使用場景;它們的性能和優化;列舉使用DataFrame和DataSet代替RDD的場景。文章大部分聚焦DataFrame和Dataset,因為這是Apache Spark 2.0的API統一的重點。
Apache Spark 2.0統一API的主要動機是:追求簡化Spark。通過減少用戶學習的概念和提供結構化的數據進行處理。除了結構化,Spark也提供higher-level抽象和API作為特定領域語言(DSL)。
彈性數據集(RDD)
RDD是Spark建立之初的核心API。RDD是不可變分布式彈性數據集,在Spark集群中可跨節點分區,並提供分布式low-level API來操作RDD,包括transformation和action。
那什么時候用RDD呢?
使用RDD的一般場景:
- 你需要使用low-level的transformation和action來控制你的數據集;
- 你的數據集非結構化,比如:流媒體或者文本流;
- 你想使用函數式編程來操作你的數據,而不是用特定領域語言(DSL)表達;
- 你不在乎schema,比如,當通過名字或者列處理(或訪問)數據屬性不在意列式存儲格式;
- 你放棄使用DataFrame和Dataset來優化結構化和半結構化數據集。
RDD在Apache Spark 2.0中慘遭拋棄?
DataFrame
Language | Main Abstraction |
---|---|
Scala | Dataset[T] & DataFrame (alias for Dataset[Row]) |
Java | Dataset<T> |
Python* | DataFrame |
R* | DataFrame |
Dataset API的優勢
2. High-level抽象以及結構化和半結構化數據集的自定義視圖![]()
{ "device_id": 198164, "device_name": "sensor-pad-198164owomcJZ", "ip": "80.55.20.25", "cca2": "PL", "cca3": "POL", "cn": "Poland", "latitude": 53.08, "longitude": 18.62, "scale": "Celsius", "temp": 21, "humidity": 65, "battery_level": 8, "c02_level": 1408, "lcd": "red", "timestamp": 1458081226051 }
case class DeviceIoTData (battery_level: Long, c02_level: Long, cca2: String, cca3: String, cn: String, device_id: Long, device_name: String, humidity: Long, ip: String, latitude: Double, lcd: String, longitude: Double, scale:String, temp: Long, timestamp: Long)
- Spark讀取JSON文件,推斷出其schema,創建一個DataFrame;
- Spark把數據集轉換DataFrame -> Dataset[Row],泛型Row object,因為這時還不知道其確切類型;
- Spark進行轉換:Dataset[Row] -> Dataset[DeviceIoTData],DeviceIoTData類的Scala JVM object。
4. 性能和優化
使用DataFrame和Dataset API獲得空間效率和性能優化的兩個原因:
首先,DataFrame和Dataset API是建立在Spark SQL引擎之上,它會使用Catalyst優化器來生成優化過的邏輯計划和物理查詢計划。R,Java,Scala或者Python的DataFrame/Dataset API使得查詢都進行相同的代碼優化以及空間和速度的效率提升。
其次,Spark作為編譯器可以理解Dataset類型的JVM object,它能映射特定類型的JVM object到Tungsten內存管理,使用Encoder。Tungsten的Encoder可以有效的序列化/反序列化JVM object,生成字節碼來提高執行速度。
什么時候使用DataFrame或者Dataset?
- 你想使用豐富的語義,high-level抽象,和特定領域語言API,那你可以使用DataFrame或者Dataset;
- 你處理的半結構化數據集需要high-level表達,filter,map,aggregation,average,sum,SQL查詢,列式訪問和使用lambda函數,那你可以使用DataFrame或者Dataset;
- 你想利用編譯時高度的type-safety,Catalyst優化和Tungsten的code生成,那你可以使用DataFrame或者Dataset;
- 你想統一和簡化API使用跨Spark的Library,那你可以使用DataFrame或者Dataset;
- 如果你是一個R使用者,那你可以使用DataFrame或者Dataset;
- 如果你是一個Python使用者,那你可以使用DataFrame或者Dataset。
// select specific fields from the Dataset, apply a predicate // using the where() method, convert to an RDD, and show first 10 // RDD rows val deviceEventsDS = ds.select($"device_name", $"cca3", $"c02_level").where($"c02_level" > 1300) // convert to RDDs and take the first 10 rows val eventsRDD = deviceEventsDS.rdd.take(10)
總結
通過上面的分析,什么情況選擇RDD,DataFrame還是Dataset已經很明顯了。RDD適合需要low-level函數式編程和操作數據集的情況;DataFrame和Dataset適合結構化數據集,使用high-level和特定領域語言(DSL)編程,空間效率高和速度快。