基于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...

相关推荐
A hao7 小时前
高对比度在XR虚拟背景中的作用
大数据·图像处理·人工智能·xr·广告
Java搬码工8 小时前
CompletableFuture 完整详解 + 全场景使用案例
java
许心月8 小时前
Java学习资料网站汇总
java
Haoxuekeji8 小时前
山东 AI 智能批改校园电子阅卷企业
大数据·人工智能·深度学习·安全·ai
c238568 小时前
第二篇:《测试指挥官:可视化单题自测框架(含 assert 实操)》
java·数据库·c++·算法·安全性测试
帅次9 小时前
Kotlin 与 Java 互操作:混合工程里的平台类型与 API 边界
java·开发语言·kotlin·suspend·nullable
酉鬼女又兒9 小时前
零基础入门 DeepSeek V4 Pro API 开发:从环境搭建、消息格式规范到翻译函数实战、少样本提示、多轮对话聊天机器人与常见报错全流程详解指南
大数据·网络·数据库·人工智能·macos·机器人·github
X-⃢_⃢-X9 小时前
一、第一阶段:认识 Spring Boot
java·spring boot·后端
前端工作日常9 小时前
我学习到的Java程序的生命周期
java·后端
SunnyDays101110 小时前
Java 实现 PDF 页面删除、排序、旋转和裁剪
java·pdf