【问题标题】:Explode JSON key Value to new Rows将 JSON 键值分解为新行
【发布时间】:2020-09-13 20:16:19
【问题描述】:

我正在寻找转换嵌套 JSON 并将其分解为新行。

当前数据:

+-----------+-----------+-----------------------------+
|         id|      site |                         sale|
+-----------------------------------------------------+
|        abc|          6|{"2019-05-08T00:00:00": null, "2019-05-09T00:00:00": [{"key1": 2, "key2": 0}]}         |
|        def|          5|{"2019-05-08T00:00:00": [{"key1": 22, "key2": 10}], "2019-05-09T00:00:00": null}       |
|        ghi|          4|{"2019-05-08T00:00:00": null, "2019-05-09T00:00:00": null}         |

想要的结果

+-----------+-----------+------------------------+-----------+-----------+
|         id|      site |                saledate|       key1|       key2|
+-------------------------------------------------------------------------
|        abc|          6|     2019-05-08T00:00:00|       null|       null|
|        abc|          6|     2019-05-09T00:00:00|          2|          0|
|        def|          5|     2019-05-08T00:00:00|         22|         10|
|        def|          5|     2019-05-09T00:00:00|       null|       null|
|        ghi|          4|     2019-05-08T00:00:00|       null|       null|
|        ghi|          4|     2019-05-09T00:00:00|       null|       null|

我尝试过的:

  • explode 仅适用于 Array 类型。
new_df = old_df.withColumn('saledate', explode('sale'))
  • 我可以通过执行以下操作来获取每个日期的属性。但是,我必须分别指定每个日期,这并不理想。
new_df = old_df
  .withColumn('sale_collection', explode('sale.2019-05-08T00:00:00'))
  .withColumn('key1', col('sale_collection').getItem('key1')
  .withColumn('key2', col('sale_collection').getItem('key2')

【问题讨论】:

    标签: python dataframe apache-spark pyspark apache-spark-sql


    【解决方案1】:

    您可以使用from_json将字符串转换为Map然后分解:

    from pyspark.sql.functions import from_json
    
    df.withColumn('sale', from_json('sale', 'map<string,array<struct<key1:int,key2:int>>>')) \
      .selectExpr('*', 'explode_outer(sale) as (saledate, keys)') \
      .selectExpr('id', 'site', 'saledate', 'inline_outer(keys)') \
      .show()
    +---+----+-------------------+----+----+
    | id|site|           saledate|key1|key2|
    +---+----+-------------------+----+----+
    |abc|   6|2019-05-08T00:00:00|null|null|
    |abc|   6|2019-05-09T00:00:00|   2|   0|
    |def|   5|2019-05-08T00:00:00|  22|  10|
    |def|   5|2019-05-09T00:00:00|null|null|
    |ghi|   4|2019-05-08T00:00:00|null|null|
    |ghi|   4|2019-05-09T00:00:00|null|null|
    +---+----+-------------------+----+----+
    

    注意:inline_outerinline 是 SparkSQL 内置函数,用于分解结构数组。

    【讨论】:

    • 谢谢@jxc。唯一的问题是 sale 列具有 Struct 数据类型,而不是字符串。我相信 from_json 只会使用StringType。它是 Struct 类型(而不是 String)的原因是因为数据是使用 spark.read 加载的
    • 只需:from_json(to_json('sale'), 'map&lt;string,array&lt;struct&lt;key1:int,key2:int&gt;&gt;&gt;')) 并确保导入 to_json。 @stack247
    • 做到了。只是好奇...如果我在withColumn 中使用explode_outer(或explode),你知道语法吗?
    • @stack247,您不能使用 withColumn 分解 MapType 列,因为它会产生两列。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-10-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-30
    • 1970-01-01
    相关资源
    最近更新 更多