如何 select 动态构造 spark dataframe 中的列?

How to select struct column in spark dataframe dynamically?

我正在尝试推断结构的模式并构建一个列表,该列表包含 dataframe.The 的 select 列列表中的结构字段(用 col 括起来,替换为 _ 作为别名) struct fields(properties) 是可选的,所以我想根据输入数据构造 select 语句。

模式推断为:

  val listOfProperties = explodeFeatures.schema
     .filter(c => c.name == "listOfFeatures")
     .flatMap(_.dataType.asInstanceOf[StructType].fields).filter(y => y.name == "properties").flatMap(_.dataType.asInstanceOf[StructType].fields)
     .map(_.name).map(x => "col(\"listOfFeatures.properties."+x+"\").as(\"properties_"+x.replace(":","_")+"\")")

上述语句的结果:(val listOfProperties)

col("type").as("type")
col("listOfFeatures.properties.a").as("properties_A"),
col("listOfFeatures.properties.b:P1").as("properties_b_P1"),
col("listOfFeatures.properties.C:ID").as("properties_C_ID"),
col("listOfFeatures.properties.D:l").as("properties_D_1")

Select声明:

explodeFeatures.select(listOfProperties .head , listOfProperties .tail : _*)

但是上面的语句在运行时解析失败。相反,如果我使用下面的硬编码,它就会成功。

explodeFeatures.select(
col("type").as("type"),
col("listOfFeatures.properties.a").as("properties_A"),
col("listOfFeatures.properties.b:P1").as("properties_b_P1"),
col("listOfFeatures.properties.C:ID").as("properties_C_ID"),
col("listOfFeatures.properties.D:l").as("properties_D_1"))

由于以下原因构建了一个列表,

需要访问结构变量, 需要重命名结构变量,因为它包含 : 在列名中。

谁能帮我解释为什么硬编码语句有效但 listOfProperties .head 、 listOfProperties .tail 无效?

异常:

Exception in thread "main" org.apache.spark.sql.AnalysisException: cannot resolve 'col("type")' given input columns: [type, listOfFeatures];;

正如评论中所建议的,您的变量是一个 Seq[String],当传递给 select 时,它看起来像 df.select("col(name)"),这使得它查找名称为 [=14= 的列] 而不是 name。您需要按如下方式更改最后一个 map

val listOfProperties = explodeFeatures.schema
     .filter(c => c.name == "listOfFeatures")
     .flatMap(_.dataType.asInstanceOf[StructType].fields)
     .filter(y => y.name == "properties")
     .flatMap(_.dataType.asInstanceOf[StructType].fields)
     .map(_.name)
      .map(x => col(s"listOfFeatures.properties.${x}").as(s"""properties_${x.replace(":","_")}""" ))

旁注:使用字符串插值。更干净了!