You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

Spark 3.3.1写入decimal(38,10)零值至Hive表变为NULL问题

问题:Spark写入Hive Parquet表时Decimal类型零值变为NULL

环境

  • Apache Spark: 3.3.1
  • Hive: 3.1.3(元数据存储+Hive服务)
  • 表存储格式: PARQUET
  • 插入方式: dataframe.format("hive").insertInto("db.table")
  • 问题字段: 类型为decimal(38,10)col_REG

问题现象

在Spark中计算得到的decimal类型零值(DataFrame.show()显示为0E-10),通过insertInto写入Parquet格式的Hive表后,对应字段值变为NULL,无任何异常抛出。

预期结果

Spark DataFrame显示为0E-10,写入Hive表后应存储为0.0000000000decimal(38,10)类型)而非NULL。

实际结果

  • Spark DataFrame:字段值显示为0E-10
  • Hive表:对应行的该字段存储为NULL

代码示例

val res = df.withColumn("col_REG",when(col("col1_REG") === "C",   col("col2").cast("decimal(38,10)"))
.when(col("col3") === "D",col("col4").cast("decimal(38,10)"))
.otherwise(lit("0.0000000000").cast("decimal(38,10)"))
)

解决方案

1. 直接构造Decimal类型零值

避免通过字符串转换生成零值,直接创建符合精度要求的Decimal字面量,消除精度偏差问题:

import org.apache.spark.sql.types.Decimal

val res = df.withColumn("col_REG", 
  when(col("col1_REG") === "C", col("col2").cast("decimal(38,10)"))
  .when(col("col3") === "D", col("col4").cast("decimal(38,10)"))
  .otherwise(lit(Decimal(0, 38, 10)))
)

2. 配置Spark与Hive兼容的序列化规则

添加以下配置,强制Spark采用与Hive兼容的Parquet序列化逻辑,保留Decimal零值的精度信息:

spark.conf.set("spark.sql.parquet.writeLegacyFormat", "true")
spark.conf.set("spark.sql.decimalOperations.allowPrecisionLoss", "false")

3. 校验Hive表字段定义

确保Hive表中col_REG字段的类型严格定义为decimal(38,10),避免元数据不一致导致的解析错误:

ALTER TABLE db.table CHANGE COLUMN col_REG col_REG DECIMAL(38,10);

原因分析

Spark通过字符串转换生成的零值可能因精度处理逻辑被识别为极小值,在Parquet序列化时被标记为无效数据;Hive读取Parquet文件时,会将这类无效的Decimal值解析为NULL。直接构造Decimal类型零值可避免转换偏差,配置项则确保Spark与Hive的类型处理逻辑一致。

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

火山引擎 最新活动