PySpark читает из Excel только с одним столбцом в формате json - PullRequest
0 голосов
/ 25 мая 2020

У меня есть данные, которые хранятся в Excel, но только один столбец имеет формат json. Я хочу сгладить этот столбец, и до сих пор я пробовал следующее:

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

Входные данные

[Row(point='["{\\"data\\":{\\"state\\":\\"IL\\"}}","{\\"data\\":{\\"state\\":\\"CA\\"}}","{\\"data\\":{\\"pop\\":\\"100\\",\\"band\\":\\"Rock\\"}}","{\\"data\\":{\\"pop\\":\\"200\\",\\"band\\":\\"Melody\\"}}","{\\"data\\":{\\"pop\\":\\"300\\",\\"band\\":\\"Race\\"}}"]', id='1abc'),  
 Row(point='["{\\"data\\":{\\"state\\":\\"IL\\"}}","{\\"data\\":{\\"state\\":\\"CA\\"}}","{\\"data\\":{\\"pop\\":\\"400\\",\\"band\\":\\"Rock\\"}}","{\\"data\\":{\\"pop\\":\\"500\\",\\"band\\":\\"Jazz\\"}}","{\\"data\\":{\\"pop\\":\\"500\\",\\"band\\":\\"Loops\\"}}"]', id='2cde')]

Ожидаемые выходные данные

id = 1abc, state = IL, pop = None, band = None
id = 1abc, state = CA, pop = None, band = None
id = 1abc, state = None, pop = 100, band = Rock
id = 1abc, state = None, pop = 200, band = Melody
id = 1abc, state = None, pop = 300, band = Race
id = 2cde, state = IL, pop = None, band = None
id = 2cde, state = CA, pop = None, band = None
id = 2cde, state = None, pop = 400, band = Rock
id = 2cde, state = None, pop = 500, band = Jazz
id = 2cde, state = None, pop = 500, band = Loops

Код на данный момент ..

# Read as pandas
pd_df = pd.read_excel('test.xlsx')

# Convert to spark df
schema = StructType([StructField("point", StringType(), True),
                StructField("id", StringType(), True)
                ])
df = spark.createDataFrame(pd_df, schema = schema)

# Do some cleaning to remove \\ and quotes
a = df.withColumn('point', regexp_replace(col('point'), "\\\\", ""))
b = a.withColumn('point', regexp_replace(col('point'), '}","', '},'))
c = b.withColumn('point', regexp_replace(col('point'), '\\["', '['))
d = c.withColumn('point', regexp_replace(col('point'), '\\"]', ']'))


# after cleaning
d.take(2)

[Row(point='[{"data":{"state":"IL"}},{"data":{"state":"CA"}},{"data":{"pop":"100","band":"Rock"}},{"data":{"pop":"200","band":"Melody"}},{"data":{"pop":"300","band":"Race"}}]', id='1abc'), Row(point='[{"data":{"state":"IL"}},{"data":{"state":"CA"}},{"data":{"pop":"400","band":"Rock"}},{"data":{"pop":"500","band":"Jazz"}},{"data":{"pop":"500","band":"Loops"}}]', id='2cde')]

# Flatten the point column

point_schema = score_schema = StructType([StructField("state", StringType(), True),
            StructField("band", StringType(), True),
            StructField("pop", IntegerType(), True)
           ])


final_df = d.withColumn('point', from_json('point', point_schema))

Результаты фрейма данных final_df всегда None, несмотря на указание point_schema. Я не уверен, почему он возвращает None. Любая помощь очень полезна

1 Ответ

0 голосов
/ 25 мая 2020

Используйте это -

final_df = d.withColumn('point', from_json('point', lit('array<struct<data:struct<band:string,pop:string,state:string>>>')))

вы можете изменить свою схему одинаково, как показано ниже -


point_schema = ArrayType(StructType([
      StructField("data", 
      StructType([
      StructField("state", StringType(),True),
      StructField("band", StringType(), True),
      StructField("pop", StringType(), True)
    ])
    ,True)]))


final_df = d.withColumn('point', from_json('point', point_schema))

Обратите внимание, что не изменяйте тип pop на int в схеме, это приведет к null для всего выражения from_json(...), поскольку значение поля pop задано как string в строке json.

...