如何将两个 Spark Dataframe 与可以不同的结构类型字段合并?

5 struct scala apache-spark apache-spark-sql

我对 Apache Spark 还很陌生,有时仍然遇到困难。我正在尝试导入一个相当复杂的 JSON 文件并将其展平,然后再将其保存到镶木地板文件中。

我的 JSON 文件是一个商店树。

{
"id": "store02",
"name": "store name",
"domain": "domain",
"currency": "EUR",
"address1": "Somewhere",
"country": "GER",
"city": "Berlin",
"zipCode": "12345",
"timeZone": "CET",
"accounts" : [
    {
        "field1": "",
        "filed2": "",
        "field3": "",
        "optionnalArray1": [
            {
                "field1": "",
                "field2": ""
            }
        ],
        "optionnalArray2": ["aa", "bb"]
    }
],
"stores": [ .... ]    
}
Run Code Online (Sandbox Code Playgroud)

每个商店都可以有一个字段,该字段是帐户数组。帐户有 3 个必填字段和两个可选字段。所以我有一个数据框,其中的字段可以有 3 种不同的类型。

将文件导入数据框中没什么大不了的,但在展平过程中,我可能想对两个数据框进行联合,其帐户可能具有不同的架构,当然我有以下错误:

“只能在具有兼容列类型的表上执行联合”

有没有办法轻松做到这一点?Spark如何毫无问题地导入这样的JSON文件?


假设我有两个数据框。第一个是没有帐户的商店的数据框。第二个是具有帐户的商店的数据框。帐户是一个定义如下的结构体:

val acquirerStruct = StructType(
    StructField("merchantId", StringType, nullable = true) ::
    StructField("name", StringType, nullable = true) ::
    Nil)

val accountStruct = StructType(
    StructField("acquirers", ArrayType(acquirerStruct), nullable = true) ::
        StructField("applicationCode", StringType, nullable = true) ::
        StructField("channelType", StringType, nullable = true) ::
        StructField("id", StringType, nullable = true) ::
        StructField("terminals", ArrayType(StringType), nullable = true) ::
        Nil)
Run Code Online (Sandbox Code Playgroud)

当我想合并两个数据帧时,我之前为第一个数据帧创建了一个列帐户:

df1.withColumn("account", array(lit(null).cast(accountStruct))).union(df2)
Run Code Online (Sandbox Code Playgroud)

如果在 df2 中,所有行都有一个与 accountStruct 具有相同结构的帐户,则它可以正常工作。但事实并非总是如此。帐户可能没有终端或收单机构。这在 JSON 中是完全有效的。在这种情况下,我会遇到前面提到的错误。

“只能在具有兼容列类型的表上执行联合”

Uch*_*ara 0

我在 PySpark 中遇到了同样的问题,我通过在读取不兼容的数据帧时提供架构来解决它

import copy
...
schema_to_read = copy.deepcopy(df1.schema)
df2 = sql_context.read.format("json").schema(schema_to_read).load(path)
Run Code Online (Sandbox Code Playgroud)