IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 大数据 -> [1022]Hive insert 字段表错位 -> 正文阅读

[大数据][1022]Hive insert 字段表错位

Hive insert 字段表错位踩坑

1 问题描述

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

insert overwrite table A select col1,col2,col3 from table B where dayid = '';

首先测试源表数据查询:

select col1,col2,col3 from B

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

2 排查过程

由于不是全表错位,而是个别行错位,首先根据关键字查询 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 作为字段分隔符,导致查询字段错位。

3 问题定位

再来看这条 SQL:

insert overwrite table A select col1,col2,col3 from table B where dayid = '';

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

  1. 查询:select col1,col2,col3 from table B where dayid = ''; 查询出的数据按照 A 表的字段分隔符以及定义的换行符拼接起来。
  2. 插入:由于 A 表是 textfile ,直接把查询的数据 insert (append)到 hdfs 上
  3. 查询:由于多余的字段符 \001 被插入到 A 表中,查询的时候必然错乱。

4 解决方案

  • 入库前清洗掉数据中的 \001
  • 修改 A 表的存储格式为 orc 等(不用关心字段分隔符)
  • 修改 A 表字段分隔符为其他不可见字符

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

推荐解决方法

insert overwrite table A select 
regexp_replace(trim(col1),'\t|\n|\001|\r','') as col1,
regexp_replace(trim(col2),'\t|\n|\001|\r','') as col2,
regexp_replace(trim(col3),'\t|\n|\001|\r','') as col3
from table B where dayid = '';

hive的insert语句列顺序问题以及新增字段遇到的坑

讲问题之前,先简单创建一个表:

CREATE TABLE IF NOT EXISTS `my.test_table`(
  `col1` int COMMENT "第一列",
  `col2` int COMMENT "第二列"
)
COMMENT "测试表"
PARTITIONED BY (`pt` int COMMENT "测试分区")
ROW FORMAT SERDE
  "org.apache.hadoop.hive.ql.io.orc.OrcSerde"
STORED AS INPUTFORMAT
  "org.apache.hadoop.hive.ql.io.orc.OrcInputFormat"
OUTPUTFORMAT
  "org.apache.hadoop.hive.ql.io.orc.OrcOutputFormat";

初始表有col1,col2两列,pt分区只是为了对比结果

insert语句列顺序

hive不像mysql、oracle这些数据库一样在insert的时候可以指定字段,必须在插入的时候插入的是全字段。所以我一直以为可以通过指定插入数据的别名来改变插入字段的顺序,好吧,事实证明我是错的!

我们来简单作一个设想,假如我们执行以下的sql会发生什么:

insert overwrite table my.test_table partition(pt=1) select 2 as col2, 1 as col1 from my.online_table;

按常规逻辑来说,查询的时候应该是col1字段都为1,col2字段都为2。但是事实上执行

select col1, col2 from my.test_table;

结果是:

2    1
2    1
2    1
2    1
....

事实上,hive并不关心你执行insert语句所用的别名,别名代表的字段可以不存在,甚至比别名都可以相同。下面的语句执行也是一样的效果:

insert overwrite table my.test_table partition(pt=1) select 2 as invalid_col, 1 as invalid_col from my.online_table;

是不是觉得很惊喜。所以,请严格保证insert语句中的字段和建表语句中的字段的顺序一致!!!

对新增字段插入数据再查询发现是NULL

**hive比较特殊的地方,在于它的表结构和数据其实是分开的。**这个会导致,对hive分区表新增字段后,在执行插入分区的动作,会发现其实数据文件中已经有新字段值了,但是在查询的时候新字段的值还是显示为null。

例如我执行了下面的方法新增了一列col3:

alter table my.test_table add columns(col3 int comment '第三列')

然后想插入一些数据:

insert overwrite table my.test_table partition(pt=1) select 1 as col1, 2 as col2, 3 as col3 from my.online_table; 

结果查询col1,col2,col3发现结果其实是:

1    2    NULL
1    2    NULL
...1

这是因为你对表结构进行了改变,但是历史分区的数据却没有做改变(新增分区不会出现这个情况)。

为了解决上面的问题,可以采用两种方式:

  • 如果已经执行添加操作,并且没有带cascade,可以尝试下面的方法:
使用replace 恢复表结构,这样历史的分区数据都不会消失
alter table industry_db.product replace columns(product_name string comment ‘产品名’);
  • 在新增的时候加上cascade关键词
alter table my.test_table add columns(col3 int comment '第三列') cascade

官方文档描述如下:

The CASCADE|RESTRICT clause is available in Hive 1.1.0. ALTER TABLE ADD|REPLACE COLUMNS with CASCADE command changes the columns of a table’s metadata, and cascades the same change to all the partition metadata. RESTRICT is the default, limiting column changes only to table metadata.

如上所述,在1.1.0中表和分区的元数据就是分开处理的,对于在添加字段的时候没有指定的cascade的情况,在增加字段的时候添加CASCADE能同时更新表和分区

因为我们在重跑数据的时候,虽然HDFS上的数据更新了,但是我们查询的时候仍然查询的是旧的元数据信息(即Mysql中的信息)

注意:对于执行了add column语句之后新生成的分区,是不会有问题的,Hive会自动维护新分区中的元数据。

参考:https://www.cnblogs.com/fnlingnzb-learner/p/13472266.html
https://www.jianshu.com/p/568a43eb5114

  大数据 最新文章
实现Kafka至少消费一次
亚马逊云科技:还在苦于ETL?Zero ETL的时代
初探MapReduce
【SpringBoot框架篇】32.基于注解+redis实现
Elasticsearch:如何减少 Elasticsearch 集
Go redis操作
Redis面试题
专题五 Redis高并发场景
基于GBase8s和Calcite的多数据源查询
Redis——底层数据结构原理
上一篇文章      下一篇文章      查看所有文章
加:2021-07-11 16:42:24  更:2021-07-11 16:42:28 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/7 3:33:31-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码