#scala #apache-spark #apache-spark-sql
#scala #apache-spark #apache-spark-sql
Вопрос:
Как я могу получить все имена массивов в Dataframe?
Проблема в том, что я пытаюсь разнести ВСЕ массивы.
import org.apache.spark.sql.{Column, DataFrame, SparkSession}
import org.apache.spark.sql.functions.col
import org.apache.spark.sql.types.{ArrayType, StructField, StructType}
val providersDF=SIWINSDF.select(explode(col("**providers**")).as("collection")).select(col("collection.*"))
def flattenSchema(schema: StructType, prefix: String = null) : Array[Column] = {
schema.fields.flatMap(f => {
val colName = if (prefix == null) f.name else (prefix "." f.name)
f.dataType match {
case st: StructType => flattenSchema(st, colName)
case _ => Array(col(colName).alias(colName))
}
})
}
val newDF=providersDF.select(flattenSchema(providersDF.schema):_*)
newDF.toDF(newDF.columns.map(_.replace(".", "_")): _*).printSchema
Чтобы ПОЛУЧИТЬ все имена массивов, я пытаюсь сделать :
чтобы получить имена, я делаю df.schema.filter(st => st.DataType.isInstanceOf[ArrayType]).flatMap(.DataType.asInstanceOf[StructType].fields).map(.name)
Приветствуется любая помощь.
Ответ №1:
Вот рекурсивный метод, который извлекает все вложенные ArrayType
столбцы из DataFrame:
import org.apache.spark.sql.types._
def extractArrayCols(schema: StructType, prefix: String): Seq[String] =
schema.fields.flatMap {
case StructField(name, struct: StructType, _, _) => extractArrayCols(struct, prefix name ".")
case StructField(name, ArrayType(_, _), _, _) => Seq(s"$prefix$name")
case _ => Seq.empty[String]
}
Тестирование метода:
import org.apache.spark.sql.functions._
case class W(u: Int, v: Seq[String])
val df = Seq(
(10, Seq(1, 2), W(1, Seq("a", "b"))),
(20, Seq(3), W(2, Seq("c", "d")))
).toDF("c1", "c2", "c3")
val arrayCols = extractArrayCols(df.schema, "")
// arrayCols: Seq[String] = ArraySeq(c2, c3.v)
Комментарии:
1. @ Leo C Я также протестирую ваше решение, вот код, который работает с import org.apache.spark.sql.types. ArrayType val arrayFields = df.schema.filter(st => st.DataType.isInstanceOf[ArrayType]) имена значений = arrayFields.map(_.name)
2. @J-kram, ваш
arrayFields
будет захватывать только столбцы ArrayType верхнего уровня. Например, в моем примере это будет только find,c2
но неc3.v
.