Datasets and DataFrames
前言 源碼 DataFrame Dataset 建立dataset 讀取json串 RDD轉換為Dataset 總結 DataFrame 總結
前言
spark1.6中引入了DataSet和DataFrame的概念,然後Spark SQL的API也是基於這兩個概念的,到2.2推出的穩定版本的Structured Streaming也是依靠Spark SQL的API,到Spark MLib也開始由RDD的API轉換為DataFrame的API,這一步步的動作表示,未來的Spark根基是DataSet。所以也就引出了這篇文章,作者意圖把DataSet認真的瞭解一下。 源碼
我們先來看看這兩個對象的源碼。 DataFrame
package object sql { ... type DataFrame = Dataset[Row]}
可以看出DataFrame是Dataset的特例,所以我先瞭解Dataset這個介面。 Dataset
private[sql] object Dataset { def apply[T: Encoder](sparkSession: SparkSession, logicalPlan: LogicalPlan): Dataset[T] = { new Dataset(sparkSession, logicalPlan, implicitly[Encoder[T]]) } def ofRows(sparkSession: SparkSession, logicalPlan: LogicalPlan): DataFrame = { val qe = sparkSession.sessionState.executePlan(logicalPlan) qe.assertAnalyzed() new Dataset[Row](sparkSession, qe, RowEncoder(qe.analyzed.schema)) }}class Dataset[T] private[sql]( @transient val sparkSession: SparkSession, @DeveloperApi @InterfaceStability.Unstable @transient val queryExecution: QueryExecution, encoder: Encoder[T]) extends Serializable {
Dataset類似於RDD,但是,不同於RDD的是,Dataset有特殊的編碼器去序列化Jvm對象以及網路資料,開發過spark程式的都知道,之前RDD一般會使用kryo或者java序列化器來做這些工作。序列化是把對象序列化成二進位,Dataset可以直接操作位元據,進行相關的轉換操作,這比RDD要強大。
因為Dataset是強型別資料集,使用時必須說明資料類型。 建立dataset
case class Person(name: String, age: Int) def main(args: Array[String]): Unit = { import spark.implicits._ val caseClassDF = Seq(Person("Andy", 32)).toDS caseClassDF.show() }
上面代碼會自動把資料對應為一張表,表的列名分別是name和age。我們來看一下執行結果:
+----+---+|name|age|+----+---+|Andy| 32|+----+---+
可以看出來,sparksession自動將一個Person對象作為表中一條資料。
如果我們不用Person封裝呢,代碼修改成如下:
> val caseClassDF = Seq("Andy", "doctorq").toDS+-------+| value|+-------+| Andy||doctorq|+-------+
預設給出一個列名”value”,每一條資料當成一個記錄。如果一行資料有多個屬性,還是用對象封裝一下比較方便。 讀取json串
val path = "src/main/resources/people.json" val peopleDS = spark.read.json(path).as[Person] peopleDS.show()
SparkSession提供的讀取外部檔案的介面非常的簡單。 RDD轉換為Dataset
val peopleDF = spark.sparkContext .textFile("src/main/resources/people.txt") .map(_.split(",")) .map(attributes => Person(attributes(0), attributes(1).trim.toInt)) .toDS()總結
得到DataSet對象的方式有很多,普通的集合,讀取外部資料,都可以很方便的轉換為DS,但是要記得引入隱式轉換。import spark.implicits._,但是有一點就是需要指定類型。 DataFrame
DataFrame為Dataset類型為Row對象,我們來看一下Row對象:
定義了行中的元素個數,資料類型schema,用來定義屬性類型。這個Row也類似一個集合類型,裡面定義了集合的大小,以及每個元素的類型,還定義了一些擷取某個位置的值。
我們在之前說Dataset之前,都說了建立Dataset都要指定資料類型,而DataFrame是特殊的,只需要用Row太泛指,其他交給Row來處理,這就把一些無法定義對象的,用DF來代替了。 總結
Dataset作為新版本的spark基礎資料集,未來還將逐漸替代RDD,正式成為底層支援,目前的流式計算和機器學習庫的轉移,都是這方面的訊號。之前看文章說Dataset是繼承RDD的,但實際上是獨立存在的,不過可以由RDD轉換而來。