Spark разделил вложенный JSON на ряды - PullRequest
0 голосов
/ 01 июля 2018

Я пытаюсь разбить несколько довольно сложных вложенных 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 в образце полезной нагрузки).

Учетная запись, идентификатор учетной записи и проверочные ключи являются прямыми для выбора из кадра данных.

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), и они меняются, поэтому, возможно, мне нужно сначала создать массив.

Есть мысли?

1 Ответ

0 голосов
/ 01 июля 2018

Если введены dataframe и schema, как показано ниже

+-------------------------------------------------------------------------------------------+
|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 array и explode, как показано ниже, чтобы получить желаемый результат как

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      |
+------------+------+--------------+-------+

Надеюсь, ответ полезен

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...