如何在PySpark中创建map<string,string>类型的非派生新列
你原有代码无法生效的核心原因:lit(None)生成的是NullType类型的字面量列,直接向MapType(StringType(),StringType())强转时,在多数Spark版本(尤其是2.4.x及更早版本)会触发类型匹配异常,即便转换成功,后续操作该列时也容易出现空指针、类型校验不通过的问题。
以下方法均可以直接生成非派生自现有列、类型为MapType(StringType(),StringType())的新列,按简洁度排序:
方法1:使用
typedLit直接传入空字典(Spark 2.3+支持,最简洁)typedLit可以直接识别Python原生集合类型,自动映射为Spark对应复杂数据类型,不需要额外强转:from pyspark.sql.functions import typedLit df = df.withColumn("normalizedvariation", typedLit({}))执行后用
df.printSchema()可验证列类型为map<string,string>,如果需要严格固定类型,也可以追加.cast(MapType(StringType(), StringType()))做显式声明。方法2:使用SQL表达式
map()(全版本兼容,稳定性最高)
直接调用Spark SQL内置的无参map()函数,原生返回空的map<string,string>类型列,不存在版本兼容问题:from pyspark.sql.functions import expr df = df.withColumn("normalizedvariation", expr("map()"))方法3:修正原有
lit强转逻辑
不直接传None做字面量,而是先生成带类型声明的空值键值对map,再强转为目标类型,兼容所有Spark版本:from pyspark.sql.functions import create_map, lit from pyspark.sql.types import MapType, StringType df = df.withColumn( "normalizedvariation", create_map(lit(None).cast(StringType()), lit(None).cast(StringType())).cast(MapType(StringType(), StringType())) )这个方案生成的列初始包含
null -> null的键值对,适合后续会直接覆写该列值的场景,如果需要初始就是完全空的Map,优先使用前两种方法。
补充:如果使用Scala API实现,除了上述
expr、typedLit方案外,还可以直接用lit(Map.empty[String,String])直接生成目标列,Scala端的lit支持直接传入空Map做类型推断,不会出现PySpark中传None的类型问题。
内容的提问来源于stack exchange,提问作者Rahul Diggi

