1 问题场景

假设某有数据的Hive表temp_table的字段状况如下,需要将A字段由string类型转为int类型:

字段名称字段类型是否为分区字段
Astring
Bint
Cbigint
Dstring

1.1 问题发生的背景

在Hdfs数据库中,该表的数据是以Parquet文件格式存储的,包含多个分区。原本在该表中的字段A的类型为int。然而笔者误操作,将该字段的类型转换为了string,即前文所述的表字段状态。

笔者在查询时发现,用HiveSql查询不会报错,而用SparkSql查询本表时,会报如下错误信息:

org.apache.spark.sql.execution.QueryExecutionException: Parquet column cannot be converted in file [文件所在OSS路径]. Column: [has_explicit_source_keys], Expected: StringType, Found: INT32

错误的大致意思为文件中的字段类型和Hive元数据中的字段类型不同,且无法强制转换。
为了继续可以用spark查询本表,笔者尝试修复表字段类型。然而在修复表字段类型时,笔者发现以下两种方法都无法完成操作,并且会报错

1.1 操作方法1

使用如下语句修改Hive表的字段类型时。可能会发现字段可以从string转到Int,但不能从Int转回String。

ALTER TABLE temp_table CHANGE CLOUMN A A int;

1.2 操作方法2

  1. 删除要转换类型的字段A,使原表只剩B、C两个字段。
  2. 新增字段A,将类型转换为int。由于Hive建表时不允许指定列的位置,所以会添加在表的最后。
  3. 将字段A挪到第一位。本步会报错,不允许进行此操作。
-- Step1
ALTER TABLE temp_table replace COLUMNS (B int,C bigint);
-- Step2
ALTER TABLE temp_table ADD COLUMNS (A int);
-- Step3(本步会报错)
ALTER TABLE temp_table CHANGE CLOUMN A A int FIRST;

1.3 报错信息

FAILED: Execution Error, return code 1 from org.apache.hadoop.hive.ql.exec.DDLTask. Unable to alter table. The following columns have types incompatible with the existing columns in their respective positions :
column_name

该错误的意思是,Hive表元数据中已有的字段类型无法被转换为新指定的字段类型。而且结合上述操作方法2可知,如果表中有数据,那么即便删除了某个字段,其字段类型仍然会保留在原来的位置上。

2 问题分析

查看官方文档后,可以了解到,列转换操作是由一个参数控制的:

hive.metastore.disallow.incompatible.col.type.changes 设置为 false 时,Metastore 中的列类型可以从任何类型更改为任何其他类型。 在执行类型更改后,如果新类型可以正确显示数据,则将显示数据。 否则,数据将显示为 NULL。

而hive.metastore.disallow.incompatible.col.type.changes这个参数,在Hive2.0后,默认为True。即在字段类型转换时,不再允许显式转换(强制转换),而是只能进行隐式转换,即由低级类型转换为高级类型。

关于隐式转换的规则Hive官方文档(需要翻墙后查看该链接)中的说明如下:
在这里插入图片描述
本例中的Hive版本为2.7.2
在这里插入图片描述

所以为了实现字段类型的显式转换,需要设置hive.metastore.disallow.incompatible.col.type.changes。

3 解决方法

特别注意:在某些环境下,前两种方法都不能使该参数生效,只能使用第三种方法

3.1 在SQL代码中加参数

在SQL代码最前方加入:set hive.metastore.disallow.incompatible.col.type.changes=false;

3.2 在提交Hive程序时,附加上hiveconf参数

3.3 修改 hive-site.xml文件

在hive 配置文件 hive-site.xml中添加或修改参数:

<property>
<name>hive.metastore.disallow.incompatible.col.type.changes</name>
<value>false</value>
</property>

修改参数之后,需要重启Hive服务才能使参数生效。重启Hive服务后,使用Hive查询该参数值,可以发现修改成功了
在这里插入图片描述
同时,可以在DDL语句修改Hive元数据中的字段类型时,实现显式转换。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐