Pyspark从行/数据与不同的列创建DataFrame

时间:2018-11-29 14:35:15

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

我有多个键/值对的数据/行,其中键的数量未知-我想从中创建一个Spark DataFrame,其中有些重叠,有些则没有。我的最终目标是从此DataFrame中写入CSV。

我对输入数据/行具有灵活性:最容易使用的是JSON字符串,但可以通过可能重叠的键进行转换:

{"color":"red", "animal":"fish"}
{"color":"green", "animal":"panda"}
{"color":"red", "animal":"panda", "fruit":"watermelon"}
{"animal":"aardvark"}
{"color":"blue", "fruit":"apple"}

理想情况下,我想根据此数据创建一个看起来像这样的DataFrame:

-----------------------------
color | animal   | fruit
-----------------------------
red   | fish     | null
green | panda    | null
red   | panda    | watermelon
null  | aardvark | null
blue  | null     | apple
-----------------------------

值得注意的是,没有特定键的数据/行是null,并且数据/行中的所有键都表示为列。

我对许多Spark基础知识感到比较满意,但是在设想一个流程以有效地将我的RDD / DataFrame与键/值对结合使用时遇到了麻烦– 但列和键的数量未知 -并使用这些键作为列创建一个DataFrame。

高效,因为如果可能的话,我想避免创建一个将所有输入行都保存在内存中的对象(例如,单个字典)。

再一次,编写CSV的最终目标是实现这一目标的合理步骤。

另一个皱纹:

某些数据将是多值的,例如:

{"color":"pink", "animal":["fish","mustang"]}
{"color":["orange","purple"], "animal":"panda"}

使用提供的定界符,例如/为避免与,冲突以分隔列,我想在列的输出中对它们进行分隔,例如:

------------------------------------
color         | animal       | fruit
------------------------------------
pink          | fish/mustang | null
orange/purple | panda        | null
------------------------------------

一旦有解决主要问题的方法,我相信我可以解决这一问题,但是无论如何都将其丢掉,因为这将成为问题的一个方面。

1 个答案:

答案 0 :(得分:2)

从文件读取

如果您的数据存储在文件中(假设它名为myfile.json),如下所示:

{"color":"red", "animal":"fish"}
{"color":"green", "animal":"panda"}
{"color":"red", "animal":"panda", "fruit":"watermelon"}
{"animal":"aardvark"}
{"color":"blue", "fruit":"apple"}
{"color":"pink", "animal":["fish","mustang"]}
{"color":["orange","purple"], "animal":"panda"}

您可以使用pyspark.sql.DataFrameReader.json以换行符分隔的JSON记录的形式读取文件。

df = spark.read.json("myfile.json")
df.show()
#+------------------+-------------------+----------+
#|            animal|              color|     fruit|
#+------------------+-------------------+----------+
#|              fish|                red|      null|
#|             panda|              green|      null|
#|             panda|                red|watermelon|
#|          aardvark|               null|      null|
#|              null|               blue|     apple|
#|["fish","mustang"]|               pink|      null|
#|             panda|["orange","purple"]|      null|
#+------------------+-------------------+----------+

df.printSchema()
#root
# |-- animal: string (nullable = true)
# |-- color: string (nullable = true)
# |-- fruit: string (nullable = true)

从RDD读取

您也可以从rdd中读取内容:

import json

rdd = sc.parallelize(
    map(
        json.dumps,
        [
            {"color":"red", "animal":"fish"},
            {"color":"green", "animal":"panda"},
            {"color":"red", "animal":"panda", "fruit":"watermelon"},
            {"animal":"aardvark"},
            {"color":"blue", "fruit":"apple"},
            {"color":"pink", "animal":["fish","mustang"]},
            {"color":["orange","purple"], "animal":"panda"}
        ]
    )
)

df = spark.read.json(rdd)

第二部分,您可以根据需要使用pyspark.sql.functions.regexp_replace格式化多值记录。

from pyspark.sql.functions import regexp_replace

def format_column(column):
    return regexp_replace(regexp_replace(column, '(^\[)|(\]$)|(")', ''), ",", "/") 

df.select(*[format_column(c).alias(c) for c in df.columns]).show()

#+------------+-------------+----------+
#|      animal|        color|     fruit|
#+------------+-------------+----------+
#|        fish|          red|      null|
#|       panda|        green|      null|
#|       panda|          red|watermelon|
#|    aardvark|         null|      null|
#|        null|         blue|     apple|
#|fish/mustang|         pink|      null|
#|       panda|orange/purple|      null|
#+------------+-------------+----------+