##问题背景 一般我们创建 Hive 表时都需要给表和字段加上注释以便理解表的用途与字段的含义。但是往往在创建 Hive 表后查看表结构发现中文注释乱码,比较头疼。本文总结了一下针对这种情况的解决方案。

##问题重现 ###创建带中文注释的Hive表employees 使用 CREATE TABLE 语法创建一个带有中文注释的 Hive 表 employees:

CREATE TABLE IF NOT EXISTS employees (
name STRING COMMENT '姓名',
salary FLOAT COMMENT '薪水',
subordinates ARRAY COMMENT '下属',
deductions MAP COMMENT '扣除金额',
address STRUCT COMMENT '住址'
) COMMENT '员工表'
ROW FORMAT DELIMITED
FIELDS TERMINATED BY '\001'
COLLECTION ITEMS TERMINATED BY '\002'
MAP KEYS TERMINATED BY '\003'
LINES TERMINATED BY '\n'
STORED AS TEXTFILE;
desc employees

使用 desc employees 语句查看表结构,发现字段注释全是乱码:

hive 字段 注释 hive给字段添加注释_hive 字段 注释

desc formatted employees

使用 desc formatted employees 语句查看表结构,发现表和字段注释全是乱码:

hive 字段 注释 hive给字段添加注释_apache_02

show create table employees

最后使用 show create table employees 语句查看 employees 建表信息,也发现表和字段注释全是乱码:

hive 字段 注释 hive给字段添加注释_hive 字段 注释_03

##问题解决方案 ###修改Hive元数据库编码 当使用 MySQL 作为 Hive 元数据库的时候, Hive 元数据库的字符集要设置成 latin1 default。

使用 show create database hive 语句查看 hive 数据库默认编码。

hive 字段 注释 hive给字段添加注释_hive 字段 注释_04

使用 alter database hive default character set latin1 将 hive 数据库默认编码改成 latin1。

hive 字段 注释 hive给字段添加注释_java_05

###修改相关表相关字段编码

以下语句是为了支持 Hive 建表时插入中文注释

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_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;

###验证结果 重新创建 employees 表。

使用 desc employees 语句查看表结构,发现字段注释可以正常显示中文。

使用 desc formatted employees 语句查看表结构, 发现字段注释可以正常显示中文,但是表注释显示的虽然不是乱码,但却是 Unicode 编码。

hive 字段 注释 hive给字段添加注释_comment hive_06

使用 show create table employees 语句查看建表信息,发现表和字段注释仍然都是乱码。

hive 字段 注释 hive给字段添加注释_comment hive_07

###打Patch Hive 表注释中文乱码是 Hive 的一个 bug, 详情参见 注释不能支持Unicode字符 。在 2.1.1 版本中还未解决这个bug, 所以需要自己手动打patch。链接中已经提供了patch文件:

hive 字段 注释 hive给字段添加注释_apache_08

方便做个记录,现将 HIVE-11837.1.patch 内容粘贴出来:

diff --git a/ql/src/java/org/apache/hadoop/hive/ql/exec/DDLTask.java b/ql/src/java/org/apache/hadoop/hive/ql/exec/DDLTask.java

index 6fca9f7ec86574a6053af3672c551c6a63aa4870..661367f27b69f9796140808eda53a3bbcdcbdb11 100644

--- a/ql/src/java/org/apache/hadoop/hive/ql/exec/DDLTask.java

+++ b/ql/src/java/org/apache/hadoop/hive/ql/exec/DDLTask.java

@@ -2048,7 +2048,7 @@ private int showCreateTable(Hive db, DataOutputStream outStream, String tableNam
if (tbl.isView()) {
String createTab_stmt = "CREATE VIEW `" + tableName + "` AS " + tbl.getViewExpandedText();
- outStream.writeBytes(createTab_stmt.toString());
+ outStream.write(createTab_stmt.toString().getBytes("UTF-8"));
return 0;
}
@@ -2196,7 +2196,7 @@ else if (sortCol.getOrder() == BaseSemanticAnalyzer.HIVE_COLUMN_ORDER_DESC) {
}
createTab_stmt.add(TBL_PROPERTIES, tbl_properties);
- outStream.writeBytes(createTab_stmt.render());
+ outStream.write(createTab_stmt.render().getBytes("UTF-8"));
} catch (IOException e) {
LOG.info("show create table: " + stringifyException(e));
return 1;

前面的 + 号表示需要新加的代码,- 号表示需要删除的代码。

接下来下载 Hive 2.1.1 源码包 apache-hive-2.1.1-src.tar.gz,然后解压。修改 DDLTask.java 源码,接着使用以下Maven命令进行编译打包。

mvn clean package -DskipTests=true

最后,将新生成的 hive-exec-2.1.1.jar 文件替换掉 $HIVE_HOME/lib 目录下的 hive-exec-2.1.1.jar 文件。

验证结果

重启 Hive 客户端 ,然后重新创建 employees 表。

使用 desc employees 语句查看表结构,发现字段注释可以正常显示中文。

使用 desc formatted employees 语句查看表结构, 发现字段注释可以正常显示中文,但是表注释显示的虽然不是乱码,但却是 Unicode 编码。

hive 字段 注释 hive给字段添加注释_apache_09

使用 show create table employees 语句查看建表信息, 发现表和字段注释都可以正常显示中文。

hive 字段 注释 hive给字段添加注释_comment hive_10

###解决desc formatted中文变成 Unicode 编码 还是需要打patch, 具体参见 https://issues.apache.org/jira/browse/HIVE-5682。链接中已经提供了patch文件:

hive 字段 注释 hive给字段添加注释_apache_11

方便做个记录,现将 HIVE-5682.patch 内容粘贴出来:

### Eclipse Workspace Patch 1.0
#P hive-0.12.0-jd-svn
Index: ql/src/java/org/apache/hadoop/hive/ql/metadata/formatting/MetaDataFormatUtils.java
===================================================================
--- ql/src/java/org/apache/hadoop/hive/ql/metadata/formatting/MetaDataFormatUtils.java(revision 29)
+++ ql/src/java/org/apache/hadoop/hive/ql/metadata/formatting/MetaDataFormatUtils.java(working copy)
@@ -28,6 +28,8 @@
import java.util.Set;
import org.apache.commons.lang.StringEscapeUtils;+import org.apache.commons.logging.Log;+import org.apache.commons.logging.LogFactory;import org.apache.hadoop.hive.conf.HiveConf;
import org.apache.hadoop.hive.metastore.TableType;
import org.apache.hadoop.hive.metastore.api.FieldSchema;
@@ -47,7 +49,7 @@
*
*/
public final class MetaDataFormatUtils {
-
+ private static final Log LOG = LogFactory.getLog("org.apache.hadoop.hive.ql.metadata.formatting.MetaDataFormatUtils");
public static final String FIELD_DELIM = "\t";
public static final String LINE_DELIM = "\n";
@@ -262,10 +264,20 @@
private static void displayAllParameters(Map params, StringBuilder tableInfo) {
List keys = new ArrayList(params.keySet());
+ String value = null;
Collections.sort(keys);
for (String key : keys) {
tableInfo.append(FIELD_DELIM); // Ensures all params are indented.
- formatOutput(key, StringEscapeUtils.escapeJava(params.get(key)), tableInfo);
+ value = params.get(key);
+ LOG.info(">>lvxin displayAllParameters:key="+key+";params.get(key)="+params.get(key));+ if("comment".equals(key)&& null!=value && value.getBytes().length!=key.length())+ {
+ formatOutput(key, value, tableInfo);
+ }
+ else
+ {
+ formatOutput(key, StringEscapeUtils.escapeJava(value), tableInfo);
+ }
}
}

前面的 + 号表示需要新加的代码,- 号表示需要删除的代码。

同样的修改 MetaDataFormatUtils 源码,接着使用以下Maven命令进行编译打包。

mvn clean package -DskipTests=true

最后,将新生成的 hive-exec-2.1.1.jar 文件替换掉 $HIVE_HOME/lib 目录下的 hive-exec-2.1.1.jar 文件。

###验证结果 重启 Hive 客户端。

使用 desc formatted employees 查看表结构,发现表和字段注释都可以正常显示中文。

hive 字段 注释 hive给字段添加注释_hive 字段 注释_12

]