Spark读取ORC文件时字符串被误解析为Decimal类型如何解决
inferSchema 配置仅对CSV、JSON这类无内置schema的文本类数据源生效。ORC属于自带强schema的二进制列式存储格式,和Parquet格式逻辑一致,Spark读取这类格式时默认优先读取文件内嵌的元数据schema,不会走schema推断流程,因此配置关闭inferSchema不会改变默认读取行为。你代码中添加的option("header", "true")同样是仅面向文本类数据源的参数,对ORC格式不产生任何作用。
方案1:读取前直接传入自定义schema(性能最优,优先推荐)
不需要强制Spark跳过内置schema读取,直接在读取环节传入你定义好的业务schema,Spark会按照指定schema做字段类型适配,不会完全沿用文件内嵌的类型定义,示例代码如下:from pyspark.sql.types import StructType, StructField, IntegerType, StringType # 按业务要求定义字段类型 target_schema = StructType([ StructField("C1", IntegerType(), nullable=True), StructField("C2", StringType(), nullable=True) ]) # 读取时直接绑定自定义schema df = spark.read.schema(target_schema).orc("path to file")该方案下,原文件中被识别为decimal类型的
1954E7会直接被转换为字符串"1954E7",不会被解析为科学计数法对应的数值,完全符合业务预期。方案2:读取完成后做显式类型转换
如果不想提前定义schema,可以先按ORC文件默认schema读取数据,再单独对需要调整类型的字段做强制转换,示例代码如下:from pyspark.sql.functions import col df = spark.read.orc("path to file") # 逐字段转换为目标类型 df = df.withColumn("C1", col("C1").cast(IntegerType())) \ .withColumn("C2", col("C2").cast(StringType()))该方案存在额外性能损耗:Spark会先按文件原schema完成一次数据解析,再做二次类型转换,数据量较大时效率低于方案1。
方案3:以原始二进制方式读取(极度不推荐)
如果确实需要完全跳过ORC内置schema解析,可以将ORC文件作为普通二进制文件读取,拿到原始字节后自行实现ORC格式的页解码、字段拆分逻辑。该方案开发成本极高,无特殊定制需求不要使用。
内容的提问来源于stack exchange,提问作者sri

