You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spark中DecimalType数值合规却报精度超出最大值问题排查

Spark DecimalType 转换报错:精度超过最大值38

我编写了如下代码:

spark = (
    SparkSession.builder
    .appName("pyspark-sandbox")
    .getOrCreate()
)
spark.conf.set("spark.sql.parquet.outputTimestampType", "TIMESTAMP_MICROS")  # type: ignore

faker = Faker()
value = faker.pydecimal(left_digits=28, right_digits=10)
print(value) # 8824750032877062776842530687.8719544506

df = spark.createDataFrame([[value]], schema=['DecimalItem'])
df = df.withColumn('DecimalItem', col('DecimalItem').cast(DecimalType(38, 10)))
df.show()

执行df.show()时抛出错误:

org.apache.spark.SparkArithmeticException: [DECIMAL_PRECISION_EXCEEDS_MAX_PRECISION] Decimal precision 46 exceeds max precision 38.

数值8824750032877062776842530687.8719544506看起来符合DecimalType(38, 10)的规格,却执行失败,请问问题出在哪里?


问题原因

  • 调用spark.createDataFrame([[value]], schema=['DecimalItem'])时,仅指定列名未明确数据类型,Spark会自动解析Python Decimal对象的内部精度。
  • Faker生成的该Decimal对象的内部精度被Spark推断为46(超出Spark DecimalType的最大精度38),后续执行cast(DecimalType(38,10))时,无法将高精度Decimal直接向下转换,触发精度超限错误。

解决方案

方案1:创建DataFrame时直接指定schema(推荐)

在创建DataFrame阶段就明确指定DecimalType(38,10),跳过自动推断步骤:

from pyspark.sql.types import StructType, StructField, DecimalType

spark = (
    SparkSession.builder
    .appName("pyspark-sandbox")
    .getOrCreate()
)
spark.conf.set("spark.sql.parquet.outputTimestampType", "TIMESTAMP_MICROS")  # type: ignore

faker = Faker()
value = faker.pydecimal(left_digits=28, right_digits=10)
print(value)

# 直接指定schema
df = spark.createDataFrame(
    [[value]], 
    schema=StructType([StructField('DecimalItem', DecimalType(38, 10))])
)
df.show()

方案2:先转字符串再转换类型

如果无法提前指定schema,可以先将Decimal转为字符串,再cast为目标类型:

df = spark.createDataFrame([[str(value)]], schema=['DecimalItem'])
df = df.withColumn('DecimalItem', col('DecimalItem').cast(DecimalType(38, 10)))
df.show()

内容的提问来源于stack exchange,提问作者lapots

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 14:05:40