Могу ли я преобразовать сложный объект json в несколько строк в кадре данных в Azure кирпичи данных, используя pyspark? - PullRequest
0 голосов
/ 12 марта 2020

У меня есть какой-то json, который читается из файла, где каждая строка выглядит примерно так:

    {
        "id": "someGuid",
        "data": {
            "id": "someGuid",
            "data": {
                "players": {
                    "player_1": {
                        "id": "player_1",
                        "locationId": "someGuid",
                        "name": "someName",
                        "assets": {
                            "assetId1": {
                                "isActive": true,
                                "playlists": {
                                    "someId1": true,
                                    "someOtherId1": false
                                }
                            },
                            "assetId2": {
                                "isActive": true,
                                "playlists": {
                                    "someId1": true
                                }
                            }
                        }
                    },
                    "player_2": {
                        "id": "player_2",
                        "locationId": "someGuid",
                        "name": "someName",
                        "dict": {
                            "assetId3": {
                                "isActive": true,
                                "playlists": {
                                    "someId1": true,
                                    "someOtherId1": false
                                }
                            },
                            "assetId4": {
                                "isActive": true,
                                "playlists": {
                                    "someId1": true
                                }
                            }
                        }
                    }
                }
            },
            "lastRefreshed": "2020-01-23T19:29:15.6354794Z",
            "expiresAt": "9999-12-31T23:59:59.9999999",
            "dataSourceId": "someId"
        }
    }

У меня возникают трудности при попытке найти способ, используя python или sql в pyspark на Azure Блоки данных, чтобы превратить это json в табличный формат, подобный следующему:

+===========+=============+===============+===========+==============+=============+=================+
| Location  | Player_ID   |    Player     | Asset_ID  | Asset_Active | Playlist_ID | Playlist_Status |
+===========+=============+===============+===========+==============+=============+=================+
|  someId   | player_1    | ThisIsAPlayer | anotherId | TRUE         | someOtherId | FALSE           |
+-----------+-------------+---------------+-----------+--------------+-------------+-----------------+

Задача состоит в том, чтобы преобразовать указанное выше свойство Players в несколько строк в каждой локации. Местоположение может иметь любое количество игроков с разными идентификаторами. Возможно, я бы не задавал этот вопрос, если бы свойство Players было массивом объектов проигрывателя вместо словаря, но я не имею никакого контроля над структурой этого документа, поэтому я должен работать с этим. Это не проблема в чем-то вроде PowerBI, где манипулирование данными более прямолинейно.

Самое дальнее, что мне удалось получить, - это сделать что-то вроде этого:

df = spark.read.json(filePath).select("data.id", "data.lastRefreshed", "data.expiresAt","data.dataSourceId","data.data.players.*")

Но это приводит к кадру / таблице данных, которая расширяет все вложенные структуры игроков ниже по столбцам. Я искал SO, ища кого-то с похожей ситуацией, но не повезло.

Как мне go разобрать / расширить столбец игроков в этом кадре данных, чтобы разделить строки?

В pyspark, я имею дело с Spark 2.4.3

1 Ответ

1 голос
/ 13 марта 2020

Вы можете попробовать функцию from_ json, чтобы преобразовать столбец / поле из StructType в MapType, развернуть и найти нужные поля. Например, JSON, вам нужно будет сделать это несколько раз:

from pyspark.sql.functions import explode, from_json, to_json, json_tuple, coalesce

df.select(explode(from_json(to_json('data.data.players'),"map<string,string>"))) \
  .select(json_tuple('value', 'locationId', 'id', 'name', 'assets', 'dict').alias('Location', 'Player_ID', 'Player', 'assets', 'dict')) \
  .select('*', explode(from_json(coalesce('assets','dict'),"map<string,struct<isActive:boolean,playlists:string>>"))) \
  .selectExpr(
    'Location',
    'Player_ID',
    'Player', 
    'key as Asset_ID',
    'value.isActive',  
    'explode(from_json(value.playlists, "map<string,string>")) as (Playlist_ID, Playlist_Status)'
  ) \
.show()
+--------+---------+--------+--------+--------+------------+---------------+
|Location|Player_ID|  Player|Asset_ID|isActive| Playlist_ID|Playlist_Status|
+--------+---------+--------+--------+--------+------------+---------------+
|someGuid| player_1|someName|assetId1|    true|     someId1|           true|
|someGuid| player_1|someName|assetId1|    true|someOtherId1|          false|
|someGuid| player_1|someName|assetId2|    true|     someId1|           true|
|someGuid| player_2|someName|assetId3|    true|     someId1|           true|
|someGuid| player_2|someName|assetId3|    true|someOtherId1|          false|
|someGuid| player_2|someName|assetId4|    true|     someId1|           true|
+--------+---------+--------+--------+--------+------------+---------------+
...