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

相关推荐
程序员黑豆2 小时前
Java 注释详解:单行、多行与文档注释的完整指南
java·前端·ai编程
hey_sml4 小时前
JAVA每日一学---CompletableFuture中thenApply与thenCompose区别详解
java·开发语言
Doraemomo4 小时前
数据结构-环形链表
java·数据结构·链表
Web3_Daisy4 小时前
Pump.fun 与 FOMO 竞争背后的 Meme 市场变局
大数据·人工智能·金融·web3·区块链
萧瑟余晖5 小时前
Java深入解析篇十七之SpringCloud
java·开发语言
是未才5 小时前
从输入 URL 到页面返回:DNS、路由、TLS 与 HTTP 完整链路
java·后端·计算机网络
ttod_qzstudio6 小时前
Java 常用语法极简通关(五):类与对象——字段、方法、构造器、this 与 static
java·开发语言·python
论文避坑指南6 小时前
论文写作全流程AI合规边界:从选题到投稿的“红绿灯“清单
大数据·人工智能·深度学习
萧瑟余晖7 小时前
Java深入解析篇十七之Spring Security
java·开发语言·spring
V哥AI增长8 小时前
Schema.org 结构化数据与GEO技术落地:AI引擎引用机制与JSON-LD部署实证研究
大数据·运维·人工智能