spark插入动态分区代码报错

本文探讨了在使用Spark和Hive进行动态分区插入时出现的异常情况,并详细记录了解决这一问题的过程。作者首先遇到了因Hive版本不兼容而导致的错误,随后尝试通过调整依赖版本来解决问题,最终总结出了在不同环境下调试和部署的最佳实践。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

现象

SparkSession session = SparkSession.builder() 
.config(sparkConf) 
.config("hive.exec.dynamic.partition.mode", "nonstrict")//动态分区 
//.config("hive.metastore.dml.events","false")
.enableHiveSupport() .getOrCreate();

dataset1.write().mode(SaveMode.Overwrite).insertInto(Constant.RENT_TABLE);

dataset第一次插入分区没有问题,但是第二次重新跑的时候

[load-dynamic-partitions-0] ERROR hive.ql.metadata.Hive - Exception when loading partition with parameters  partPath=hdfs://s2cluster/user/hive/warehouse/odszjdata.db/ods_zj_building_area_check_list/.hive-staging_hive_2022-11-07_18-12-45_911_2372413257026787436-1/-ext-10000/period_id=202210,  table=ods_zj_building_area_check_list,  partSpec={period_id=202210},  replace=true,  listBucketingEnabled=false,  isAcid=false,  hasFollowingStatsTask=false
org.apache.hadoop.hive.ql.metadata.HiveException: org.apache.thrift.TApplicationException: Required field 'filesAdded' is unset! Struct:InsertEventRequestData(filesAdded:null)
    at org.apache.hadoop.hive.ql.metadata.Hive.fireInsertEvent(Hive.java:2437)
    at org.apache.hadoop.hive.ql.metadata.Hive.loadPartitionInternal(Hive.java:1632)
    at org.apache.hadoop.hive.ql.metadata.Hive.lambda$loadDynamicPartitions$4(Hive.java:1974)
    at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
    at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: org.apache.thrift.TApplicationException: Required field 'filesAdded' is unset! Struct:InsertEventRequestData(filesAdded:null)
    at org.apache.thrift.TApplicationException.read(TApplicationException.java:111)
    at org.apache.thrift.TServiceClient.receiveBase(TServiceClient.java:79)
    at org.apache.hadoop.hive.metastore.api.ThriftHiveMetastore$Client.recv_fire_listener_event(ThriftHiveMetastore.java:4836)
    at org.apache.hadoop.hive.metastore.api.ThriftHiveMetastore$Client.fire_listener_event(ThriftHiveMetastore.java:4823)
    at org.apache.hadoop.hive.metastore.HiveMetaStoreClient.fireListenerEvent(HiveMetaStoreClient.java:2531)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at org.apache.hadoop.hive.metastore.RetryingMetaStoreClient.invoke(RetryingMetaStoreClient.java:154)
    at com.sun.proxy.$Proxy29.fireListenerEvent(Unknown Source)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at org.apache.hadoop.hive.metastore.HiveMetaStoreClient$SynchronizedHandler.invoke(HiveMetaStoreClient.java:2562)
    at com.sun.proxy.$Proxy29.fireListenerEvent(Unknown Source)
    at org.apache.hadoop.hive.ql.metadata.Hive.fireInsertEvent(Hive.java:2435)
    ... 6 more
Exception in thread "main" org.apache.spark.sql.AnalysisException: org.apache.hadoop.hive.ql.metadata.HiveException: Exception when loading 1 in table ods_zj_building_area_check_list with loadPath=hdfs://s2cluster/user/hive/warehouse/odszjdata.db/ods_zj_building_area_check_list/.hive-staging_hive_2022-11-07_18-12-45_911_2372413257026787436-1/-ext-10000;
    at org.apache.spark.sql.hive.HiveExternalCatalog.withClient(HiveExternalCatalog.scala:108)
    at org.apache.spark.sql.hive.HiveExternalCatalog.loadDynamicPartitions(HiveExternalCatalog.scala:924)
    at org.apache.spark.sql.catalyst.catalog.ExternalCatalogWithListener.loadDynamicPartitions(ExternalCatalogWithListener.scala:189)
    at org.apache.spark.sql.hive.execution.InsertIntoHiveTable.processInsert(InsertIntoHiveTable.scala:205)
    at org.apache.spark.sql.hive.execution.InsertIntoHiveTable.run(InsertIntoHiveTable.scala:99)
    at org.apache.spark.sql.execution.command.DataWritingCommandExec.sideEffectResult$lzycompute(commands.scala:104)
    at org.apache.spark.sql.execution.command.DataWritingCommandExec.sideEffectResult(commands.scala:102)
    at org.apache.spark.sql.execution.command.DataWritingCommandExec.doExecute(commands.scala:122)
    at org.apache.spark.sql.execution.SparkPlan$$anonfun$execute$1.apply(SparkPlan.scala:131)
    at org.apache.spark.sql.execution.SparkPlan$$anonfun$execute$1.apply(SparkPlan.scala:127)
    at org.apache.spark.sql.execution.SparkPlan$$anonfun$executeQuery$1.apply(SparkPlan.scala:155)
    at org.apache.spark.rdd.RDDOperationScope$.withScope(RDDOperationScope.scala:151)
    at org.apache.spark.sql.execution.SparkPlan.executeQuery(SparkPlan.scala:152)
    at org.apache.spark.sql.execution.SparkPlan.execute(SparkPlan.scala:127)
    at org.apache.spark.sql.execution.QueryExecution.toRdd$lzycompute(QueryExecution.scala:80)
    at org.apache.spark.sql.execution.QueryExecution.toRdd(QueryExecution.scala:80)
    at org.apache.spark.sql.DataFrameWriter$$anonfun$runCommand$1.apply(DataFrameWriter.scala:668)
    at org.apache.spark.sql.DataFrameWriter$$anonfun$runCommand$1.apply(DataFrameWriter.scala:668)
    at org.apache.spark.sql.execution.SQLExecution$$anonfun$withNewExecutionId$1.apply(SQLExecution.scala:78)
    at org.apache.spark.sql.execution.SQLExecution$.withSQLConfPropagated(SQLExecution.scala:125)
    at org.apache.spark.sql.execution.SQLExecution$.withNewExecutionId(SQLExecution.scala:73)
    at org.apache.spark.sql.DataFrameWriter.runCommand(DataFrameWriter.scala:668)
    at org.apache.spark.sql.DataFrameWriter.insertInto(DataFrameWriter.scala:325)
    at org.apache.spark.sql.DataFrameWriter.insertInto(DataFrameWriter.scala:311)
    at com.tencent.s2.HouseRentSparkJob.main(HouseRentSparkJob.java:56)

但是我在服务器跑代码反复测试 都是可以重复插入分区的。。window实在是难搞

百度得到

.config("hive.metastore.dml.events","false") 就好了。。 windows确实好了。 

没时间分析原因。

参考文章

Supporthttps://knowledge.informatica.com/s/article/594919?language=en_US

__________________________________________________________________________

回家越想越不对劲,突然意识到可能是我windows的jar包版本太低导致的。

window还是以前的cdh版本

<spark.version>2.4.0-cdh6.3.2</spark.version>

<hadoop.version>3.0.0-cdh6.3.2</hadoop.version>

但是服务现在的cdp已经是

hadoop 3.1.1 hive3.1.1 spark2.4.7了,

那么我先调整pom的版本 hadoop为3.1.1 结果报错

Unrecognized Hadoop major version number: 3.1.1

这个错也很简单,我们根据报错,查到这个地方,发现是hive-exec1.2.1里ShimLoader里只判断了hadoop版本是1和2 如果是3就会直接报错。

因为我cdp版本是 3.1.1所以我pom引入3.1.1也合情合理吧 

现在的问题是什么?

pom里spark版本2.4.7中的hive-exec:1.2.1里只判断了hadoop1 和hadoop2的版本

但是我hadoop引入的版本是3.1.1

解决办法:

1 找个spark版本高的版本 可能它就有hive-exec2 hive-exec3(因为我服务器本身是hive3,所以往这方面想) 这样就可以支持hive3了。如下图所示 

2.改hadoop的低版本,因为我主要是用spark去开发hive的读写。

最终我选择了1。。结果发现走不通。还是说下过程吧。改了pom发现报错

        <dependency>
            <groupId>org.apache.spark</groupId>
            <artifactId>spark-hive_2.11</artifactId>
            <version>${spark.version}</version>
            <exclusions>
                <exclusion>
                    <groupId>org.spark-project.hive</groupId>
                    <artifactId>hive-exec</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.spark-project.hive</groupId>
                    <artifactId>hive-metastore</artifactId>
                </exclusion>
            </exclusions>
            <!--<scope>provided</scope>-->
        </dependency>
        <dependency>
            <groupId>org.apache.hive</groupId>
            <artifactId>hive-exec</artifactId>
            <version>3.1.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.hive</groupId>
            <artifactId>hive-metastore</artifactId>
            <version>3.1.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.hive</groupId>
            <artifactId>hive-jdbc</artifactId>
            <version>3.1.2</version>
        </dependency>

紧接着又遇到这个错,Exception in thread "main" java.lang.NoSuchFieldError: HIVE_STATS_JDBC_TIMEOUT
    at org.apache.spark.sql.hive.HiveUtils$.formatTimeVarsForHiveClient(HiveUtils.scala:204)

遇到这个错其实很简单。我们打开HiveUtils类查看formatTimeVarsForHiveClient这个方法

看到这里没 就 HIVE_STATS_JDBC_TIMEOUT 这个枚举和下面的枚举是黑的,代表ConfVars里面没有这个枚举,ConfVars是哪里的?

点进去 发现是hive-exec的jar.找了一圈 确实没这个枚举,那现在是什么问题呢?

spark-hive_2.1.1:2.4.1有这个 HIVE_STATS_JDBC_TIMEOUT枚举 

hive_3.1.1没有这个枚举

解决办法1 从spark入手找个spark版本没这个枚举的。

2.找个hive版本有这个枚举的。

先从2入手 进入github里找到这个。确实只有1.2的hive-exec版本里有 2.0 3.0都没有 

 

现在的问题是啥 spark2.4.7的hiveUtils里要HIVE_STATS_JDBC_TIMEOUT

hive-exec的1.2有这个,但是hive-exec1.2只支持hadoop1 hadoop2

此时我们好像陷入了循环?那么我们直接用spark2.4.7+hive-exec1.2.1+hadoop2.x是不是就可以了?答案是可以的,但是别忘了我们最开始的目的?

大数据线上问题排查系列 - HIVE 踩坑记- hive.metastore.dml.events - 知乎 

我们反复插入hive分区表会报错,原因在于hive1.2.1这个jar呀,此时我希望的是本地使用hive3的jar。 所以我应该使用更高版本的spark?原因还在于spark的hiveUtils。

经过我看源码发现spark3已经没有这个参数了

 但是spark2.4还是有这个参数。

 所以感觉这个思路可行 

spark3+hive3+hadoop3 一切是那么美好。结果 我真是他妈的吐了。 

 

这里的mvn显示有3.1.2的jar,我点进去发现最多只有2.4.8......真是日了狗哟。。。。 仔细看才发现是scala2.12才有3.1.2......

最后也下了spark_hive_2.12_3.1.2的jar 结果运行就报错。。。放弃了。

通过这次醒悟到两个道理。

1.windows也就是本地调试bug太多,jar包各种依赖太深,随便改就会报错。

 2.尽量还是打成jar到服务器去跑吧。。。。

<think>好的,我需要帮助用户了解如何通过Presto向Hive插入分区数据。首先,我得回顾一下用户提供的引用资料,特别是引用[4],里面提到Presto不支持Hive的INSERT OVERWRITE和直接指定分区的写法。这意味着用户不能像在Hive中那样直接在Presto里用类似的语法。 接下来,我需要找出Presto支持的替代方法。根据引用[4]中的错误信息,Presto需要符合ANSI SQL标准的语法,可能只能使用INSERT INTO而不是INSERT OVERWRITE。此外,动态分区的处理方式也可能不同,可能需要依赖Hive的表结构来自动处理分区。 然后,用户提供的引用[2]提到Hive动态分区是通过INSERT INTO加载的,并且查询字段需要与分区字段对应。这可能意味着在Presto中插入数据时,需要确保数据中的分区字段值正确,这样Hive才能自动创建分区。因此,在Presto中可能需要将分区字段作为普通列包含在插入的数据中,这样当数据写入Hive表时,Hive会自动根据这些列的值创建或更新分区。 另外,引用[3]提到Hive和Presto查询结果不一致的问题,这可能涉及到数据同步或元数据更新的延迟。因此,在插入数据后,可能需要手动刷新Hive的元数据,或者在Presto中执行相应的操作以确保数据可见。 现在,我需要将这些信息整合成一个步骤指南。首先,确认表结构是否包含分区字段,然后使用INSERT INTO将包含分区字段的数据插入,让Hive自动处理分区。同时,注意Presto不支持覆盖写入,所以需要先删除旧数据或使用其他方法。最后,可能需要处理元数据同步的问题,确保查询时能看到新插入的数据。 可能还需要考虑示例代码的正确性,例如正确的INSERT INTO语句,以及如何组织数据中的分区列。此外,用户可能需要了解如何验证分区是否成功创建,比如通过Hive的SHOW PARTITIONS命令,或者在Presto中检查数据。 最后,总结步骤,强调Presto的限制和解决方法,确保用户理解动态分区的处理方式以及后续的数据验证步骤。同时,相关问题部分可以引导用户进一步探索动态分区的原理、数据一致性问题以及替代工具的使用。</think>以下是关于如何使用Presto向Hive插入分区数据的详细说明: --- ### 一、Presto插入Hive分区数据的限制与原理 1. **Presto语法限制** Presto遵循ANSI SQL标准,不支持Hive原生的`INSERT OVERWRITE`语法和直接指定分区的操作(如`PARTITION (dt='2023')`)。尝试使用这类语法会报错"missing 'INTO'"或"extraneous input 'partition'"[^4]。 2. **动态分区实现原理** Hive动态分区通过数据中的分区字段值自动创建分区目录。在Presto中,需要将分区字段作为普通列包含在插入数据中,Hive Metastore会根据这些列值自动生成分区结构[^2]。 --- ### 二、具体操作步骤 #### 步骤1:创建带分区的Hive表 ```sql -- Hive中执行 CREATE TABLE user_behavior ( user_id STRING, action STRING ) PARTITIONED BY (dt STRING); ``` #### 步骤2:通过Presto插入数据 ```sql -- Presto中执行 INSERT INTO hive.default.user_behavior SELECT user_id, action, '2023-10-01' AS dt -- 将分区字段作为普通列 FROM source_table; ``` - **关键点**:`dt`字段必须包含在SELECT语句中,且与表定义的分区字段名称一致 - **效果**:Hive会自动在HDFS上创建路径`/user/hive/warehouse/user_behavior/dt=2023-10-01/` #### 步骤3:验证分区数据 ```sql -- Hive中验证 SHOW PARTITIONS user_behavior; -- 应显示dt=2023-10-01 -- Presto中查询 SELECT * FROM hive.default.user_behavior WHERE dt = '2023-10-01'; ``` --- ### 三、注意事项 1. **数据覆盖问题** Presto不支持`INSERT OVERWRITE`,如需覆盖数据,需先通过Hive删除旧分区: ```sql -- Hive中执行 ALTER TABLE user_behavior DROP IF EXISTS PARTITION (dt='2023-10-01'); ``` 2. **元数据同步** 插入数据后,Hive可能需要`MSCK REPAIR TABLE user_behavior`刷新元数据,但Presto通过Hive Connector会自动检测新分区[^3]。 3. **性能优化** 批量插入时建议按分区字段排序,可以减少HDFS小文件生成。 --- ### 四、替代方案对比 | 方法 | 优点 | 缺点 | |-----------|---------------------|---------------------| | Presto写入 | 实时性高,适合小批量数据 | 无覆盖写入能力,依赖Hive元数据 | | Hive写入 | 支持复杂操作(动态/静态分区) | 时效性较低 | | Spark写入 | 适合大规模数据,支持覆盖操作 | 需要Spark环境 | ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值