Hive和Spark对分区字段的处理区别

报错:

spark任务在Insert时出错

User class threw exception:org.apache.spark.sql.AnalysisException:`ods_binlog`.`ods_binlog_doctorrecipe_avatar_recipedetails_di` requires thatthe data to be inserted have the same number of columns as the target table:target table has 3 column(s) but the inserted data has 2 column(s), including 0partition column(s) having constant value(s).

翻译:

用户类引发异常:org.apache.spark.sql。AnalysisException:`ods_binlog``ods_binlog_doctorrecipe_avatar_recipedetails_di`要求要插入的数据具有与目标表相同的列数:目标表有3列,但插入的数据有2列,包括0个具有常量值的分区列。

查文件:

发现暂停消费改代码后重新消费时,数据中没有dt列

查sql:

select * fromods_binlog.ods_binlog_doctorrecipe_avatar_recipedetails_di where ctime > '2022-10-2015';

发现这些数据在sql查询结果中是有dt列的

查出该数据所在文件:

select *, INPUT__FILE__NAME fromods_binlog.ods_binlog_doctorrecipe_avatar_recipedetails_di where dt ='2022-10-20'
andget_json_object(get_json_object(content,'$.data'),'$.id') = '8959181639' andget_json_object(get_json_object(content,'$.data'),'$.ver') = '5';

发现dt去过滤的时候也是生效的,但是文件里却一直没有dt字段,那是如何生效的就很奇怪,外表依赖映射文件,文件里没有的列外表为什么有,而且还是一个正常的值

尝试直接查询并插入hive表:

CREATE TABLE tmp.zy_binlogtest ( content STRING, ctime STRING ) PARTITIONED BY ( dt STRING ) STORED AS PARQUET;
insert OVERWRITE table tmp.zy_binlogtest partition (dt)
select * from ods_binlog.ods_binlog_doctorrecipe_avatar_recipedetails_di where dt = '2022-10-20'
and get_json_object(get_json_object(content,'$.data'),'$.id') = '8959181639' and get_json_object(get_json_object(content,'$.data'),'$.ver') = '5';

发现直接插入这条记录时并没有什么问题,hive插入读的是下面的sql语句,而hive的文件只要在当前分区目录内,尽管文件里没有该字段,但他查询时可以自己加上分区字段,

那为什么3点以前的文件明明有三列,再加上分区字段列,也就是四列,但是插入时也没问题呢?4列是如何插入3列里呢?

创建临时表模拟情景:

CREATE TABLE tmp.zhangyang ( name STRING , age INT) PARTITIONED BY ( dt STRING ) 
row format delimited fields terminated by '\t';
msck repair table tmp.zhangyang;
select * from tmp.zhangyang;

表中数据有两列另外有一个dt字段,映射的txt文件却直接有三列,且在dt=2022-10-21分区目录下,但查询结果却为三列,直接忽略了文件中为性别的列

所以说,hive和文件之间的映射,并不简单的只是映射文件,而是映射相应的列,和相应的分区目录,就算文件内有其他多个不相干的列,只要有表所需要的列,也不会出问题,也可以完成映射关系

扩展思考:

如果我们吧性别和年龄反过来了会怎样?会把性别读成年龄吗?还是会直接隔过去性别直接读后面的年龄?

答案是都不是,会按顺序读,如果类型不匹配直接补NULL,那如果后面还有性别列呢?会继续读到吗?

CREATE external TABLE tmp.zhangyang1 ( name STRING , age INT, sex STRING) PARTITIONED BY ( dt STRING ) 
row format delimited fields terminated by '\t' location 'hdfs://HDFSNS/Data/d1/hive/warehouse/tmp.db/zhangyang';
msck repair table tmp.zhangyang1;

答案是,他并不会吧第二列性别当性别,他是按照下标取,直接取第三列年龄作为性别,原来宁可将就也不回头找前任啊

查看报错对应的代码:

由此可知,spark任务在这里读的只是文件本身,他不关心你是在哪个分区目录下的,他也不会给你自动加上去,而目标表需要分区字段,无法拿到dt字段自然就给不了所以报错

所以说spark和Hive不一样,spark这里读文件,有几列我就挨着顺序读几列,分区也得给而且只能给到最后一列,不会读分区目录,也不会根据类型判断取谁不取谁和补NULL等操作

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spark SQL可以通过以下步骤解析查询Parquet格式的Hive表并获取分区字段和查询条件: 1. 首先,使用SparkSession对象创建一个DataFrame,该DataFrame将连接到Hive表并读取Parquet格式的数据。 2. 接下来,使用DataFrame的schema()方法获取表的模式,包括分区字段和非分区字段。 3. 使用DataFrame的filter()方法来应用查询条件,并使用where()方法来指定分区字段的值。 4. 最后,使用DataFrame的select()方法选择要返回的列,并使用show()方法显示结果。 示例代码如下: ``` from pyspark.sql import SparkSession # 创建SparkSession对象 spark = SparkSession.builder.appName("ParquetHiveTable").enableHiveSupport().getOrCreate() # 读取Hive表中的Parquet数据 df = spark.table("myhive.parquet_table") # 获取表的模式 schema = df.schema # 应用查询条件并指定分区字段的值 df_filtered = df.filter("column1 > 10").where("partition_column = '2022-01-01'") # 选择要返回的列并显示结果 df_filtered.select("column1", "column2").show() ``` 在上面的代码中,我们假设Parquet格式的Hive表名为“myhive.parquet_table”,其中包含一个名为“column1”的非分区字段和一个名为“partition_column”的分区字段。我们使用filter()方法应用查询条件“column1 > 10”,并使用where()方法指定分区字段的值为“2022-01-01”。最后,我们选择要返回的列“column1”和“column2”,并使用show()方法显示结果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值