将数组形式(作为字符串)转换为Pyspark中的列

时间:2018-07-30 15:50:19

标签: arrays pyspark pivot

我有以下格式的df:

+---------------------------------------+
|ID|ESTRUC_COMP                         |
+---------------------------------------+
|4A|{'AP': '201', 'BQ': '2'}            |
|8B| {'AP': '501', 'BQ': '1', 'IN': '5'}|
+---------------------------------------+

我需要这样的东西:

+------------------------------------------------+
|ID|ESTRUC_COMP                        |AP |BQ|IN|
+------------------------------------------------+
|4A|{'AP': '201', 'BQ': '2'}           |201|2 |  |
|8B|{'AP': '501', 'BQ': '1', 'IN': '5'}|501|1 |5 |
+------------------------------------------------+

但是,ESTRUC_COMP是一个字符串。

root
 |-- ID: string (nullable = true)
 |-- ESTRUC_COMP: string (nullable = true)

如何执行此转换?预先谢谢你。

鲍里斯

1 个答案:

答案 0 :(得分:1)

由于您使用的是Spark 1.6,因此无法使用pyspark.sql.functions.from_json()-您将不得不使用@OneToMany(cascade = CascadeType.ALL) @JoinColumn(name = "invoiceNumber") private List<InvoiceLineItems> invoiceLineItems;

这个问题与PySpark “explode” dict in column非常相似,但是出于两个原因,我承认这不是一个骗子:

  1. 您的字符串列不是有效的JSON(由于单引号)

  2. 您希望键成为列

不过,第一步是对链接帖子中的相同步骤进行基本调整,并对udf函数进行较小的调整,该函数将单引号替换为双引号:

parse()

现在您可以解析字符串并调用pyspark.sql.functions.explode()

from pyspark.sql.functions import udf, explode, first
from pyspark.sql.types import *
import json

def parse(s):
    try:
        return json.loads(s.replace("'", '"'))
    except json.JSONDecodeError:
        pass

parse_udf = udf(parse, MapType(StringType(), StringType()))

最后,pivot()将键作为列。您可以将df.select("ID", explode(parse_udf("ESTRUC_COMP"))).show() #+---+---+-----+ #| ID|key|value| #+---+---+-----+ #| 4A| BQ| 2| #| 4A| AP| 201| #| 8B| IN| 5| #| 8B| BQ| 1| #| 8B| AP| 501| #+---+---+-----+ 用作聚合函数,因为我们知道每个first()的键值关系都是一对一的。

ID

当然,由于我定义了df.select("*", explode(parse_udf("ESTRUC_COMP")))\ .groupBy("ID","ESTRUC_COMP").pivot("key").agg(first("value")).show(truncate=False) #+---+-----------------------------------+---+---+----+ #|ID |ESTRUC_COMP |AP |BQ |IN | #+---+-----------------------------------+---+---+----+ #|4A |{'AP': '201', 'BQ': '2'} |201|2 |null| #|8B |{'AP': '501', 'BQ': '1', 'IN': '5'}|501|1 |5 | #+---+-----------------------------------+---+---+----+ 以返回udf,因此所有结果列都将是字符串。您可以cast them或相应地修改MapType(StringType(), StringType())