在手动编写Spark数据帧的整个架构不可行的情况下(当数据帧中可能有很多字段)并且您具有该数据帧的预期架构时,最省时的方法是声明代码中预期的模式?
详细信息:
MapType
和ArrayType
StructFields
),并且由于字段数量众多,将整个架构声明为val schema = StructType(Array(StructField("colName", ...
为此,您想自动化在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))
但是,这不能编译。要使其编译,您必须执行以下操作:
StructType
,Array
或List
中的每个Seq
中,即StructType(StructField(Names,ArrayType....
-> StructType(Array(StructField(Names,ArrayType....
。如您所见,这对于小型架构是可以的,但对于大型架构则无法手动扩展。
但是,可能的解决方案是仅将数据的一部分存储到磁盘上,以用于其架构。因此,在读取新文件时,您可以使用所维护的子集的架构在新数据集上实施架构。我不喜欢这种解决方案,因为它感觉很笨拙,希望找到一种快速的方法来提取模式的代码表示形式。
答案 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]