1. 概述
Hive使用过程中的中文乱码主要涉及两块,元数据乱码和数据乱码,下面罗列了各种乱码以及相关的解决办法。
本文中涉及中文乱码的组件主要是指 metastore 和 Hive CLI这两个组件。
1.1 环境版本说明
- Hadoop: 2.6.1
- Hive: 1.2.2
- mysql community: 5.7.43 (hive 元数据)
1.2 字符集编码概述
TODO
2. Hive元数据中文乱码
2.1 Hive CLI 查看 show create table 中文乱码
2.1.1 现象
2.1.2 解决办法
hive源代码对中文支持不好,需要修改源代码重新编译,才能解决这个问题。
https://github.com/apache/hive/blob/rel/release-1.2.2/ql/src/java/org/apache/hadoop/hive/ql/exec/DDLTask.java#L548
修改前
outStream.writeBytes(createTab_stmt.toString());
修改后
outStream.write(createTab_stmt.toString().getBytes("UTF-8"));
修改前
outStream.writeBytes(createTab_stmt.render());
修改后
outStream.write(createTab_stmt.render().getBytes("UTF-8"));
2.2 Hive CLI 查看 desc table 中文乱码
这个问题是由于Hive Metadata SQL脚本中创建表的默认字符集用的是latin1造成的。
2.2.1 现象
和Hive CLI 中的 show create table中文乱码类似
只不过使用的命令是
hive > desc <table_name>
2.2.2 解决办法-现有环境
对于Hive Metadata已经在数据库创建好的情况下,按照如下步骤检查修改
此修改仅对后续hive table创建产生作用
- 修改Hive Metadata数据库中相关字段字符集为utf8
-- 修改表字段注解和表注解
alter table hive.COLUMNS_V2 modify column COMMENT varchar(256) character set utf8;
alter table hive.TABLE_PARAMS modify column PARAM_VALUE varchar(4000) character set utf8;
-- 修改分区字段注解
alter table hive.PARTITION_PARAMS modify column PARAM_VALUE varchar(4000) character set utf8 ;
alter table hive.PARTITION_KEYS modify column PKEY_COMMENT varchar(4000) character set utf8;
-- 修改索引注解
alter table hive.INDEX_PARAMS modify column PARAM_VALUE varchar(4000) character set utf8;
- mysql中验证
select table_schema, table_name, TABLE_COLLATION, CREATE_OPTIONS, TABLE_COMMENT from information_shcema.tables where TABLE_SCHEMA='hive';
+--------------+---------------------------+-------------------+----------------+---------------+
| table_schema | table_name | TABLE_COLLATION | CREATE_OPTIONS | TABLE_COMMENT |
+--------------+---------------------------+-------------------+----------------+---------------+
| hive | BUCKETING_COLS | utf8_general_ci | | |
| hive | CDS | utf8_general_ci | | |
| hive | COLUMNS_V2 | utf8_general_ci | | |
| hive | COMPACTION_QUEUE | utf8_general_ci | | |
| hive | COMPLETED_TXN_COMPONENTS | utf8_general_ci | | |
| hive | DATABASE_PARAMS | utf8_general_ci | | |
| hive | DBS | utf8_general_ci | | |
| hive | DB_PRIVS | utf8_general_ci | | |
| hive | DELEGATION_TOKENS | utf8_general_ci | | |
select TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME,DATA_TYPE,COLUMN_TYPE,CHARACTER_SET_NAME,COLLATION_NAME from COLUMNS where TABLE_SCHEMA='hive' and table_name ='COLUMNS_V2';
+--------------+------------+-------------+-----------+---------------+--------------------+-----------------+
| TABLE_SCHEMA | TABLE_NAME | COLUMN_NAME | DATA_TYPE | COLUMN_TYPE | CHARACTER_SET_NAME | COLLATION_NAME |
+--------------+------------+-------------+-----------+---------------+--------------------+-----------------+
| hive | COLUMNS_V2 | CD_ID | bigint | bigint(20) | NULL | NULL |
| hive | COLUMNS_V2 | COMMENT | varchar | varchar(256) | utf8 | utf8_general_ci |
| hive | COLUMNS_V2 | COLUMN_NAME | varchar | varchar(128) | utf8 | utf8_general_ci |
| hive | COLUMNS_V2 | TYPE_NAME | varchar | varchar(4000) | utf8 | utf8_general_ci |
| hive | COLUMNS_V2 | INTEGER_IDX | int | int(11) | NULL | NULL |
+--------------+------------+-------------+-----------+---------------+--------------------+-----------------+
5 rows in set (0.00 sec)
- 更新hive-site.xml
<property>
<name>javax.jdo.option.ConnectionURL</name>
<value>jdbc:mysql://IP:3306/db_name? createDatabaseIfNotExist=true&useUnicode=true&characterEncoding=UTF-8</value>
<description>JDBC connect string for a JDBC metastore</description>
</property>
2.2.2 解决办法-待建环境
对于Hive Metadata尚未在数据库创建的情况下,如新环境搭建,在安装hive前,检查如下步骤。
-
修改mysql字符集
mysql字符集修改前
-
vi /etc/my.cnf
character_set_server=utf8
systemctl restart mysqld
- 修改Hive Mysql metadata SQL脚本中的字符集
>find $HIVE_HOME -name "*mysql*.sql"
./scripts/metastore/upgrade/mysql/hive-schema-1.2.0.mysql.sql
./scripts/metastore/upgrade/mysql/hive-txn-schema-0.14.0.mysql.sql
修改脚本中的字符集
DEFAULT CHARSET=latin1 -> DEFAULT CHARSET=utf8
CHARACTER SET latin1 COLLATE latin1_bin -> CHARACTER SET utf8 COLLATE utf8_bin
- 更新hive-site.xml
<property>
<name>javax.jdo.option.ConnectionURL</name>
<value>jdbc:mysql://IP:3306/db_name? createDatabaseIfNotExist=true&useUnicode=true&characterEncoding=UTF-8</value><description>JDBC connect string for a JDBC metastore</description>
</property>
- 创建hive metadata
$HIVE_HOME/bin/schematool -dbType mysql -initSchema
3. Hive表数据乱码
3.1 数据准备
hive> CREATE TABLE test(
way string COMMENT 'way字段备注',
random_str string COMMENT 'random_str字段备注')
COMMENT 'test表备注'
ROW FORMAT DELIMITED FIELDS
TERMINATED BY ',' LINES TERMINATED BY '\n';
3.2 insert语句插入的数据
采用三种不同的方式直接用insert语句插入hive table,第一种情况会导致乱码
-- 方式1 - 乱码
hive> insert into test values ('way1','中文测试');
-- 方式2 - OK
hive> insert into test select 'way2', '中文测试' from (select 1) dummy;
-- 方式3 - OK
hive> insert into test select 'way3', decode(binary('测试3'),'utf-8') from (select 1) dummy;
hive> select * from test;
insert语句hive查询结果
[hadoop@master etc]$ hadoop dfs -text hdfs://master:9000/hive/warehouse/test/000000_0*
hdfs文件查看结果
问题:
为什么方式1的插入方式是乱码?
3.3 load文件到表
这里模拟两种字符编码的文件load分别是UTF-8和GBK
在load文件到hive之前先要确定文件的编码
[hadoop@master hive]$ file test*
test-data.gbk.txt: ISO-8859 text
test-data.utf8.txt: UTF-8 Unicode text
- 1.UTF-8文件Load - OK
hive> load data local inpath '/home/hadoop/lianxi/hive/test-data.utf8.txt' into table test;
Loading data to table default.test
Table default.test stats: [numFiles=4, numRows=0, totalSize=130, rawDataSize=0]
- GBK文件Load - 乱码
hive> load data local inpath '/home/hadoop/lianxi/hive/test-data.gbk.txt' into table test;
Loading data to table default.test
Table default.test stats: [numFiles=5, numRows=0, totalSize=199, rawDataSize=0]
-
查询
hive查询结果
hdfs查询结果
-
-
- 问题与解决
hive默认的表的编码是UTF-8,要支持其他编码的数据,可以使用如下两种方式
- 4.1 原始文件转为UTF-8再load到表中 [推荐做法]
[hadoop@master hive]$ iconv -f gbk -t utf-8 /home/hadoop/lianxi/hive/test-data.gbk.txt > /home/hadoop/lianxi/hive/test-data.gbk-utf8.txt
- 4.2 Hive表属性serialization.encoding修改再load到表中 [不推荐]
这个是表级别的修改,会导致表中已有数据出现乱码
hive> ALTER TABLE test SET SERDEPROPERTIES('serialization.encoding'='GBK');
- 问题与解决
问题:
有方法在load的时候把数据从一种编码比如GBK转换为UTF-8 而不是通过修改表级别的编码?