【问题标题】:Update structured values of a map type column in Pyspark更新 Pyspark 中地图类型列的结构化值
【发布时间】:2021-04-10 14:11:56
【问题描述】:

我正在尝试修改 Map 类型的 Dataframe 列,其值依次为 Struct 类型:

root
 |-- name: string (nullable = true)
 |-- age: long (nullable = true)
 |-- MapName: map (nullable = true)
 |    |-- key: string
 |    |-- value: struct (valueContainsNull = true)
 |    |    |-- field1: double (nullable = true)
 |    |    |-- field2: double (nullable = true)

我以 MapName 列初始化为 None 的方式创建了 DataFrame,因为我需要在以后的阶段填写信息。我使用的代码如下:

from pyspark.sql import SparkSession, DataFrame
from pyspark.sql.functions import col, udf, lit
from pyspark.sql.types import StructType, StringType, LongType, DoubleType, MapType

spark = SparkSession.builder.appName("testMapType").getOrCreate()

data = [('Alice', 1)]
df = spark.createDataFrame(data, ['name','age'])

def value_struct():
    schema = StructType([
        StructField('field1', DoubleType(), True),
        StructField('field2', DoubleType(), True)])

    return schema

myschema = StructType([
        StructField('name', StringType(), True),
        StructField('age', LongType(), True),
        StructField('MapName', MapType(StringType(), value_struct()), True)])

df = df.withColumn('MapName',lit(None).cast(MapType(StringType(), value_struct())))
df = spark.createDataFrame(df.rdd, schema=myschema)
df.printSchema()

现在,当我尝试像这样使用 udf 更新 MapName 列时:

my_update_udf = udf(lambda x: {**x, **{'a_map_key':{'field1':3.2,'field2':2.6}}}, MapType(StringType(), value_struct()))
df2 = df.withColumn('MapName', my_update_udf(col('MapName')))
df2.collect()

我收到以下错误:

TypeError: 'NoneType' object is not a mapping

我在过去的询问中找不到任何建议,这里有什么帮助吗?

【问题讨论】:

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


    【解决方案1】:

    您不需要 UDF。您可以使用相关的 Spark SQL 函数来创建映射和结构。

    import pyspark.sql.functions as F
    
    new_map = F.create_map(
        F.lit('a_map_key'),
        F.struct(
            F.lit(3.2).alias('field1'),
            F.lit(2.6).alias('field2')
        )
    )
    
    df2 = df.withColumn(
        'MapName',
        F.when(
            F.col('MapName').isNotNull(),      # need to check null because 
            F.map_concat('MapName', new_map)   # map_concat doesn't work if map is null
        ).otherwise(new_map)
    )
    
    df2.show(truncate=False)
    +-----+---+-------------------------+
    |name |age|MapName                  |
    +-----+---+-------------------------+
    |Alice|1  |[a_map_key -> [3.2, 2.6]]|
    +-----+---+-------------------------+
    

    【讨论】:

      猜你喜欢
      • 2018-01-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-06-26
      • 1970-01-01
      • 1970-01-01
      • 2023-03-16
      • 2021-12-08
      相关资源
      最近更新 更多