【问题标题】:Combine columns into list of key, value pairs (no UDF)将列组合成键、值对列表(无 UDF)
【发布时间】:2021-02-12 15:51:15
【问题描述】:

我想创建一个新列,它是其他一些列的 JSON 表示。列表中的键、值对。

来源:

origin destination count
toronto ottawa 5
montreal vancouver 10

我想要什么:

origin destination count json
toronto ottawa 5 [{"origin":"toronto"},{"destination","ottawa"}, {"count": "5"}]
montreal vancouver 10 [{"origin":"montreal"},{"destination","vancouver"}, {"count": "10"}]

(一切都可以是字符串,没关系)。

我尝试过类似的方法:

df.withColumn('json', to_json(struct(col('origin'), col('destination'), col('count'))))

但它会在一个对象中创建包含所有 key:value 对的列:

{"origin":"United States","destination":"Romania"}

如果没有 UDF,这可能吗?

【问题讨论】:

    标签: apache-spark pyspark apache-spark-sql key-value


    【解决方案1】:

    解决这个问题的方法:

    import pyspark.sql.functions as F
    
    df2 = df.withColumn(
        'json', 
        F.array(
            F.to_json(F.struct('origin')),
            F.to_json(F.struct('destination')),
            F.to_json(F.struct('count'))
        ).cast('string')
    )
    
    df2.show(truncate=False)
    +--------+-----------+-----+--------------------------------------------------------------------+
    |origin  |destination|count|json                                                                |
    +--------+-----------+-----+--------------------------------------------------------------------+
    |toronto |ottawa     |5    |[{"origin":"toronto"}, {"destination":"ottawa"}, {"count":"5"}]     |
    |montreal|vancouver  |10   |[{"origin":"montreal"}, {"destination":"vancouver"}, {"count":"10"}]|
    +--------+-----------+-----+--------------------------------------------------------------------+
    

    【讨论】:

    • 嗨,谢谢!我想避免使用 udf 的一个原因是我一直在阅读的性能问题(我还没有尝试 pyarrow ...)。如果我在大数据帧上运行此方法(即多次调用 to_json),您是否预见到这种方法会产生大量计算开销?
    • @AlexanderWitte 我不认为它会很贵。 to_json 对我来说似乎是一个微不足道的操作。
    • @AlexanderWitte 根据经验,Spark SQL 函数将比 UDF 更好(即使使用 pyarrow)
    【解决方案2】:

    另一种方法是在调用to_json之前创建地图列数组:

    from pyspark.sql import functions as F
    
    df1 = df.withColumn(
        'json',
        F.to_json(F.array(*[F.create_map(F.lit(c), F.col(c)) for c in df.columns]))
    )
    
    df1.show(truncate=False)
    
    #+--------+-----------+-----+------------------------------------------------------------------+
    #|origin  |destination|count|json                                                              |
    #+--------+-----------+-----+------------------------------------------------------------------+
    #|toronto |ottawa     |5    |[{"origin":"toronto"},{"destination":"ottawa"},{"count":"5"}]     |
    #|montreal|vancouver  |10   |[{"origin":"montreal"},{"destination":"vancouver"},{"count":"10"}]|
    #+--------+-----------+-----+------------------------------------------------------------------+
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-06-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多