Spark读取多CSV文件时inferSchema=True的异常行为问询
首先,你的问题核心在于多个CSV文件的格式不一致——2个文件用双引号包裹字段,1个没有,这直接干扰了Spark批量读取时的Schema推断逻辑。
为什么会出现这种异常?
当你用spark.read.csv('/dir/*.csv')批量读取文件时,Spark的inferSchema机制默认会抽样部分文件(或文件中的部分行)来推断字段类型。如果抽样到那个不带引号的文件,Spark解析时会把数值字段误判为String类型——因为没有引号的情况下,解析逻辑对字段的识别规则和带引号的文件不一致,最终导致统一推断出的Schema把所有数值列都设为String。
而单独读取单个文件时,Spark会针对该文件的格式单独解析,所以能正确识别Double/整数类型;用union合并时,每个DataFrame已经有了正确的Schema,Spark会自动兼容类型(只要字段匹配),所以结果符合预期。
解决办法
这里给你几个可行的方案,按推荐优先级排序:
统一所有CSV文件的格式
这是最根本的解决办法。把那个不带引号的文件改成和其他文件一致的格式(用双引号包裹字段),之后再用inferSchema=True批量读取,就能正确识别数值类型了。毕竟Spark的CSV读取器对同目录下的文件格式一致性要求很高,统一格式能避免后续各种解析异常。手动指定Schema,绕过自动推断
如果你没法修改文件格式,可以直接定义好目标Schema,强制Spark按照这个Schema解析所有文件,完全避免自动推断的问题。示例代码如下:from pyspark.sql.types import StructType, StructField, StringType, DoubleType # 按照你的实际字段定义Schema custom_schema = StructType([ StructField("Name", StringType(), nullable=True), StructField("Sale_Value", DoubleType(), nullable=True), # 添加上其他字段的定义 ]) # 读取时指定schema,同时明确quote参数确保解析正确 df = spark.read.csv( '/dir/*.csv', header=True, schema=custom_schema, quote='"' )调整抽样比例(不推荐,仅临时应急)
你可以设置samplingRatio=1.0让Spark扫描所有文件的所有行来推断Schema,但这个方法在文件量大的时候会严重影响性能,而且如果格式不一致的问题没解决,仍然可能出现推断错误,所以只适合小数据集临时用:df = spark.read.csv( '/dir/*.csv', header=True, inferSchema=True, samplingRatio=1.0, quote='"' )
小提示
Spark的CSV读取器对格式细节非常敏感,除了引号,分隔符、换行符、空值表示方式等不一致,都可能导致解析问题。所以日常处理时,尽量保证同批次读取的CSV文件格式完全统一,能省掉很多麻烦。
内容的提问来源于stack exchange,提问作者Satya

