如何在impala中修改parquet表的字段类型以及修复过程

2022-09-09 12:59:11

一、需求场景

众所周知impala和hive是共用一天元数据。因为前期设计impala外部表的时候考虑不足,某些字段设置成int类型,但是随着业务增长数值已经超过了int的最大值,不能满足业务需求,所以要对某些int类型的字段进行修改字段类型为string。但是parquert在存储上,做了加密,二级制存储压缩,因为Impala对Parquet文件中列的顺序很敏感,所以在表的列定义与Parquet文件的列定义顺序不一致时,会导致Impala查询返回的结果与预期不一致。可以参考Impala的JIRA,https://issues.apache.org/jira/browse/IMPALA-779

场景:

impala修改表字段语法为:

ALTER TABLE name CHANGE column_name new_name new_type

#问题复现

ALTER TABLE test.page_mv CHANGE ware_goods_id ware_goods_id STRING;


在impala中我修改page_mv表(parquet表)的ware_goods_id字段从int改成string类型后select查询报错

ERROR: File '/user/hive/warehouse/page_mv/p_point_day=2019-10-21/p_point_type=1/fd4c71a99_data.0.parq' has an incompatible Parquet schema for column 'page_mv.ware_goods_id'. Column type: STRING, Parquet schema:
optional int32 ware_goods_id [i:69 d:1 r:0]

于是乎我改回int类型,查询恢复正常。

ALTER TABLE test.page_mv CHANGE ware_goods_id ware_goods_id STRING;


但是我确实需要把ware_goods_id字段类型从int改成string!!!于是我再次尝试

ALTER TABLE test.page_mv CHANGE ware_goods_id ware_goods_id STRING;


然后新建一张page_mv_tmp表定义里面ware_goods_id字段是string类型,

CREATE EXTERNAL TABLE test.page_mv_tmp (                                                  
  data_key STRING COMMENT '数据键md5',                                                                                                                                 
  ware_goods_id STRING COMMENT '入库商品',                                                                                                                          
)                                                                                                         
PARTITIONED BY (                                                                                          
  p_point_day STRING COMMENT '日期',                                                                      
  p_point_type INT COMMENT '埋点类型'                                                                     
)                                                                                                         
STORED AS PARQUET                                                                                         
LOCATION 'hdfs://nameservice1/user/hive/warehouse/test/page_mv';
--这里可以选择指定原来的hdfs路径,也可以选择重新指定一个新的hdfs路径。因为这张是外部表只是对hdfs路径进行映射而已。

这方面如果想了解可以参考外部表和内部表区别
hive1.1.0建立外部表关联HDFS文件

然后执行

insert overwrite table test.page_mv_tmp partition(p_point_day,p_point_type)  select * from page_mv

报错说字段类型不匹配!

Expression 'page_mv.ware_goods_id' (type: INT) is not compatible with column 'ware_goods_id' (type: STRING)

这下看来直接alter parquet表是不可能成功的

二、解决过程

在insert overwrite进刚才新建的page_mv_tmp时对这个ware_goods_id字段进行强转,这里用到的是impala的动态分区原理

insert overwrite table test.page_mv_tmp partition(p_point_day,p_point_type)
select data_key,CAST(ware_goods_id AS string),p_point_day,p_point_type from test.page_mv;

通过这样处理把原来page_mv的数据重新导入到page_mv_tmp表中了,而且是动态分区导入到指定日期分区里面,相当于数据自己对号入座了。

全部导入完成后对page_mv_tmp修改表名即可完成对ware_goods_id字段的类型转换(从int转到string类型)

ALTER TABLE test.page_mv_tmp RENAME TO test.page_mv;

总结:其实上述整个过程并不是真正的对parquet进行修改字段类型,只是新建了一张修改好字段类型的新表,然后把原来表的数据以动态分区的方式导入到新表中,再重命名为原来的表名完成的。因为parquet是parquert在存储上,做了加密,二级制存储压缩,不可以修改的,包括去hive中执行也是不行的!

  • 作者:杜克泰森
  • 原文链接:https://blog.csdn.net/duketyson2009/article/details/103205033
    更新时间:2022-09-09 12:59:11