Pyspark DataFrame解析含None值的JSON数组列异常怎么解决?
问题根因
你遇到的解析失败并非schema定义错误,核心有两个原因:
- 你存储的cast列JSON为Python风格格式:使用单引号包裹键值、空值用
None表示,不符合标准JSON要求(标准JSON用双引号、空值为null),PySpark默认按标准JSON规则解析会报错 from_json解析后返回的是ArrayType(StructType)结构,直接调用getField("name")无法正确提取数组内每个struct的name字段
可行解决方案
有两种可直接落地的处理方式,均兼容全量4.5万条数据的批量处理:
方案1:预处理JSON格式后解析(兼容性最优,推荐)
先将cast列的非标准JSON转为标准格式,再执行解析,代码如下:
from pyspark.sql.functions import regexp_replace, from_json, col, transform, concat_ws # 1. 转换为标准JSON格式:替换单引号为双引号,替换None为null credits_upd = credits_upd.withColumn( "cast_std", regexp_replace(regexp_replace(col("cast"), "'", '"'), "None", "null") ) # 原schema定义无需修改,已设置nullable=True支持空值 cast_schema=ArrayType(StructType([ StructField('cast_id',IntegerType(),nullable=True), StructField('character',StringType(),nullable=True), StructField('credit_id',StringType(),nullable=True), StructField('gender',IntegerType(),nullable=True), StructField('id',IntegerType(),nullable=True), StructField('name',StringType(),nullable=True), StructField('order',IntegerType(),nullable=True), StructField('profile_path',StringType(),nullable=True) ])) # 2. 解析JSON并提取演员名,按需选择返回格式 # 格式1:保留数组格式的演员名列表 credits_upd = credits_upd.withColumn( "movies_cast", transform(from_json(col("cast_std"), cast_schema), lambda item: item.name) ) # 格式2:转为逗号分隔的字符串 # credits_upd = credits_upd.withColumn( # "movies_cast", # concat_ws(",", transform(from_json(col("cast_std"), cast_schema), lambda item: item.name)) # ) # 验证结果 credits_upd.select("id", "movies_cast").show(truncate=False)
方案2:配置from_json参数适配非标准JSON
无需预处理列,直接通过解析参数适配非标准格式,代码如下:
from pyspark.sql.functions import from_json, col, transform cast_schema=ArrayType(StructType([ StructField('cast_id',IntegerType(),nullable=True), StructField('character',StringType(),nullable=True), StructField('credit_id',StringType(),nullable=True), StructField('gender',IntegerType(),nullable=True), StructField('id',IntegerType(),nullable=True), StructField('name',StringType(),nullable=True), StructField('order',IntegerType(),nullable=True), StructField('profile_path',StringType(),nullable=True) ])) credits_upd = credits_upd.withColumn( "movies_cast", transform( # 配置允许单引号、非标准空值的解析参数 from_json(col("cast"), cast_schema, options={"allowSingleQuotes": "true", "allowNonNumericNumbers": "true"}), lambda item: item.name ) ) credits_upd.select("id", "movies_cast").show(truncate=False)
两种方案都可以正确解析id=8844的记录,提取到Robin Williams的名字。
内容的提问来源于stack exchange,提问作者user15345826
相关产品推荐
相关产品推荐

