Hive insert 字段表错位踩坑

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Hive insert 字段表错位踩坑相关的知识,希望对你有一定的参考价值。

参考技术A 往 Hive 表 insert 数据后,查询时出现个别行字段错位,插入语句如下:

首先测试源表数据查询:

查询来的数据没发现有什么异常;照理说逐字段查出来没问题,再逐字段插入应该不会错位。实际上 hive 的 insert 跟想象中传统的 insert 不太一样。

由于不是全表错位,而是个别行错位,首先根据关键字查询 hive 错位那行数据,导出文本到本地。肉眼查看发现有部分"乱码"(异常字符: ^M ,如果经验丰富一眼就能看出这个是 \001 ,vim 下可以通过组合键 ctrl + a 输出),怀疑是异常字符导致,通过 linux od 命令查看 16 进制编码,如图所示:有好几个 \001 ,多么眼熟的数字啊 - 这是 hive 默认字段分隔符。

一般 insert A from select B 我们没有关注 A 表的字段分隔符,看到 \001 直觉跟 A 表的字段分隔符有关:
查看 A 的表结构,字段分隔符默认的 \001 。存储类型: textfile 。

进一步分析:textfile 是 hive 默认的存储结构,行存储,存储的实际数据结构跟表逻辑结构一致。导入数据时会直接把数据文件拷贝到 hdfs上不进行处理。源文件可以直接通过hadoop fs -cat 查看; 例如 text 字段分隔符: \001 , 换行符: \n,表在 hdfs 实际存储的格式为:
v1\001v2\001v3\n
v4\001v5\001v5

猜测字段值缺失错位的根源在于:文本中的不可见字符 \001 插入到表中,而表以 \001 作为字段分隔符,导致查询字段错位。

再来看这条 SQL:

我们可以还原这条 SQL 从插入到查询异常的全流程:

第一种方式可行且更加合理;
第二种方式可行,一种补救方案,但是 orc 等格式不支持 load 操作
第三种方式临时解决问题,不能根本上解决问题;

对 hive 的基础知识了解不足,导致问题出现排查速度较慢。
数据源头进行必要的数据 ETL 清洗,对字段分隔符的处理必须谨慎。
Hive 表尽可能使用 orc parquet 这类存储方式,空间占用,查询效率相对 textfile 有大幅提升,同时可以规避字段分隔符,错位等问题。
更深入一步 了解 hive orc 这类存储方式实现原理。

使用 INSERT OVERWRITE DIRECTORY 从 HIVE 表插入 HDFS 失败

【中文标题】使用 INSERT OVERWRITE DIRECTORY 从 HIVE 表插入 HDFS 失败【英文标题】:Failed to insert into HDFS from HIVE table using INSERT OVERWRITE DIRECTORY 【发布时间】:2014-07-15 05:02:19 【问题描述】:

我的主要需求是使用 INSERT OVERWRITE uery 从 HIVE 加载 HDFS 中的文件。在此查询中,我尝试加入 3 个配置单元表。以下是查询:

select * FROM 
    AGG_CUSTOMER_EXPSR_DRV_HIVE DRV 
LEFT OUTER JOIN 
    AGG_CUSTOMER_EXPSR_SRC_HIVE SRC 
ON 
    (SRC.CUSTOMER_ID = DRV.CUSTOMER_ID) 
    AND (SRC.AGGREGATION_LEVEL_CD = DRV.AGGREGATION_LEVEL_CD) 
    AND (SRC.PRODUCT_GROUP_CD = DRV.PRODUCT_GROUP_CD) AND (SRC.SRC_SYS_CD = DRV.SRC_SYS_CD) 
LEFT OUTER JOIN 
    ALTERNATE_IP_HIVE AIP1 
ON 
    (DRV.DERIVED_CUSTOMER_ID = AIP1.IP_ID) AND (AIP1.IP_TYPE_CD IN (1, 4)) 
LEFT OUTER JOIN 
    ALTERNATE_IP_HIVE AIP3 
ON 
    (SRC.FINANCIAL_RPTNG_UNIT_ID = AIP3.IP_ID) AND (AIP3.IP_TYPE_CD = 3) 
WHERE EXCLUDE_IND ='N';

但我收到如下错误: -sh: syntax error near unexpected token(`

有人可以帮我找出问题吗?

注意:我已经删除了 SELECT 子句中的字段。

【问题讨论】:

【参考方案1】:

如果您在 hive 中创建了一个包含上述 sql 的结果字段数量的表,那么您可以简单地做

INSERT OVERWRITE TABLE <database_name.your_created_table_name> SELECT * FROM 
    AGG_CUSTOMER_EXPSR_DRV_HIVE DRV 
LEFT OUTER JOIN 
    AGG_CUSTOMER_EXPSR_SRC_HIVE SRC 
ON 
    (SRC.CUSTOMER_ID = DRV.CUSTOMER_ID) 
    AND (SRC.AGGREGATION_LEVEL_CD = DRV.AGGREGATION_LEVEL_CD) 
    AND (SRC.PRODUCT_GROUP_CD = DRV.PRODUCT_GROUP_CD) AND (SRC.SRC_SYS_CD = DRV.SRC_SYS_CD) 
LEFT OUTER JOIN 
    ALTERNATE_IP_HIVE AIP1 
ON 
    (DRV.DERIVED_CUSTOMER_ID = AIP1.IP_ID) AND (AIP1.IP_TYPE_CD IN (1, 4)) 
LEFT OUTER JOIN 
    ALTERNATE_IP_HIVE AIP3 
ON 
    (SRC.FINANCIAL_RPTNG_UNIT_ID = AIP3.IP_ID) AND (AIP3.IP_TYPE_CD = 3) 
WHERE EXCLUDE_IND ='N';

来自 SELECT 是您的查询。您可以查看this URL 以获取有关 hiveql 的更多帮助

【讨论】:

对不起..我的错..我尝试在 HIVE 命令提示符中运行 INSERT OVERWRITE 查询,现在它工作正常。但是下面的 CASE 语句导致了一个问题: CASE WHEN (DRV.AGGREGATION_LEVEL_CD = 1) THEN CASE WHEN (SUBSTR(AIP1.SRC_SYS_UNIQUE_KEY_TXT, 1, (INSTR(AIP1.SRC_SYS_UNIQUE_KEY_TXT, '~', 1, 1) - 1)) NOTNULL) THEN SUBSTR(AIP1.SRC_SYS_UNIQUE_KEY_TXT, 1, (INSTR(AIP1.SRC_SYS_UNIQUE_KEY_TXT, '~', 1, 1) - 1)) 失败:SemanticException [错误 10015]:第 1:1125 行参数长度不匹配 '1':函数 INSTR正好接受 2 个参数。 WHEN ('') THEN '' ELSE NULL END ELSE '' END AS OVERRIDE_FAMILY_CUSTOMER_SRC_SYS_CD, 您能否分享您的完整查询并说明您遇到的问题 实际上我的问题是,通过 INSERT OVERWRITE DIRECTORY 将表从 HIVE 导入 HDFS 时,我无法使用 JOIN。我在上面的 INSERT 中使用的查询有 INSTR、SUBSTR、NOT NULL,问题出在 INSTR 语法上。我不知道 SQL 和 HIVE-QL 之间的 INSTR 语法差异。现在它工作正常。 很高兴你让它工作了。如果可能的话,只需编辑您的问题并将您的解决方案与 cmets 一起使用,以防万一有人查看此帖子,它会对他们有所帮助。

以上是关于Hive insert 字段表错位踩坑的主要内容,如果未能解决你的问题,请参考以下文章

hive修改分区字段值

Spark SQL写入Hive,同分区overwrite,不同分区insert

navicat导出insert语句能限制字段嘛

hive表按多个字段分桶怎么理解

Hive 修改表字段类型

hive表新增字段后,新字段无法写入的问题 -- cascade