如何在 PySpark 中将字符串转换为字典 (JSON) 的 ArrayType

mal*_*har 4 python pyspark pyspark-sql

尝试将 StringType 转换为 JSON 的 ArrayType 以获取从 CSV 格式生成的数据帧。

使用pyspark上Spark2

我正在处理的 CSV 文件;如下——

date,attribute2,count,attribute3
2017-09-03,'attribute1_value1',2,'[{"key":"value","key2":2},{"key":"value","key2":2},{"key":"value","key2":2}]'
2017-09-04,'attribute1_value2',2,'[{"key":"value","key2":20},{"key":"value","key2":25},{"key":"value","key2":27}]'
Run Code Online (Sandbox Code Playgroud)

如上所示,它"attribute3"在文字字符串中包含一个属性,从技术上讲,它是一个精确长度为 2 的字典(JSON)列表。(这是功能 distinct 的输出)

摘录自 printSchema()

attribute3: string (nullable = true)
Run Code Online (Sandbox Code Playgroud)

我试图施放"attribute3"到ArrayType如下

temp = dataframe.withColumn(
    "attribute3_modified",
    dataframe["attribute3"].cast(ArrayType())
)
Run Code Online (Sandbox Code Playgroud)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __init__() takes at least 2 arguments (1 given)
Run Code Online (Sandbox Code Playgroud)

实际上,ArrayType期望数据类型作为参数。我尝试过"json",但没有奏效。

所需的输出 - 最后,我需要转换attribute3为ArrayType()简单的 Python 列表。(我试图避免使用eval)

如何将其转换为ArrayType,以便我可以将其视为 JSON 列表?

我在这里错过了什么吗?

(文档,没有以直接的方式解决这个问题)

Psi*_*dom 8

使用from_json与attribute3列中的实际数据匹配的模式将 json 转换为 ArrayType:

原始数据框:

df.printSchema()
#root
# |-- date: string (nullable = true)
# |-- attribute2: string (nullable = true)
# |-- count: long (nullable = true)
# |-- attribute3: string (nullable = true)

from pyspark.sql.functions import from_json
from pyspark.sql.types import *
Run Code Online (Sandbox Code Playgroud)

创建架构:

schema = ArrayType(
    StructType([StructField("key", StringType()), 
                StructField("key2", IntegerType())]))
Run Code Online (Sandbox Code Playgroud)

使用from_json:

df = df.withColumn("attribute3", from_json(df.attribute3, schema))

df.printSchema()
#root
# |-- date: string (nullable = true)
# |-- attribute2: string (nullable = true)
# |-- count: long (nullable = true)
# |-- attribute3: array (nullable = true)
# |    |-- element: struct (containsNull = true)
# |    |    |-- key: string (nullable = true)
# |    |    |-- key2: integer (nullable = true)

df.show(1, False)
#+----------+----------+-----+------------------------------------+
#|date      |attribute2|count|attribute3                          |
#+----------+----------+-----+------------------------------------+
#|2017-09-03|attribute1|2    |[[value, 2], [value, 2], [value, 2]]|
#+----------+----------+-----+------------------------------------+
Run Code Online (Sandbox Code Playgroud)


pau*_*ult 7

@Psidom 的答案对我不起作用,因为我使用的是 Spark 2.1 。

就我而言,我必须稍微修改您的attribute3字符串以将其包装在字典中:

import pyspark.sql.functions as f
df2 = df.withColumn("attribute3", f.concat(f.lit('{"data": '), "attribute3", f.lit("}")))
df2.select("attribute3").show(truncate=False)
#+--------------------------------------------------------------------------------------+
#|attribute3                                                                            |
#+--------------------------------------------------------------------------------------+
#|{"data": [{"key":"value","key2":2},{"key":"value","key2":2},{"key":"value","key2":2}]}|
#+--------------------------------------------------------------------------------------+
Run Code Online (Sandbox Code Playgroud)

现在我可以定义架构如下:

schema = StructType(
    [
        StructField(
            "data",
            ArrayType(
                StructType(
                    [
                        StructField("key", StringType()),
                        StructField("key2", IntegerType())
                    ]
                )
            )
        )
    ]
)
Run Code Online (Sandbox Code Playgroud)

现在使用from_json后跟getItem():

df3 = df2.withColumn("attribute3", f.from_json("attribute3", schema).getItem("data"))
df3.show(truncate=False)
#+----------+----------+-----+---------------------------------+
#|date      |attribute2|count|attribute3                       |
#+----------+----------+-----+---------------------------------+
#|2017-09-03|attribute1|2    |[[value,2], [value,2], [value,2]]|
#+----------+----------+-----+---------------------------------+
Run Code Online (Sandbox Code Playgroud)

和架构:

df3.printSchema()
# root
# |-- attribute3: array (nullable = true)
# |    |-- element: struct (containsNull = true)
# |    |    |-- key: string (nullable = true)
# |    |    |-- key2: integer (nullable = true)
Run Code Online (Sandbox Code Playgroud)

  • 这对我来说非常有效。巧妙地使用包装技巧使其发挥作用。我在2.1上也遇到了同样的问题。只是为了补充您的答案,我能够使用 `schema = Spark.read.json(df2.rdd.map(lambda row: row.attribute3)).schema` 动态地让 Spark 确定架构 (4认同)