Hive之中文乱码

1. 概述

Hive使用过程中的中文乱码主要涉及两块,元数据乱码和数据乱码,下面罗列了各种乱码以及相关的解决办法。
本文中涉及中文乱码的组件主要是指 metastore 和 Hive CLI这两个组件。

Hive 架构图

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 现象

hive元数据乱码

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前,检查如下步骤。

    1. 修改mysql字符集


      mysql字符集修改前

vi /etc/my.cnf
character_set_server=utf8

systemctl restart mysqld

mysql字符集修改后
    1. 修改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

    1. 更新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>

    1. 创建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]
    1. 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]
    1. 查询


      hive查询结果

      hdfs查询结果
    1. 问题与解决
      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 而不是通过修改表级别的编码?

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,525评论 6 507
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,203评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,862评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,728评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,743评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,590评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,330评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,244评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,693评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,885评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,001评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,723评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,343评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,919评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,042评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,191评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,955评论 2 355

推荐阅读更多精彩内容