美文网首页
Hive元数据中中文乱码问题排查解决

Hive元数据中中文乱码问题排查解决

作者: 9c46ece5b7bd | 来源:发表于2019-01-24 22:47 被阅读13次

    背景:最近一直在做基于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               comment
    
    id                      int                     id
    name                    string                  ????
    

    为什么不直接使用utf8

    由于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.1
    
    Connection id:      396097
    Current database:
    SSL:            Not in use
    Current pager:      stdout
    Using outfile:      ''
    Using delimiter:    ;
    Server version:     5.6.28 MySQL Community Server (GPL)
    Protocol version:   10
    Connection:     127.0.0.1 via TCP/IP
    Server characterset:    latin1
    Db     characterset:    latin1
    Client characterset:    latin1
    Conn.  characterset:    latin1
    TCP 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_ci
    character-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: SDS
    Create 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=latin1
    1 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&amp;useUnicode=true&amp;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 '测试表';
    OK
    
    hive (default)> desc formatted t3;
    OK
    # col_name              data_type               comment
    
    name                    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;
    create
      external
    table 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');
    

    相关文章

      网友评论

          本文标题:Hive元数据中中文乱码问题排查解决

          本文链接:https://www.haomeiwen.com/subject/tklpjqtx.html