【问题标题】:Spark split nested json into rowsSpark 将嵌套的 json 拆分为行
【发布时间】:2018-12-09 21:39:00
【问题描述】:

我正在尝试将一些相当复杂的嵌套 json 拆分为更合理的格式,但我正在努力扩展一个在我的数据集中更改名称的键。

我的数据集如下所示:

{
    "account": {
       "accountID":  "test_account",
        "name": "abc123",
        "checks": {
            "abc123": {
                "check1":  "pass",
                "check2": "fail",
                "check3": 0
               },
            "xzy7892": {
                "check1":  "pass",
                "check2": "fail",
                "check3": 0,
                "result": { 
                    "item1": 1,
                    "item2": 2
                }
            },
            "foobar11012387": {
                "check1":  "fail",
                "check2": "pass",
                "check3": 0,
                "result": {
                    "item1": 1,
                    "item2": 2
                    }
                }
            }
        }
}

我无法控制架构,因此只能使用给定的内容。本质上,有效负载被分解为各种检查,但每个检查都有一个唯一的名称(示例有效负载中的 abc123、xzy7892 和 foobar1012387)。

帐户、帐户 ID 和检查键可以直接从数据框中选择。

df2.select(['account.accountID', 'account.checks']).show()
+------------+--------------------+
|   accountID|              checks|
+------------+--------------------+
|test_account|[[pass, fail, 0],...|
+------------+--------------------+

但我可以比这一点更进一步(即 account.checks.abc123.check1)。最终,我想将这三个检查合理化到数据框中它们自己的行中,但由于检查键发生了变化,我不太确定如何去做。

| accountID | check_name | check1 | check2 | check3 | result |
+-----------|------------|--------|--------|--------|--------|
| test_account | abc123  | pass   | fail   | 0      | null   |
| test_account | xyz7892 | pass   | fail   | 0      | [1, 2] |
| test_account | foobar11012387 | fail   | pass   | 0      | [1, 2] |

我希望 DF 看起来类似于上表(我没有展开结果,但我可以更进一步)。我不提前知道测试的名称(即 abc123、xzy7892),它们确实发生了变化,所以也许我需要先构建一个数组。

有什么想法吗?

【问题讨论】:

  • 感谢您的帖子,它给了我一些关于我应该去的方向的指示。

标签: json apache-spark pyspark


【解决方案1】:

如果您输入的dataframeschema 如下

+-------------------------------------------------------------------------------------------+
|account                                                                                    |
+-------------------------------------------------------------------------------------------+
|[test_account, [[pass, fail, 0], [fail, pass, 0, [1, 2]], [pass, fail, 0, [1, 2]]], abc123]|
+-------------------------------------------------------------------------------------------+

root
 |-- account: struct (nullable = true)
 |    |-- accountID: string (nullable = true)
 |    |-- checks: struct (nullable = true)
 |    |    |-- abc123: struct (nullable = true)
 |    |    |    |-- check1: string (nullable = true)
 |    |    |    |-- check2: string (nullable = true)
 |    |    |    |-- check3: long (nullable = true)
 |    |    |-- foobar11012387: struct (nullable = true)
 |    |    |    |-- check1: string (nullable = true)
 |    |    |    |-- check2: string (nullable = true)
 |    |    |    |-- check3: long (nullable = true)
 |    |    |    |-- result: struct (nullable = true)
 |    |    |    |    |-- item1: long (nullable = true)
 |    |    |    |    |-- item2: long (nullable = true)
 |    |    |-- xzy7892: struct (nullable = true)
 |    |    |    |-- check1: string (nullable = true)
 |    |    |    |-- check2: string (nullable = true)
 |    |    |    |-- check3: long (nullable = true)
 |    |    |    |-- result: struct (nullable = true)
 |    |    |    |    |-- item1: long (nullable = true)
 |    |    |    |    |-- item2: long (nullable = true)
 |    |-- name: string (nullable = true)

您可以使用struct arrayexplode 函数如下获得您想要的输出

checks1 = ['abc123', 'foobar11012387', 'xzy7892']
checks2 = ['check1', 'check2', 'check3']

from pyspark.sql import functions as f
df.select(f.col('account.accountID'), f.explode(f.array(*[f.struct([f.col('account.checks.'+y+'.'+x).cast('string').alias(y) for y in checks1]).alias(x) for x in checks2])).alias('temp'))\
    .select(f.col('accountID'), f.col('temp.*'))\
    .show(truncate=False)

这应该给你

+------------+------+--------------+-------+
|accountID   |abc123|foobar11012387|xzy7892|
+------------+------+--------------+-------+
|test_account|pass  |fail          |pass   |
|test_account|fail  |pass          |fail   |
|test_account|0     |0             |0      |
+------------+------+--------------+-------+

希望回答对你有帮助

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-09-28
    • 1970-01-01
    • 2020-12-06
    • 2022-01-07
    • 1970-01-01
    • 2023-04-06
    • 2017-08-24
    • 2020-04-24
    相关资源
    最近更新 更多