Spark SQL學習——DataFrame和DataSet

Hiway發表於2019-04-04

其他更多java基礎文章:
java基礎學習(目錄)


學習資料:Spark-SQL之DataFrame基本操作
Spark SQL 函式全集
再談RDD、DataFrame、DataSet關係以及相互轉換(JAVA API)
DataFrame常用方法(程式碼詳細)
DataSet常用方法(程式碼詳細)

DataFrame基本原理

我們知道,RDD是spark早期很重要的一個概念,是資料的immutable distributed的集合,由不同節點上的partition組成。DataFrame和RDD類似,也是資料的不可變分散式集合。不同的是,資料被組織成帶名字的列,就像關係型資料庫中的表。是一種有結構的高階別抽象,與之相應的提供了一種領域特定語言(DSL)API來操作這些分散式資料。

Spark SQL學習——DataFrame和DataSet
DataFrame直觀上很像是RDDs的加強版,它和RDDs在資料儲存上最大的區別就在於,DataFrame是有Schema的,通俗的講,就是上圖中藍色框住的那個表頭。不要小看這一點,對於複雜的資料型別,DataFrame的這種結構可以使程式設計大大簡化。

在spark2.0後,DataFrame的API和DataSet的API合併統一了,DataFrame相當於DataSet[Row]。現在只需要處理DataSet相關API即可。

DataFrame的限制

  • 沒有編譯階段的型別檢查: 不能在編譯時刻對安全性做出檢查,而且限制了使用者對於未知結構的資料進行操作。比如下面程式碼在編譯時沒有錯誤,但是在執行時會出現異常:
case class Person(name : String , age : Int) 
val dataframe = sqlContect.read.json("people.json") 
dataframe.filter("salary > 10000").show 
=> throws Exception : cannot resolve 'salary' given input age , name
複製程式碼
  • 不能保留類物件的結構: 一旦把一個類結構的物件轉成了Dataframe,就不能轉回去了。下面這個栗子就是指出了:
case class Person(name : String , age : Int)
val personRDD = sc.makeRDD(Seq(Person("A",10),Person("B",20)))
val personDF = sqlContect.createDataframe(personRDD)
personDF.rdd // returns RDD[Row] , does not returns RDD[Person]
複製程式碼

DataSet

Dataset API是對DataFrame的一個擴充套件,使得可以支援型別安全的檢查,並且對類結構的物件支援程式介面。它是強型別的,不可變collection,並對映成一個相關的schema。 Dataset API的核心是一個被稱為Encoder的概念。它是負責對JVM的物件以及表格化的表達(tabular representation)之間的相互轉化。 表格化的表達在儲存時使用了Spark內建的Tungsten二進位制形式,允許對序列化資料操作並改進了記憶體使用。在Spark 1.6版本之後,支援自動化生成Encoder,可以對廣泛的primitive型別(比如String,Integer,Long等)、Scala的case class以及Java Bean自動生成對應的Encoder。

DataFrame也可以叫Dataset[Row],每一行的型別是Row,不解析,每一行究竟有哪些欄位,各個欄位又是什麼型別都無從得知,只能用上面提到的getAS方法或者共性中的第七條提到的模式匹配拿出特定欄位

而Dataset中,每一行是什麼型別是不一定的,在自定義了case class之後可以很自由的獲得每一行的資訊

DataFrame和DataSet的建立

park2.0以前,使用不同的資料型別,需要採用不同的入口類,如RDD對應的入口類是SparkContext,DataFrame對應的入口類是SQLContext或者HiveContext,入口類用於指定Spark叢集的各種引數,並與資源管理器做互動。

Spark2.0開始及之後,提出了一個統一的入口類SparkSession,封裝了SparkContext、SQLContext和HiveContext。具體程式碼可以看學習資料中的再談RDD、DataFrame、DataSet關係以及相互轉換(JAVA API)

  • 如果要建立RDD,需要通過SparkSession入口類獲取SparkContext入口類
  • 如果要建立DataFrame和DataSet,通過 SparkSession入口類即可。

建立DataFrame的幾種方式

SparkSQL初始和建立DataFrame的幾種方式

  • 1、讀取json格式的檔案建立DataFrame
  • 2、通過json格式的RDD建立DataFrame
  • 非json格式的RDD建立DataFrame(重要)
    • 通過反射的方式將非json格式的RDD轉換成DataFrame
    • 動態建立Schema將非json格式的RDD轉換成DataFrame(建議使用)

通過反射的方式將非json格式的RDD轉換成DataFrame

/**
* 傳入進去Person.class的時候,sqlContext是通過反射的方式建立DataFrame
* 在底層通過反射的方式獲得Person的所有field,結合RDD本身,就生成了DataFrame
*/
DataFrame df = sqlContext.createDataFrame(personRDD, Person.class);
df.show();
df.registerTempTable("person");
sqlContext.sql("select  name from person where id = 2").show();
複製程式碼

動態建立Schema將非json格式的RDD轉換成DataFrame

/**
* 動態構建DataFrame中的後設資料,一般來說這裡的欄位可以來源自字串,也可以來源於外部資料庫
*/
List<StructField> asList =Arrays.asList(//這裡欄位順序一定要和上邊對應起來
   DataTypes.createStructField("id", DataTypes.StringType, true),
   DataTypes.createStructField("name", DataTypes.StringType, true),
   DataTypes.createStructField("age", DataTypes.IntegerType, true)
);

StructType schema = DataTypes.createStructType(asList);
DataFrame df = sqlContext.createDataFrame(rowRDD, schema);

df.show();
複製程式碼

相關文章