基于GPT代码提示,辅助实现datax hdfswriter 支持decimal类型,并且支持定义precision, scale

在参考相关博客,完成datax hdfswriter支持decimal类型需求后,在数据使用时发现了新的问题:

写出的orc文件中,decimal类型字段序列化时使用的是默认精度:decimal(38,18)。在某些情况下,会触发精度转换异常的报错,导致计算任务失败。

java 复制代码
public class HiveDecimal implements Comparable<HiveDecimal> {
  public static final int SYSTEM_DEFAULT_PRECISION = 38;
  public static final int SYSTEM_DEFAULT_SCALE = 18;
}
markdown 复制代码
df.printSchema()
root
 |-- xxxx_rate: decimal(38,18) (nullable = true)

因此需要在hdfswriter写出orc文件时,为decimal字段指定需要的precision和scale

查看了decimal默认的objectInspector的实例化逻辑,并没有传入decimal字段的precision和scale的参数位置。

java 复制代码
import org.apache.hadoop.hive.common.type.HiveDecimal;
...

public List<ObjectInspector>  getColumnTypeInspectors(List<Configuration> columns){
    ...
    
    case DECIMAL:
        // 创建DECIMAL的objectInspector
        objectInspector = ObjectInspectorFactory.getReflectionObjectInspector(HiveDecimal.class, ObjectInspectorFactory.ObjectInspectorOptions.JAVA);
        break;
}

深入ObjectInspectorFactory.getReflectionObjectInspector中,查看Inspector的实例化逻辑

java 复制代码
public static ObjectInspector getReflectionObjectInspector(Type t, ObjectInspectorOptions options) {
  ObjectInspector oi = (ObjectInspector)objectInspectorCache.get(t);
  if (oi == null) {
    // 没有缓存,进行第一次实例化
    oi = getReflectionObjectInspectorNoCache(t, options);
    objectInspectorCache.put(t, oi);
  }

  ...
  return oi;
}

第一次实例化,根据指定数据的class类型,实例化对应的objectInspector

java 复制代码
private static ObjectInspector getReflectionObjectInspectorNoCache(Type t, ObjectInspectorOptions options) {
    ...
    
    if (!(t instanceof Class)) {
    throw new RuntimeException(ObjectInspectorFactory.class.getName() + " internal error:" + t);
    } else {
    Class<?> c = (Class)t;
    if (PrimitiveObjectInspectorUtils.isPrimitiveJavaType(c)) {
      return PrimitiveObjectInspectorFactory.getPrimitiveJavaObjectInspector(PrimitiveObjectInspectorUtils.getTypeEntryFromPrimitiveJavaType(c).primitiveCategory);
    } else if (PrimitiveObjectInspectorUtils.isPrimitiveJavaClass(c)) {
      // org.apache.hadoop.hive.common.type.HiveDecimal 
      // 不属于基本数据类型或对应的装箱类型,只是原始Java类
      // 并且没有支持自定义精度传参的迹象,需要另寻他法。
      return PrimitiveObjectInspectorFactory.getPrimitiveJavaObjectInspector(PrimitiveObjectInspectorUtils.getTypeEntryFromPrimitiveJavaClass(c).primitiveCategory);
    } else if (PrimitiveObjectInspectorUtils.isPrimitiveWritableClass(c)) {
      return PrimitiveObjectInspectorFactory.getPrimitiveWritableObjectInspector(PrimitiveObjectInspectorUtils.getTypeEntryFromPrimitiveWritableClass(c).primitiveCategory);
    } else if (Enum.class.isAssignableFrom(c)) {
      return PrimitiveObjectInspectorFactory.getPrimitiveJavaObjectInspector(PrimitiveCategory.STRING);
    } else {
        ...
    }

}

在查询gpt后,得到了潜在的实现逻辑,根据这个实现建议,测试一下下:

java 复制代码
import org.apache.hadoop.hive.common.type.HiveDecimal;
...

public List<ObjectInspector>  getColumnTypeInspectors(List<Configuration> columns){
    ...
    
    case DECIMAL:
        // 创建支持自定义精度的DECIMAL的objectInspector
        Integer precision = eachColumnConf.getInt(Key.PRECISION);
        Integer scale = eachColumnConf.getInt(Key.SCALE);
        DecimalTypeInfo typeInfo = TypeInfoFactory.getDecimalTypeInfo(precision, scale);
        objectInspector = PrimitiveObjectInspectorFactory.getPrimitiveJavaObjectInspector(typeInfo);
        break;
}

重新编译打包后,测试指定decimal的precision和scale的job.json。

json 复制代码
{
    ...
    "writeMode": "append",
    "column": [
        {
            "type": "decimal",
            "name": "xxxx_rate",
            "precision": 38,
            "scale": 0
        },
        ...
    ]
}

测试spark读取写出的orc文件,查看对应字段的schema信息,读取到了正确的精度信息,问题解决:

markdown 复制代码
df = spark.read.orc("/user/hive/warehouse/xxxx/xxxxx")

df.printSchema()
root
 |-- xxxx_rate: decimal(38,0) (nullable = true)

参考文章:

1、blog.csdn.net/Shadow_Ligh...

2、github.com/alibaba/Dat...

3、github.com/alibaba/Dat...

相关推荐
Zane19941 分钟前
遍历时删元素为什么报错:modCount 这个"计数器"在背后盯着你
java·后端
TDengine (老段)6 分钟前
TDengine 应用案例 — 工业大数据与智能制造
大数据·数据库·制造·时序数据库·tdengine·涛思数据
SXkehuirongsheng23 分钟前
定制软件开发哪家的售后响应速度更快?
大数据
2601_9578793324 分钟前
Seedance排队太久怎么办?2026免排队AI视频工具与替代方案怎么选
大数据·人工智能·深度学习
智码看视界30 分钟前
Spark 3.5 AQE 调优:10 个生产环境案例让作业提速 3-10 倍
大数据·spark·性能调优·aqe·sparksql·数据倾斜·etl优化
电商API_1800790524744 分钟前
速卖通商品采集API技术文章
java·开发语言·c++·api·跨境电商·商品详情
郑州光合科技余经理1 小时前
海外版外卖系统架构:订单怎么流转、权限怎么分
java·开发语言·前端·系统架构·uni-app·php·ai编程
starzy19901 小时前
SparkStreaming 之容错机制深度剖析
大数据·spark
记忆张量MemTensor1 小时前
MemOS Skill 上线|一句话即可接入 MemOS Cloud
大数据·数据库·人工智能·typescript·开源
一木 之林1 小时前
五、C++新特性、关键字与编译原理
java·jvm·算法