[英]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.