首页 > 数据库 > 数据库开发技术 > Hive元数据中中文乱码问题排查解决
背景:最近一直在做基于Hive的离线数据仓库的构建,随着仓库的初具规模,发现在使用过程往往会有同事发现hive表的英文注释并不容易理解,因此想着能够使用中文进行hive表的元数据管理,但在时间过程中也发现了一些中文乱码的问题,在这里进行笔记。
hive (default)> CREATE TABLE `t2`(`id` int COMMENT 'id',`name` string COMMENT '名称');hive (default)> desc formatted t2;OK# col_name data_type commentid int idname string ????
由于Hive使用关系型数据库MySQL进行管理元数据,而Hive表在存储过程中由于字符长度的问题,默认使用了latin1字符集,这个时候,我们千万不能为了修改中文乱码的问题,而把全部的库、表、行都改成utf-8,否则会有意外的惊喜。
知道了为什么存在中文乱码的问题后,我们就可以根据以下几点逐一排查。
•数据库本身相关环境的默认字符集是否为utf8•业务数据库的库表行使用的默认字符集•客户端连接默认使用的字符集
检查MySQL环境
mysql> \s;--------------mysql Ver 14.14 Distrib 5.1.73, for redhat-linux-gnu (x86_64) using readline 5.1Connection id: 396097Current database:SSL: Not in useCurrent pager: stdoutUsing outfile: ''Using delimiter: ;Server version: 5.6.28 MySQL Community Server (GPL)Protocol version: 10Connection: 127.0.0.1 via TCP/IPServer characterset: latin1Db characterset: latin1Client characterset: latin1Conn. characterset: latin1TCP port: 3306....mysql> show variables like "%collation%";+----------------------+-------------------+| Variable_name | Value |+----------------------+-------------------+| collation_connection | latin1_swedish_ci || collation_database | latin1_swedish_ci || collation_server | latin1_swedish_ci |+----------------------+-------------------+mysql> show variables like 'char%';+--------------------------+----------------------------+| Variable_name | Value |+--------------------------+----------------------------+| character_set_client | latin1 || character_set_connection | latin1 || character_set_database | latin1 || character_set_filesystem | binary || character_set_results | latin1 || character_set_server | latin1 || character_set_system | utf8 || character_sets_dir | /usr/share/mysql/charsets/ |+--------------------------+----------------------------+
由上面信息知道,当前MySQL实例默认的字符集就设置成了latin1,如果想要修改默认字符集,可以通过修改MySQL的配置文件,并重启完成。
# 修改MySQL配置文件/etc/my.cnf 并重启MySQL[mysqld]collation-server = utf8_general_cicharacter-set-server = utf8[client]default-character-set=utf8
排查业务数据库相关的字符集
mysql> show create database hive;+----------+-----------------------------------------------------------------+| Database | Create Database |+----------+-----------------------------------------------------------------+| hive | CREATE DATABASE `hive` /*!40100 DEFAULT CHARACTER SET latin1 */ |+----------+-----------------------------------------------------------------+mysql> show create table hive.SDS\G;*************************** 1. row ***************************Table: SDSCreate Table: CREATE TABLE `SDS` (`SD_ID` bigint(20) NOT NULL,`CD_ID` bigint(20) DEFAULT NULL,`INPUT_FORMAT` varchar(4000) CHARACTER SET latin1 COLLATE latin1_bin DEFAULT NULL,`IS_COMPRESSED` bit(1) NOT NULL,`IS_STOREDASSUBDIRECTORIES` bit(1) NOT NULL,`LOCATION` varchar(4000) CHARACTER SET latin1 COLLATE latin1_bin DEFAULT NULL,`NUM_BUCKETS` int(11) NOT NULL,`OUTPUT_FORMAT` varchar(4000) CHARACTER SET latin1 COLLATE latin1_bin DEFAULT NULL,`SERDE_ID` bigint(20) DEFAULT NULL,PRIMARY KEY (`SD_ID`),KEY `SDS_N50` (`SERDE_ID`),KEY `SDS_N49` (`CD_ID`),CONSTRAINT `SDS_FK1` FOREIGN KEY (`CD_ID`) REFERENCES `CDS` (`CD_ID`),CONSTRAINT `SDS_FK2` FOREIGN KEY (`SERDE_ID`) REFERENCES `SERDES` (`SERDE_ID`)) ENGINE=InnoDB DEFAULT CHARSET=latin11 row in set (0.00 sec)
由上面输出可以知道,hive库以及库中的相关表均使用latin1作为默认的字符集,因此,可以针对需要支持中文的地方进行修改默认字符集即可。
排查客户端连接(JDBC)默认字符集
# 查看hive的JDBC连接串$ cat hive/conf/hive-site.xml | grep mysql<value>jdbc:mysql://10.0.0.1:3306/hive?createDatabaseIfNotExist=true&useUnicode=true&characterEncoding=UTF-8</value><value>com.mysql.jdbc.Driver</value>
由上面输出可以看到,客户端的JDBC连接串是使用的utf8编码。
从以上三个排查过程中发现,数据库默认字符集和库表字符集均是latin1,那我们知道作为hive的元数据存储一般只有库、表、行的注释部分才可能会有中文字符,因此,为了避免对过多的库表进行字符集设置,我们仅需要对相关库、表、行注释部分进行设置utf8字符即可。
# 修改表字段和表注释alter table TABLE_PARAMS modify column PARAM_VALUE varchar(4000) character set utf8;alter table COLUMNS_V2 modify column COMMENT varchar(256) character set utf8# 修改分区字段注释alter table PARTITION_PARAMS modify column PARAM_VALUE varchar(4000) character set utf8;alter table PARTITION_KEYS modify column PKEY_COMMENT varchar(4000) character set utf8;# 修改索引注释alter table INDEX_PARAMS modify column PARAM_VALUE varchar(4000) character set utf8;
修改完成后,我们重新来创建一张表:
# hive建表,查看注释hive (default)> create table t3(name string comment '名字') comment '测试表';OKhive (default)> desc formatted t3;OK# col_name data_type commentname string 名字# MySQL查看相关字符集mysql> select * from COLUMNS_V2 where CD_ID > 1001;+-------+---------+-------------+-----------+-------------+| CD_ID | COMMENT | COLUMN_NAME | TYPE_NAME | INTEGER_IDX |+-------+---------+-------------+-----------+-------------+| 1006 | 名字 | name | string | 0 |+-------+---------+-------------+-----------+-------------+1 row in set (0.00 sec)mysql> SELECT * FROM TABLE_PARAMS WHERE TBL_ID >920;+--------+-----------------------+-------------+| TBL_ID | PARAM_KEY | PARAM_VALUE |+--------+-----------------------+-------------+| 921 | comment | 测试表 || 921 | transient_lastDdlTime | 1548340084 |+--------+-----------------------+-------------+
至此,我们的Hive表已经支持中文元数据注释了。
虽然我们临时修改了表的字符集解决了几个问题,但是我们仍然需要注意一下几个问题:
•在国内,生产环境中,我们的MySQL数据库通常要提前设置成utf8的字符集,以避免后期的字典维护的问题•建议在Hive在刚开始使用时就将相关库表字符集改成utf8,否则在改之前的数据依然是乱码的•如果在中途修改了字符集,如果需要将历史数据进行中文字符集修改,需要进行库表重建(或者直接修改表注释)
alter table t1 CHANGE COLUMN name name string comment '名称';# 修改完之后立刻生效
注意:如果源表已经存在乱码的comment,通过上述语句修改表描述并不能直接修改为中文注释,此时需要将表重建,进行重新生成元数据,如果源表为外部分区表,直接将分区导入即可,如果是普通管理表,需要重新导入数据
# 外部分区表重建过程drop table host;createexternaltable if not exists dwd.host (ip string comment '主机地址',appname string comment '主机关联应用名',ip_state string comment '主机状态(资源分配|在线|下线)',group string comment '主机所在应用的分组',envtype string comment '主机所在应用的环境类型',idc string comment '主机所属机房')PARTITIONED BY (dt string)stored as ORC;desc dwd.fact_sure_host;# 数据导入(需要提前查找表的分区,并按照分区导入)alter table dwd.host add partition(dt='20190106');alter table dwd.host add partition(dt='20190105');alter table dwd.host add partition(dt='20190104');
欢迎关注我的公众号
原文作者:云原生运维技术;如有侵权,请联系管理员删除。