从DataFrame中选择不属于某个架构的嵌套字段



假设我有一个具有以下模式的DataFrame:

{
a: IntegerType,
b: { // nested struct
c: StringType,
d: IntegerType
}
}

我想用另一种模式省略d

{
a: IntegerType,
b: { // nested struct
c: StringType
}
}

有没有一种方法可以通过编程从只包含第二个模式中的列的原始数据框中创建新的DataFrame?如果我这样做:

val finalDf = df.select([col for col in otherSchema])

则它仍将获得CCD_ 2,因为CCD_。

同样,如果我有一个非常复杂的模式,其中只改变了最深层,我该怎么做?例如,原始DataFrame有一个类似于的模式

Array
(Struct
(Array
(Struct
(Array
(Struct
(a: INT, b: String)
)
)
)
)
)

我只想选择:

Array
(Struct
(Array
(Struct
(Array
(Struct
(a: INT)
)
)
)
)
)

下面是一个变换的草图,它允许您执行类似的操作。其思想是根据新的目标模式将数据从输入struct选择为输出struct

def transformSchema[T](target: StructType)(ds: Dataset[T]): DataFrame = {
import org.apache.spark.sql.functions.{col, struct, transform}
def toType(column: Column, currentDt: DataType, targetDt: DataType): Column = {
(currentDt, targetDt) match {
case (_, `currentDt`) => column
case (StructType(currentFields), StructType(targetFields)) =>
val columns = targetFields.toSeq.flatMap {
case StructField(name, target, _, _) =>
currentFields.collectFirst {
case StructField(`name`, current, _, _) =>
toType(column.getField(name), current, target).as(name)
}
}
struct(columns: _*)
case (ArrayType(current, _), ArrayType(target, _)) =>
transform(column, toType(_, current, target))
// Note: Cases to handle incompatible target schemas are missing here
case _ =>
column
}
}
ds
.select(toType(struct(ds.columns.map(col): _*), ds.schema, target).as("col"))
.select(target.fields.map(f => col("col").getField(f.name).as(f.name)): _*)
}

最新更新