从当前数据框架的架构中编写Spark数据框架的架构(以代码形式)

时间:2019-10-16 19:58:38

标签: dataframe apache-spark apache-spark-sql schema

在手动编写Spark数据帧的整个架构不可行的情况下(当数据帧中可能有很多字段)并且您具有该数据帧的预期架构时,最省时的方法是声明代码中预期的模式?

详细信息:

  1. 假设您的数据框包含很多字段(可能包含MapTypeArrayType StructFields),并且由于字段数量众多,将整个架构声明为val schema = StructType(Array(StructField("colName", ...
  2. 您知道数据框的当前架构是您希望数据框将来始终具有的架构。

为此,您想自动化在Scala中声明架构的过程(如第1点中的代码),以便下次您必须声明期望的架构时,可以节省时间。有没有一种经过实践检验的方法?

例如,如果当前数据框的架构为:

root
 |-- Names: array (nullable = true)
 |    |-- element: struct (containsNull = true)
 |    |    |-- additionalMetadata: struct (nullable = true)
 |    |    |    |-- value: string (nullable = true)
 |    |    |    |-- key: string (nullable = true)
 |    |    |-- name: string (nullable = true)

以代码形式获取架构:

val schema = StructType(Array(
  StructField("Names", ArrayType(StructType(Array(
    StructField("AdditionalMetadata", StructType(Array(
      StructField("value", StringType),
      StructField("key", StringType)
    ))),
    StructField("name", StringType)
  ))))
))

以代码表示的架构可以在读取spark.read.schema之类的数据框时用于强制架构。

TLDR :给定一个Spark Dataframe,在代码中获取架构的声明。

更新 我看到dataframe.schema的输出与我想要的类似。这是打印dataframe.schema时的输出示例:

StructType(StructField(Names,ArrayType(StructType(StructField(AdditionalMetadata,StructType(StructField(value,StringType,true), StructField(key,StringType,true)),true), StructField(name,StringType,true)),true),true))

但是,这不能编译。要使其编译,您必须执行以下操作:

  1. 在字段名称(即“名称”,“ AdditionalMetadata”,“值”)周围加上双引号。
  2. 将所有元素放入StructTypeArrayList中的每个Seq中,即StructType(StructField(Names,ArrayType....-> StructType(Array(StructField(Names,ArrayType....

如您所见,这对于小型架构是可以的,但对于大型架构则无法手动扩展。

但是,可能的解决方案是仅将数据的一部分存储到磁盘上,以用于其架构。因此,在读取新文件时,您可以使用所维护的子集的架构在新数据集上实施架构。我不喜欢这种解决方案,因为它感觉很笨拙,希望找到一种快速的方法来提取模式的代码表示形式。

1 个答案:

答案 0 :(得分:1)

您可以使用df获得数据框df.schema的架构。该模式可以直接在spark.read.schema中使用,因此不需要将模式作为可编译代码获得。例如:

val df = ...
val df2 = spark.read.schema(df.schema).csv(...)

要保留多次运行的模式,可以使用以下命令将其另存为json:

val jsonString = df.schema.json

您现在可以将该字符串保存到文件(或程序中的硬代码)中,以备后用。请注意,如果需要,还可以轻松调整json字符串,就像您具有可编译的代码一样。

将架构转换为json后,要在之后将其恢复为正确的类型,您需要执行以下操作:

val schema = DataType.fromJson(jsonString).asInstanceOf[StructType]