[英]How to convert a simple DataFrame to a DataSet Spark Scala with case class?
[英]How to convert Row of a Scala DataFrame into case class most efficiently?
一旦我在Spark中獲得了一些Row類,無論是Dataframe還是Catalyst,我想將它轉換為我的代碼中的case類。 這可以通過匹配來完成
someRow match {case Row(a:Long,b:String,c:Double) => myCaseClass(a,b,c)}
但是當行有大量的列,比如十幾個雙打,一些布爾,甚至偶爾的空位時,它變得丑陋。
我想能夠將-all-cast轉換為myCaseClass。 是否可能,或者我已經獲得了最經濟的語法?
DataFrame只是Dataset [Row]的類型別名。 與強類型Scala / Java數據集一起提供的“類型轉換”相比,這些操作也稱為“無類型轉換”。
從數據集[Row]到Dataset [Person]的轉換在spark中非常簡單
val DFtoProcess = SQLContext.sql("SELECT * FROM peoples WHERE name='test'")
此時,Spark將您的數據轉換為DataFrame = Dataset [Row],這是一個通用Row對象的集合,因為它不知道確切的類型。
// Create an Encoders for Java class (In my eg. Person is a JAVA class)
// For scala case class you can pass Person without .class reference
val personEncoder = Encoders.bean(Person.class)
val DStoProcess = DFtoProcess.as[Person](personEncoder)
現在,Spark轉換Dataset[Row] -> Dataset[Person]
類型特定的Scala / Java JVM對象,由Person類指定。
有關詳細信息,請參閱databricks提供的以下鏈接
據我所知,你不能將一行寫入一個案例類,但我有時會選擇直接訪問行字段,比如
map(row => myCaseClass(row.getLong(0), row.getString(1), row.getDouble(2))
我發現這更容易,特別是如果case類構造函數只需要行中的某些字段。
scala> import spark.implicits._
scala> val df = Seq((1, "james"), (2, "tony")).toDF("id", "name")
df: org.apache.spark.sql.DataFrame = [id: int, name: string]
scala> case class Student(id: Int, name: String)
defined class Student
scala> df.as[Student].collectAsList
res6: java.util.List[Student] = [Student(1,james), Student(2,tony)]
spark.implicits._
的spark
是你的SparkSession
。 如果您在REPL中,則會話已定義為spark
否則您需要相應地調整名稱以對應SparkSession
。
當然,您可以將Row對象匹配到案例類中。 假設您的SchemaType有很多字段,並且您希望將它們中的一些匹配到您的案例類中。 如果您沒有空字段,則可以執行以下操作:
case class MyClass(a: Long, b: String, c: Int, d: String, e: String)
dataframe.map {
case Row(a: java.math.BigDecimal,
b: String,
c: Int,
_: String,
_: java.sql.Date,
e: java.sql.Date,
_: java.sql.Timestamp,
_: java.sql.Timestamp,
_: java.math.BigDecimal,
_: String) => MyClass(a = a.longValue(), b = b, c = c, d = d.toString, e = e.toString)
}
在空值的情況下,此方法將失敗,並且還要求您明確定義每個單個字段的類型。 如果必須處理空值,則需要通過執行操作丟棄包含空值的所有行
dataframe.na.drop()
即使空字段不是您的案例類的模式匹配中使用的空字段,也會丟棄記錄。 或者,如果要處理它,可以將Row對象轉換為List,然后使用選項模式:
case class MyClass(a: Long, b: String, c: Option[Int], d: String, e: String)
dataframe.map(_.toSeq.toList match {
case List(a: java.math.BigDecimal,
b: String,
c: Int,
_: String,
_: java.sql.Date,
e: java.sql.Date,
_: java.sql.Timestamp,
_: java.sql.Timestamp,
_: java.math.BigDecimal,
_: String) => MyClass(
a = a.longValue(), b = b, c = Option(c), d = d.toString, e = e.toString)
}
檢查這個github項目Sparkz(),它將很快引入很多庫來簡化Spark和DataFrame API,並使它們更具功能性。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.