问询SPARK-25177关联修复PR是否已纳入Spark正式版本
问题说明
使用基于Spark 3.3.0的AWS Glue 4时,遭遇SPARK-25177问题:当decimal类型的scale>6时,0值会以科学计数法输出,导致DataFrame写入外部数据库失败。已在AWS Glue 4中验证该问题未修复,关联修复PR#22171已合并至Spark master分支,需确认该修复是否已进入Spark正式发布版本。
重现代码
spark.sql("create table test (a decimal(10,7), b decimal(10,6), c decimal(10,8))") spark.sql("insert into test values(0, 0,0)") spark.sql("insert into test values(1, 1, 1)") spark.table("test").show()
执行结果:
+---------+--------+----------+
| a| b| c|
+---------+--------+----------+
| 0E-7|0.000000| 0E-8| // scale>6时,0值以科学计数法显示
|1.0000000|1.000000|1.00000000|
+---------+--------+----------+
修复版本确认
PR#22171的修复逻辑已合并至Spark master分支,该修复首次正式发布在Spark 2.4.3版本中。但部分定制化Spark发行版(如AWS Glue 4基于的Spark 3.3.0)可能未包含该修复,或存在回归情况。
若需确认特定Spark版本是否包含该修复,可通过两种方式:
- 查看对应版本的Release Notes,搜索SPARK-25177关键词;
- 检查该版本源码中
Decimal.toString()方法的实现,确认是否针对scale>6的0值做了非科学计数法的处理。
临时解决方案
自定义UDF处理0值格式
创建自定义UDF,判断decimal值是否为0,若是则输出对应scale的固定格式字符串,否则保留原格式:
import org.apache.spark.sql.functions._ import org.apache.spark.sql.types.DecimalType val formatDecimalZero = udf((value: java.math.BigDecimal, scale: Int) => { if (value.compareTo(java.math.BigDecimal.ZERO) == 0) { s"0.${"0" * scale}" } else { value.toPlainString } }) // 示例:处理test表中scale=7的a列、scale=8的c列 val processedDF = spark.table("test") .withColumn("a", formatDecimalZero(col("a"), lit(7))) .withColumn("c", formatDecimalZero(col("c"), lit(8))) processedDF.show()
执行后0值将以非科学计数法显示,可正常写入外部数据库。
转换为字符串时使用toPlainString
在将decimal列转换为字符串时,调用BigDecimal的toPlainString方法,避免科学计数法输出。该方法会返回不带指数的字符串表示,适用于所有decimal值的格式统一处理。
内容的提问来源于stack exchange,提问作者biertje72

