Hive中文注释乱码解决方案
本文来自网易云社区
作者:王潘安
快速解决方法
目前的hive客户端在执行desc tablexxx和show create table xxx命令的时候,字段的中文注释会出现乱码情况,如(????)。在使用 ROW FORMAT SERDE 'org.openx.data.jsonserde.JsonSerDe' 建表的时候,注释则会出现from deserializer。以下几个步骤可以帮你快速解决这些问题:
1.首先在hive客户端的conf目录下找到hive-site.xml配置文件,查询本机hive所连接的metastore地址。例如:
<property>
<name>javax.jdo.option.ConnectionURL</name>
<value>jdbc:mysql://10.120.xxx.xxx:3306/hive_study</value>
</property>
连接该数据库。找到表COLUMNS_V2并查询其中的字段。如果为类似以下的乱码:
| 952 | ?????????? | in_l_notice_mail | string | 14 |
| 952 | ???????? | live_course_notice_mail | string | 22 |
| 952 | ???????????????? | mark_best_reply | string | 4 |
| 952 | ??????????? | platform_notice_mail | string | 13 |
| 952 | ???????? | question_answered | string | 3 |
| 952 | ????????? | question_digged | string | 6 |
| 952 | sns??????? | sns_friends_attend | string | 20 |
| 952 | sns??????? | sns_new_fans | string | 21 |
| 952 | | study_plan_notice | string | 15 |
| 952 | ??id
则对数据库做如下设置:
//修改字段注释字符集
alter table COLUMNS_V2 modify column COMMENT varchar(256) character set utf8;
//修改表注释字符集
alter table TABLE_PARAMS modify column PARAM_VALUE varchar(4000) character set utf8;
//修改分区注释字符集
alter table PARTITION_KEYS modify column PKEY_COMMENT varchar(4000) character set utf8;
并且重新建hive表(不是metastore的表)。如果COLUMNS_V2中的数据不为乱码,则不用做任何操作,跳过此步。
2.将本文附件中的两个jar包替换到hive客户端的lib目录中。
3.重启hive客户端,测试一下效果。
解决过程及BUG原因解释
1.准备工作
首先在自己电脑上部署HADOOP,HIVE环境。下载hive和Hive-JSON-Serde,链接:https://github.com/apache/hive https://github.com/rcongiu/Hive-JSON-Serde 确保可以运行起来。然后就要做好以下准备:
1.找到hive运行时打印的log的位置。如果没有配置如下属性,那就是默认位置:
<property>
<name>hive.exec.local.scratchdir</name>
<value>${system:java.io.tmpdir}/${system:user.name}</value>
<description>Local scratch space for Hive jobs</description>
</property>
以云课堂为例,就是放在/tmp/study目录下,日志会记录在hive.log中。
2.准备好调试环境。找到hadoop的目录,在bin目录下找到hadoop这个可执行的命令,打开它,找到如下一段代码:
if [ "$COMMAND" = "fs" ] ; then
.apache.hadoop.fs.FsShell
elif [ "$COMMAND" = "version" ] ; then
.apache.hadoop.util.VersionInfo
elif [ "$COMMAND" = "jar" ] ; then
.apache.hadoop.util.RunJar
elif [ "$COMMAND" = "key" ] ; then
.apache.hadoop.crypto.key.KeyShell
elif [ "$COMMAND" = "checknative" ] ; then
.apache.hadoop.util.NativeLibraryChecker
把他改为:
if [ "$COMMAND" = "fs" ] ; then
.apache.hadoop.fs.FsShell
elif [ "$COMMAND" = "version" ] ; then
.apache.hadoop.util.VersionInfo
elif [ "$COMMAND" = "jar" ] ; then
if ! echo "$HADOOP_CLIENT_OPTS"|fgrep 'dt_socket' ; then
HADOOP_CLIENT_OPTS="$HADOOP_CLIENT_OPTS -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8765"
fi
HIVE_DEBUG_RECURSIVE=y
HIVE_MAIN_CLIENT_DEBUG_OPTS="suspend=n,address=8765"
HIVE_CHILD_CLIENT_DEBUG_OPTS="suspend=y,address=8766"
export HADOOP_CLIENT_OPTS HIVE_CHILD_CLIENT_DEBUG_OPTS HIVE_DEBUG_RECURSIVE HIVE_MAIN_CLIENT_DEBUG_OPTS
.apache.hadoop.util.RunJar
elif [ "$COMMAND" = "key" ] ; then
.apache.hadoop.crypto.key.KeyShell
elif [ "$COMMAND" = "checknative" ] ; then
.apache.hadoop.util.NativeLibraryChecker
这样,就打开了端口号为8765的远程调试端口
具体为啥这样设置,参考这篇博客:http://blog.csdn.net/wisgood/article/details/38047921
2.查找BUG
首先声明,以下所有的调试都是基于hive 1.2.1版本和json-serde 1.3.6的版本。
Hive客户端的启动是在源码的cli目录下的org.apache.hadoop.hive.cli包中的CliDriver类中,它又具体去调用了ql目录下的org.apache.hadoop.hive.ql包中的Driver类。因此,我们在IDE中只需要引入ql目录下的maven工程即可。
打开Driver类,找到它的run方法,这便是hive命令执行的函数入口。在run方法中,主要调用的就是runInternal方法。而runInternal方法中主要就是调用了compileInternal和execute方法,也就是编译命令和执行命令两部分。
编译阶段
首先我们看看compile阶段干了些啥,通过跟踪compileInternel方法,我们可以知道,它最终调用的是compile方法。这个方法主要是用来生成执行计划树的。首先解析出树形结构,这段代码慎重跟踪下去,水太深,会游泳的可以下去看看:
ParseDriver pd = new ParseDriver();
ASTNode tree = pd.parse(command, ctx);
然后进行语义分析:
BaseSemanticAnalyzer sem = SemanticAnalyzerFactory.get(conf, tree);
sem.analyze(tree, ctx);
接着生成执行计划:
plan = new QueryPlan(queryStr, sem, perfLogger.getStartTime(PerfLogger.DRIVER_RUN), queryId,
SessionState.get().getCommandType());
最后还要拿到返回结果的模板,也就是说明返回值的样子:
schema = getSchema(sem, conf);
在这个过程中,我们重点关注的是语义分析和返回值模板的情况。可以看到,语义分析首先通过工厂返回了一个BaseSemanticAnalyzer,这是一个父类,而我们执行类似show create table xxx的时候,它实际执行的是它的一个子类DDLSemanticAnalyzer中的analyzeInternal方法。我们去看这个方法,发现它是一堆switch case,我们在其中找到如下代码:
case HiveParser.TOK_SHOW_CREATETABLE:
ctx.setResFile(ctx.getLocalTmpPath());
analyzeShowCreateTable(ast);
break;
跟到analyzeShowCreateTable方法中去,发现有这样一段代码:
Table tab = getTable(tableName);
好激动,貌似拿到了表信息,我们把断点打在这,并且进行调试,看看这个tab变量里面究竟有啥: 
发现什么表信息都有,的确去metastore库里面拿了东西,注意:我这里的comment是???这样的乱码是因为我的metastore里面的表的编码格式没改。所以到目前为止,hive的代码是正常的。
在analyzeShowCreateTable方法中,还有几个要注意的点,一个是:
showCreateTblDesc = new ShowCreateTableDesc(tableName, ctx.getResFile().toString());
一个是:
setFetchTask(createFetchTask(showCreateTblDesc.getSchema()));
还有一个:
rootTasks.add(TaskFactory.get(new DDLWork(getInputs(), getOutputs(), showCreateTblDesc), conf));
首先看ShowCreateTableDesc类里面有什么,发现有这样一个字符串常量:
private static final String schema = "createtab_stmt#string";
通过对比这个类同包中的其他类的schema常量,比如DescTableDesc类:
private static final String schema = "col_name,data_type,comment#string:string:string";
不难猜出,这个就是定义输出结果的样子和每个结构的类型的常量。接着我们看createFetchTask方法,在这个里面,它把上面说的字符串schema解析出来放到了Properties配置中:
String[] colTypes = schema.split("#");
prop.setProperty("columns", colTypes[0]);
prop.setProperty("columns.types", colTypes[1]);
prop.setProperty(serdeConstants.SERIALIZATION_LIB, LazySimpleSerDe.class.getName());
看到这段代码,简直点燃了我的兴奋点!我们的问题不就是字段注释乱码吗?(剧透一下,如果你不给hive传注释信息,那么hive就给你写个from deserializer)这里定义了字段名字,字段类型以及序列化类,但是没有定义字段注释!难道问题就出在这?然而仔细想想,这个地方就是误导你的。因为在这个阶段虽然已经在metastore中获取了table信息,然而这个阶段仍然是编译阶段,具体的命令还没有执行。另外在property中,设置的都是常量,所以它更不可能是最后的返回结果。其实它的作用是描述这个模板的类型以及序列化方法,而不是用来描述最后的结果的。
最后我们再来看rootTasks.add方法干了什么,可以发现,TaskFactory通过get方法产生了一个task,放到了task的序列中,这个get方法通过你传入进来的work类型,找到相应的task类型,并且通过java的反射机制创建一个task实例。在这里,我们传入的是一个DDLWork,因此它会创建一个DDLTask。我们要牢记这个DDLTask类,因为后面的执行过程中,就是去执行它!
网易云免费体验馆,0成本体验20+款云产品!
更多网易研发、产品、运营经验分享请访问网易云社区。
相关文章:
【推荐】 医疗大数据的分析和挖掘发展现状以及未来的应用前景
【推荐】 使用 Prometheus + Grafana 对 Kubernetes 进行性能监控的实践
【推荐】 用scrapy数据抓取实践
Hive中文注释乱码解决方案的更多相关文章
- Hive中文注释乱码解决方案(2)
本文来自网易云社区 作者:王潘安 执行阶段 launchTask 回到Driver类的runInternal方法,看以下执行过程.在runInternal方法中,执行过程调用了execute方法 ...
- 【原创】大叔经验分享(34)hive中文注释乱码
在hive中查看表结构时中文注释乱码,分为两种情况,一种是desc $table,一种是show create table $table 1 数据库字符集 检查 mysql> show vari ...
- Ubuntu下Matlab代码中中文注释乱码解决方案
环境:Ubuntu18.04,Matlab R2017b. 把matlab文件从windows拷贝到Ubuntu中,打开发现原先的中文注释全部乱码.真正原因是因为windows中.m文件采用的是gbk ...
- Intellij IDEA 导入 eclipese项目之后,中文注释乱码解决方案
首先,看导入后整个IJ界面: 可以看到注释是乱码,要解决问题就跟我开始做吧,看右下角有个"UTF-8",点一下选择"GBk",选择"Reload&qu ...
- myeclipse10中文注释乱码问题
将别人的项目或JAVA文件导入到自己的Eclipse中时,常常会出现JAVA文件的中文注释变成乱码的情况,主要原因就是别人的IDE编码格式和自己的Eclipse编码格式不同. 总结网上的建议和自己的体 ...
- Eclipse中文注释乱码解决
将别人的项目或JAVA文件导入到自己的Eclipse中时,常常会出现JAVA文件的中文注释变成乱码的情况,主要原因就是别人的IDE编码格式和自己的Eclipse编码格式不同. 总结网上的建议和自己的体 ...
- MyEclipse中文注释乱码解决
MyEclipse中文注释乱码解决 将别人的项目或JAVA文件导入到自己的Eclipse中时,常常会出现JAVA文件的中文注释变成乱码的情况,主要原因就是别人的IDE编码格式和自己的Eclipse编码 ...
- css中文字体乱码解决方案
css中文字体乱码解决方案:把css编码和html页面编码统一起来.如果html页面是utf-8.css.js也统一成utf-8编码.还有一个避免中文乱码的办法就是把中文字体写成英文来表示 css中文 ...
- Source Insight中文注释乱码、字体大小、等宽解决方法
中文注释乱码解决方法: 用记事本打开源文件,然后,选择文件->另存为,编码选为”ANSI“ 字体的调整: Source Insight 菜单栏选择Options->Document O ...
随机推荐
- 第六章 设计程序架构 之 设计实现WebSocket策略
1. 概述 传统网页的通信方式是请求-响应模式,每次请求-响应都是新的连接.连接的建立和断开也是需要消耗资源的. WebSocket是基于TCP协议,实现单个连接上的双向通信. 本章内容包括: 异步读 ...
- 从零开始利用vue-cli搭建简单音乐网站(七)
这几天完成了歌曲收藏功能,先看最后效果: 新注册用户:“newuser”,进入“我的音乐界面如下所示” 点击新建歌单,输入:“新歌单”,确认,如下: 目前还没有歌曲,打开音乐界面,点击收藏功能,如下, ...
- Azure 项目构建 – 部署 Drupal 网站
通过完整流程详细介绍了如何通过 Azure Web 应用. MySQL DB on Azure 等服务在 Azure 平台上快速搭建 Drupal 服务器,并将其连接到 MySQL 数据库. 此系列的 ...
- [转]八款开源Android游戏引擎
八款开源Android游戏引擎 1.Angle Angle是一款专为Android平台设计的,敏捷且适合快速开发的2D游戏引擎,基于OpenGL ES技术开发.该引擎全部用Java代码编写,并且可以根 ...
- 51nod 算法马拉松17 解题报告 以后不能赛中写题解(查逐梦者抄袭本人代码...
B题(数学题: 问(1+sqrt(2)) ^n 能否分解成 sqrt(m) +sqrt(m-1)的形式 如果可以 输出 m%1e9+7 否则 输出no n<=1e18 刚看题没思路 暴力一下 ...
- elasticsearch最全详细使用教程:搜索详解
一.搜索API 1. 搜索API 端点地址从索引tweet里面搜索字段user为kimchy的记录 GET /twitter/_search?q=user:kimchy从索引tweet,user里面搜 ...
- Web项目之Django实战问题剖析
基于AdminLTE-master模板的后台管理系统 左侧菜单栏的二级标签设计 面包屑 Django文件上传 后台管理系统CRM项目设计流程分析
- .net MVC下跨域Ajax请求(CORS)
二.CROS (Cross-origin Resource Sharing) CROS相当于一种协议,由浏览器.服务端共同完成安全验证,进行安全的跨域资源共享.对于开发人员来说就跟在本站AJAX请求一 ...
- 数据库-SQL语法:GROUP BY与HAVING
注意:select 后的字段,必须要么包含在group by中,要么包含在having 后的聚合函数里. 1. GROUP BY 是分组查询, 一般 GROUP BY 是和聚合函数配合使用. grou ...
- A*和IDA*介绍
\(A*\)算法是一种很神奇的搜索方法,它属于启发式搜索中的一种.A*最主要的功能当然就是用来剪枝,提高搜索的效率.A*主要的实现方法是通过一个估价函数,每次对下一步进行一个估价,根据估价出的值来决定 ...