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

相关推荐
CodeSheep程序羊几秒前
宇树科技,即将上市!
java·c语言·c++·人工智能·python·科技·硬件工程
白露与泡影1 分钟前
Java 8老系统旁路接入AI Gateway:不升级JDK也能用AI
java·人工智能·gateway
Misnearch1 分钟前
Java中创建Map的做法
java·hashmap
scan7242 分钟前
从runtime获取信息
java·服务器·前端
serve the people2 分钟前
Elasticsearch(3) show me some examples
大数据·elasticsearch·jenkins
心之伊始3 分钟前
Spring Cloud Gateway RequestRateLimiter 实战:Redis 令牌桶限流从配置到本地压测验证
java·架构·源码分析·csdn
招标采购导航网7 分钟前
标讯质量评分体系:招标采购导航网如何给每条标讯打“可信度分”和“价值分”
大数据·人工智能
段一凡-华北理工大学14 分钟前
工业领域的Hadoop架构学习~系列文章22:Hadoop生态展望 - 面向未来的技术演进
大数据·人工智能·hadoop·分布式·学习·架构·高炉炼铁
AI人工智能+电脑小能手15 分钟前
【大白话说Java面试题 第105题】【并发篇】第5题:说一下 synchronized 关键字的底层原理?
java·开发语言·面试
渡码桑17 分钟前
英伟达与SK海力士合作,下一代AI内存技术路线解析
大数据·人工智能·音视频