Hive 2.1.1字段和表注释中文乱码

时间:2021-02-19 07:58:27

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


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

CREATE TABLE IF NOT EXISTS employees (
    name STRING COMMENT '姓名',
    salary FLOAT COMMENT '薪水',
    subordinates ARRAY<STRING> COMMENT '下属',
    deductions MAP<STRING, FLOAT> COMMENT '扣除金额',
    address STRUCT<street:STRING, city:STRING, state:STRING, zip:INT> 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 2.1.1字段和表注释中文乱码

desc formatted employees

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

Hive 2.1.1字段和表注释中文乱码

show create table employees

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

Hive 2.1.1字段和表注释中文乱码


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

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

Hive 2.1.1字段和表注释中文乱码

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

Hive 2.1.1字段和表注释中文乱码

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

以下语句是为了支持 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 2.1.1字段和表注释中文乱码

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

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

Hive 2.1.1字段和表注释中文乱码

方便做个记录,现将 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 2.1.1字段和表注释中文乱码

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

Hive 2.1.1字段和表注释中文乱码

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

Hive 2.1.1字段和表注释中文乱码

方便做个记录,现将 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<String, String> params, StringBuilder tableInfo) {
     List<String> keys = new ArrayList<String>(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 2.1.1字段和表注释中文乱码]