当Hive表使用中文列名时遇到的异常问题

2023-02-03 15:03:00.0

问题描述

使用Spark SQL将DataFrame(列名为中文)写入到Iceberg Hive Catalog中时,出现如下异常信息,并且写入失败:

“org.apache.spark.sql.AnalysisException: org.apache.hadoop.hive.ql.metadata.HiveException: MetaException(message:Add request failed : INSERT INTO COLUMNS_V2 (CD_ID,COMMENT,`COLUMN_NAME`,TYPE_NAME,INTEGER_IDX) VALUES (?,?,?,?,?) )”
......

实际上,如果直接在Hive中创建带有中文字段名称的表时,也会遇到这个异常信息。例如:

CREATE EXTERNAL TABLE stu(
  `商品ID` STRING,
  `库存数量` INT,
  `单价` DOUBLE
)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY ','
LINES TERMINATED BY '\n'
STORED AS TEXTFILE
LOCATION 'hdfs://xueai8:8020/business'

问题剖析

从报错信息中分析,推断是在执行建表语句时,需要更新Hive的元数据,而在Hive的元数据进行更新时,需要向元数据存储数据库MySQL的hive数据库的COLUMNS_V2表中插入表结构信息。报错信息中说明:在向MySQL中hive数据库的表COLUMNS_V2中插入字段名称时出现了问题。

为了证明这个推测,登录MySQL服务器,查看数据库hive中的COLUMNS_V2表的创建语句,命令如下:

mysql> use hive;
mysql> show create table COLUMNS_V2\G;

输出内容如下:

MariaDB [hive]> show create table COLUMNS_V2\G;
*************************** 1. row ***************************
       Table: COLUMNS_V2
Create Table: CREATE TABLE `COLUMNS_V2` (
  `CD_ID` bigint(20) NOT NULL,
  `COMMENT` varchar(256) CHARACTER SET latin1 COLLATE latin1_bin DEFAULT NULL,
  `COLUMN_NAME` varchar(767) CHARACTER SET latin1 COLLATE latin1_bin NOT NULL,
  `TYPE_NAME` mediumtext,
  `INTEGER_IDX` int(11) NOT NULL,
  PRIMARY KEY (`CD_ID`,`COLUMN_NAME`),
  KEY `COLUMNS_V2_N49` (`CD_ID`),
  CONSTRAINT `COLUMNS_V2_FK1` FOREIGN KEY (`CD_ID`) REFERENCES `CDS` (`CD_ID`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
1 row in set (0.01 sec)

观察上面的输出内容,可以看到COLUMN_NAME字段的编码字符集为默认的latin1字符集,因此中文名无法识别。所以要想能识别中文字段名,需要将该字段的字符集编码改为utf8。

问题解决

通过SQL命令将COLUMN_NAME字段的字符集编码修改为utf8,命令如下:

mysql> alter table COLUMNS_V2 modify column COLUMN_NAME varchar(255) character set utf8   COLLATE utf8_general_ci not null;

然后再执行hive创建带有中文列名的表的时候,或者向Iceberg Hive Catalog中创建带有中文列名的表的时候,都可以正常执行了。


《Spark原理深入与编程实战》