Spark2.1.0使用saveAsTable保存DataFrame到Hive SerDe表报错的解决方法
解决Spark saveAsTable()写入Hive SerDe表触发AnalysisException的问题
先帮你梳理下问题场景:
我尝试使用
saveAsTable()方法将DataFrame保存至Hive表,计划以TextInputFormat格式存储数据,但触发了如下异常:Exception in thread "main" org.apache.spark.sql.AnalysisException: Saving data in the Hive serde table `cdx_network`.`inv_devices_incr` is not supported yet. Please use the insertInto() API as an alternative..;执行代码:
reducedFN.write().mode(SaveMode.Append).saveAsTable("cdx_network.alert_pas_incr");我已尝试
insertInto()方法,但……
这个问题我之前做Spark+Hive开发时也碰到过,本质是Spark的saveAsTable()对Hive原生SerDe表(比如用TextInputFormat存储的表)有兼容性限制——Spark默认更适配Parquet这类列式存储格式,对Hive传统的行式SerDe表,目前还不支持直接用saveAsTable()写入,所以才会抛出这个异常。
针对你的情况,给你几个可行的解决方向:
1. 修正insertInto()的使用方式(大概率能解决你的问题)
你说已经尝试了insertInto()但没成功,大概率是忽略了几个关键细节:
- Schema必须完全匹配:Hive的
insertInto()对Schema的要求非常严格,DataFrame的字段名称、数据类型、顺序必须和目标Hive表完全一致。比如Hive表字段顺序是id, name, dt,你的DataFrame也得按这个顺序输出,不能乱序。 - 分区表要注意动态/静态分区配置:如果目标表是分区表,要是用动态分区,得先开启动态分区参数:
同时DataFrame里必须包含分区字段,且值要符合分区规则。spark.sql("SET hive.exec.dynamic.partition=true"); spark.sql("SET hive.exec.dynamic.partition.mode=nonstrict"); - 写入模式的坑:
insertInto()默认就是Append模式,如果你想覆盖数据,得先手动清空表(比如spark.sql("TRUNCATE TABLE cdx_network.alert_pas_incr")),再执行写入。
给你一个完整的Java示例:
// 先调整DataFrame的Schema,确保和Hive表字段顺序、类型完全匹配 Dataset<Row> adjustedDF = reducedFN.select("id", "device_name", "dt"); // 开启动态分区(如果是分区表的话) spark.sql("SET hive.exec.dynamic.partition=true"); spark.sql("SET hive.exec.dynamic.partition.mode=nonstrict"); // 执行插入 adjustedDF.write().mode(SaveMode.Append).insertInto("cdx_network.alert_pas_incr");
2. 用LOAD DATA的方式间接写入
如果你不想用insertInto(),可以先把DataFrame写入HDFS临时目录,再通过Hive的LOAD DATA命令加载到目标表:
// 将DataFrame以Text格式写入HDFS临时目录,指定分隔符和Hive表一致(比如\t) reducedFN.write() .mode(SaveMode.Overwrite) .format("text") .option("sep", "\t") .save("/tmp/temp_alert_pas_data"); // 通过Spark SQL执行Hive加载命令,把临时目录的数据导入表中 spark.sql("LOAD DATA INPATH '/tmp/temp_alert_pas_data' INTO TABLE cdx_network.alert_pas_incr");
这种方式要注意:DataFrame的输出格式必须和Hive表的TextInputFormat兼容,比如字段分隔符、换行符要匹配,不然加载后数据会乱掉。
3. 确认Hive表的定义是否正确
最后再检查下你的Hive表创建语句,确保是Hive原生SerDe的Text表,比如:
CREATE TABLE cdx_network.alert_pas_incr ( id string, device_name string ) PARTITIONED BY (dt string) ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t' STORED AS TEXTFILE;
如果表的存储格式不是TextFile,或者SerDe用了其他自定义类,也可能导致写入异常。
内容的提问来源于stack exchange,提问作者wandermonk
相关产品推荐
相关产品推荐

