Hive中文乱码(JDBC连接HiveServer2)问题解决

工作中遇到通过jdbc连接hive服务器(我们是用HiveServer2),获取的中文是乱码的问题。使用beeline有同样的效果,而用hive命令行却能正常显示中文。而写入,读取的文件,都是用的UTF-8,Java环境也都是UTF-8字符集。这是怎么回事?

问题重现

我们可以以如下方式重现:

shell> cat upload.txt
row1
行2
行3
row4

hive中在default库中创建表str_test(v string),然后将upload.txt文件上传到该表的存储路径:

shell> hadoop fs -put upload.txt /user/hive/warehouse/str_test/
shell> beeline -d org.apache.hive.jdbc.HiveDriver -u jdbc:hive2://localhost:10000 -e “select * from str_test”

+——-+
| v |
+——-+
| row1 |
| ?2 |
| ?3 |
| row4 |
| |
+——-+

shell> hive -e “select * from str_test”

row1
行2
行3
row4

出现乱码时,交互方式是:Client->jdbc->Hive Server2->Hadoop,而正常显示的Hive命令行的交互是:Hive CLI->Hadoop。所以基本可以确定乱码问题在Client->jdbc->Hive Server2这三个部分的其中一个部分上。

排查1.Client

Client是我们自行开发的Java应用,经查整个项目一直都是用的UTF-8字符集,排查Client的编码问题。

排查2.jdbc

网上查询一番类似的问题,参考了 文章12后,我们初步认为,采用网上推荐的方案,更新hive的JDBC驱动程序,将获取的字符强制硬编码使用UTF-8字符集,可以解决我们的问题。

我们使用的驱动包是hive-jdbc-0.10.0-cdh4.5.0.jar,可以看到里面有两个包:

hive-jdbc

我们按照网上的说法,更新org.apache.hadoop.hive.jdbc.HiveResultSet,采用如下patch:

Index: jdbc/src/java/org/apache/hadoop/hive/jdbc/HiveQueryResultSet.java
===================================================================
— jdbc/src/java/org/apache/hadoop/hive/jdbc/HiveQueryResultSet.java (revision 1195103)
+++ jdbc/src/java/org/apache/hadoop/hive/jdbc/HiveQueryResultSet.java (working copy)
@@ -153,7 +153,7 @@
StructObjectInspector soi = (StructObjectInspector) serde.getObjectInspector();
List fieldRefs = soi.getAllStructFieldRefs();
- Object data = serde.deserialize(new BytesWritable(rowStr.getBytes()));
+ Object data = serde.deserialize(new BytesWritable(rowStr.getBytes(“UTF-8″)));
assert row.size() == fieldRefs.size() : row.size() + “, ” + fieldRefs.size();
for (int i = 0; i < fieldRefs.size(); i++) {

这个patch强制将获取的内容强制使用UTF-8编码解码。修改jar的方式是

  1. 获取jdbc/src/java/org/apache/hadoop/hive/jdbc/HiveQueryResultSet.java的源码(通过svn:http://svn.apache.org/repos/asf/hive/trunk或者使用Maven直接download source)
  2. 在依赖满足的情况下编译获取class文件
  3. 用新生成的HiveQueryResultSet.class直接替换掉hive-jdbc jar中org.apache.hadoop.hive.jdbc包下HiveQueryResultSet.class!

按照如上方式处理后,发现依然无效。不仅如此,我们调整LOG为DEBUG(即打印出大量DEBUG日志),然后尝试各种方法:加入打印语句、修改输出内容、甚至整个删除jar中的org.apache.hadoop.hive.jdbc包等等,最终发现,Java程序调用Hive JDBC时根本没进入org.apache.hadoop.hive.jdbc中,即使删除org.apache.hadoop.hive.jdbc这个包都没影响,生效的是org.apache.hive.jdbc包中的内容!

org.apache.hive.jdbc包中没有找到相似的serde.deserialize这样的反序列化的语句。看来网上的方案在我们这不适用。那么这两个包是什么用途,什么关系呢?

HiveServer2 Clients中,一段话提醒了我们:

The JDBC connection URL format has the prefix jdbc:hive2:// and the Driver class is org.apache.hive.jdbc.HiveDriver. Note that this is different from the old HiveServer.

再看第一版本的HiveServer Client,使用的是:

driverName = “org.apache.hadoop.hive.jdbc.HiveDriver“;

看到这两个包,在比对我们疑惑的两个包,一切明朗了:

  • org.apache.hadoop.hive.jdbc 针对HiveServer1,与我们的场景无关。
  • org.apache.hive.jdbc 针对HiveServer2,我们需要关注。
  • 如上网络上给出的方案针对HiveServer1,确实不适用我们的场景。

细查org.apache.hive.jdbc的类,发现这个版本与HiveServer1的处理完全不一样了,不是使用serde,还是直接用了thrift,其中也没找到编码相关的选项。这条路走到头了。

排查3.HiveServer2

剩下就是检查HiveServer2使用的字符集了。

系统层面:
shell> locale 
LANG=zh_CN.UTF-8
LC_CTYPE=”zh_CN.UTF-8″
LC_NUMERIC=”zh_CN.UTF-8″
LC_TIME=”zh_CN.UTF-8″
LC_COLLATE=”zh_CN.UTF-8″
LC_MONETARY=”zh_CN.UTF-8″
LC_MESSAGES=”zh_CN.UTF-8″
LC_PAPER=”zh_CN.UTF-8″
LC_NAME=”zh_CN.UTF-8″
LC_ADDRESS=”zh_CN.UTF-8″
LC_TELEPHONE=”zh_CN.UTF-8″
LC_MEASUREMENT=”zh_CN.UTF-8″
LC_IDENTIFICATION=”zh_CN.UTF-8″
LC_ALL=
shell> echo $LANG
zh_CN.UTF-8

我们是使用CDH4.5中自带的hive-server2启动脚本启动的hiveserver2服务,看看脚本环境中字符集是怎样的。

/etc/init.d/hive-server2中添加locale命令,重启后却是这样的:

shell> service hive-server2 restart
LANG=
LC_CTYPE=”POSIX”
LC_NUMERIC=”POSIX”
LC_TIME=”POSIX”
LC_COLLATE=”POSIX”
LC_MONETARY=”POSIX”
LC_MESSAGES=”POSIX”
LC_PAPER=”POSIX”
LC_NAME=”POSIX”
LC_ADDRESS=”POSIX”
LC_TELEPHONE=”POSIX”
LC_MEASUREMENT=”POSIX”
LC_IDENTIFICATION=”POSIX”
LC_ALL=
Starting Hive Server2 (hive-server2): [确定]
Hive Server2 is running [确定]

看来hive-server2的运行环境并没有沿用系统层面的环境,针对它进行配置:

在/etc/init.d/hive-server2删除刚添加的locale,然后添加语句:export LANG=zh_CN.UTF-8

这样确保hive-server2的启动会使用指定字符集。

当然,如果使用hive –service hiveserver2命令启动,只要保证环境变量LANG=zh_CN.UTF-8即可。

测试结果,如上设置,重启hive-server2后,乱码问题解决!

小结

最终解决乱码问题只是添加了export LANG=zh_CN.UTF-8,确保hive-server2的运行环境使用的是UTF-8字符集,这样Client,Hive-Server和Hadoop集群都采用了UTF-8,自然不会有乱码存在了。

Done!

参考:
http://wocclyl.blog.163.com/blog/static/4622350420134301120474/

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值