Databricks用PySpark解析Stack Exchange PostHistory.xml为DataFrame遇空表
问题原因及解决办法
一、Databricks使用spark-xml读取全为null的问题
错误核心原因
- 多数版本的
spark-xml库默认会给XML节点的属性添加_前缀作为解析后的字段名,你自定义Schema里的字段名是ContentLicense,但实际解析出来的字段是_ContentLicense,字段名完全不匹配导致所有值被识别为null。 - 可选次要原因:你配置的字符集参数
UTF8书写不规范,应该为UTF-8;部分属性前后的空格未被自动忽略也可能导致解析异常。
解决步骤
- 先执行无Schema的推断读取,确认实际解析的字段名:
test_df = spark.read.format("com.databricks.spark.xml") \ .option("rowTag", "row") \ .option("charset", "UTF-8") \ .load("/FileStore/tables/PostHistory.xml") test_df.printSchema()
- 如果输出字段名带
_前缀,两种方案二选一即可:- 方案一:添加配置关闭属性前缀,匹配你现有Schema
PostHistoryDF = spark.read.format("com.databricks.spark.xml") \ .option("rowTag", "row") \ .option("charset", "UTF-8") \ .option("attributePrefix", "") \ # 关闭属性前缀 .option("ignoreLeadingWhitespace", True) \ .option("ignoreTrailingWhitespace", True) \ .schema(schema_posthistory) \ .option("treatEmptyValuesAsNulls", "true") \ .load("/FileStore/tables/PostHistory.xml")- 方案二:修改Schema字段名,添加对应
_前缀即可
- 额外检查:如果原始XML文件属性值存在未转义的双引号、尖括号,需要先预处理转义为XML标准转义字符(双引号转
",<转<,>转>),否则也会导致解析失败。
- 注:你Schema里的
UserDisplayName、Comment属于可选字段,样例数据中不存在,解析后为null属于正常情况。
二、Jupyter自定义解析逻辑报错、列数不足的问题
错误核心原因
DataFrame.replace()方法不支持正则表达式,你写的df.replace("[^a-zA-Z0-9]", " ")完全无效,Text字段内的特殊字符、分隔符|未被处理,写入CSV时会把单个字段拆分为多列,导致列偏移。- 写入CSV时未设置引号、转义配置,
Text字段内的空格、特殊符号会触发CSV自动拆列,最终读取时只有7列。 spark.createDataFrame从字典生成DataFrame时,列顺序不固定,你手动按固定顺序指定Schema读取会出现列错位。
解决步骤
- 用
regexp_replace处理特殊字符,避免列拆分:
from pyspark.sql.functions import regexp_replace, col # 仅替换会影响CSV解析的换行、分隔符即可,不需要清洗所有非字母数字字符,避免丢失数据 df = df.withColumn("Text", regexp_replace(col("Text"), "[\\n\\r|]", " "))
- 写入CSV时添加引号、转义、表头配置:
df.write.csv( linkcsv + ".csv", sep="|", quote='"', escape='"', header=True, mode="overwrite" )
- 读取CSV时开启表头自动识别,不需要手动固定顺序写Schema:
PostHistory_df = spark.read.format("csv") \ .option("header", "true") \ .option("sep", "|") \ .option("quote", '"') \ .load("LiteratureCSV/PostHistory.csv") # 读取完成后再手动转换对应字段的类型即可
内容的提问来源于stack exchange,提问作者MoOn
相关产品推荐
相关产品推荐

