[英]Cast values of a Spark dataframe using a defined StructType
有沒有一種方法可以使用StructType轉換數據幀的所有值?
讓我用一個例子解釋我的問題:
假設我們從文件讀取后獲得了一個數據框(我提供了生成該數據框的代碼,但是在我的真實世界項目中,我從文件讀取后獲得了該數據框):
import org.apache.spark.sql.{Row, SparkSession}
import org.apache.spark.sql.types._
import org.apache.spark.sql.functions._
import spark.implicits._
val rows1 = Seq(
Row("1", Row("a", "b"), "8.00", Row("1","2")),
Row("2", Row("c", "d"), "9.00", Row("3","4"))
)
val rows1Rdd = spark.sparkContext.parallelize(rows1, 4)
val schema1 = StructType(
Seq(
StructField("id", StringType, true),
StructField("s1", StructType(
Seq(
StructField("x", StringType, true),
StructField("y", StringType, true)
)
), true),
StructField("d", StringType, true),
StructField("s2", StructType(
Seq(
StructField("u", StringType, true),
StructField("v", StringType, true)
)
), true)
)
)
val df1 = spark.createDataFrame(rows1Rdd, schema1)
println("Schema with nested struct")
df1.printSchema()
root
|-- id: string (nullable = true)
|-- s1: struct (nullable = true)
| |-- x: string (nullable = true)
| |-- y: string (nullable = true)
|-- d: string (nullable = true)
|-- s2: struct (nullable = true)
| |-- u: string (nullable = true)
| |-- v: string (nullable = true)
現在,假設我的客戶端為我提供了他想要的數據的架構(與讀取的數據框的架構等效,但是具有不同的數據類型(包含StringTypes,IntegerTypes ...)):
val wantedSchema = StructType(
Seq(
StructField("id", IntegerType, true),
StructField("s1", StructType(
Seq(
StructField("x", StringType, true),
StructField("y", StringType, true)
)
), true),
StructField("d", DoubleType, true),
StructField("s2", StructType(
Seq(
StructField("u", IntegerType, true),
StructField("v", IntegerType, true)
)
), true)
)
)
使用提供的StructType轉換數據框的值的最佳方法是什么?
如果有一種方法可以應用到數據幀上,那就很不錯了,它可以通過強制轉換所有值來應用新的StructType。
PS:這是一個小的數據框,僅作為示例,在我的項目中,該數據框包含更多行。 如果這是一個只有幾列的小型Dataframe,我可以很容易地進行轉換,但就我而言,我正在尋找一種智能的解決方案,可以通過應用StructType來轉換所有值,而不必手動轉換每個列/值。編碼。
我將很感激您能提供的任何幫助,非常感謝!
沒有自動執行轉換的方法。 您可以在Spark SQL中表達轉換邏輯,以便一次轉換所有內容-但是,如果您有很多字段,那么生成的SQL可能會變得很大。 但是至少您可以將所有轉換都放在一個地方。
例:
df1.selectExpr("CAST (id AS INTEGER) as id",
"STRUCT (s1.x, s1.y) AS s1",
"CAST (d AS DECIMAL) as d",
"STRUCT (CAST (s2.u AS INTEGER), CAST (s2.v AS INTEGER)) as s2").show()
要注意的一件事是,每當轉換失敗時(例如,當d
不是數字時),您將得到NULL
。 一種選擇是在轉換之前運行一些驗證,然后過濾掉df1
記錄以僅轉換有效的記錄。
經過大量研究,這里有一個通用的解決方案,可以按照模式強制轉換數據框:
val castedDf = df1.selectExpr(wantedSchema.map(
field => s"CAST ( ${field.name} As ${field.dataType.sql}) ${field.name}"
): _*)
這是強制轉換的數據框的架構:
castedDf.printSchema
root
|-- id: integer (nullable = true)
|-- s1: struct (nullable = true)
| |-- x: string (nullable = true)
| |-- y: string (nullable = true)
|-- d: double (nullable = true)
|-- s2: struct (nullable = true)
| |-- u: integer (nullable = true)
| |-- v: integer (nullable = true)
我希望它能對某人有所幫助,我花了5天的時間尋找這種簡單/通用的解決方案。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.