Spark写入Parquet触发java.io.IOException,如何无错写入Hive表?
问题描述
执行Spark写入Parquet格式Hive表时抛出如下异常:
java.io.IOException: Null or empty fields is found at org.apache.parquet.crypto.CryptoMetadataRetriever.getFileEncryptionProperties(CryptoMetadataRetriever.java:114) at org.apache.parquet.crypto.CryptoClassLoader.getFileEncryptionPropertiesOrNull(CryptoClassLoader.java:74) at org.apache.parquet.hadoop.ParquetOutputFormat.getRecordWriter(ParquetOutputFormat.java:405) at org.apache.parquet.hadoop.ParquetOutputFormat.getRecordWriter(ParquetOutputFormat.java:362) at org.apache.spark.sql.execution.datasources.parquet.ParquetOutputWriter.<init>(ParquetOutputWriter.scala:37) at org.apache.spark.sql.execution.datasources.parquet.ParquetFileFormat$$anon$1.newInstance(ParquetFileFormat.scala:163) at org.apache.spark.sql.execution.datasources.SingleDirectoryDataWriter.newOutputWriter(FileFormatDataWriter.scala:120) at org.apache.spark.sql.execution.datasources.SingleDirectoryDataWriter.<init>(FileFormatDataWriter.scala:108) at org.apache.spark.sql.execution.datasources.FileFormatWriter$.org$apache$spark$sql$execution$datasources$FileFormatWriter$$executeTask(FileFormatWriter.scala:253) at org.apache.spark.sql.execution.datasources.FileFormatWriter$$anonfun$write$1.apply(FileFormatWriter.scala:170) at org.apache.spark.sql.execution.datasources.FileFormatWriter$$anonfun$write$1.apply(FileFormatWriter.scala:169) at org.apache.spark.scheduler.ResultTask.runTask(ResultTask.scala:90) at org.apache.spark.scheduler.Task.run(Task.scala:121) at org.apache.spark.executor.Executor$TaskRunner$$anonfun$11.apply(Executor.scala:440) at org.apache.spark.util.Utils$.tryWithSafeFinally(Utils.scala:1371) at org.apache.spark.executor.Executor$TaskRunner.run(Executor.scala:446) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:748)
触发错误的代码如下:
DataFrameWriter<Row> dfw = sparkSession.createDataFrame(javaSparkContext.parallelize(uuids), MyCustomDataClass.class).write();
其中uuids为ArrayList<MyCustomDataClass>类型,需实现将数据以Parquet格式写入Hive表且不触发该错误。
解决方案
该错误核心是Parquet加密组件检测到空字段,而实际场景大概率未启用加密或加密配置缺失,可通过以下方式解决:
显式禁用Parquet加密
在Spark配置中添加参数强制关闭加密功能,避免加密组件的不必要检查:sparkSession.conf().set("spark.sql.parquet.enableEncryption", "false");或在Spark启动时通过
--conf参数设置:--conf spark.sql.parquet.enableEncryption=false修复自定义类字段定义
确保MyCustomDataClass的所有字段均有合法取值,无空值或未初始化情况。若字段允许为空,需标注Spark支持的注解(如@Nullable),让Spark正确识别字段可空性,避免Parquet处理时误判为空字段。直接写入Hive表
不要使用通用write()方法,而是指定写入Hive表,让Spark自动适配表的Parquet格式配置:sparkSession.createDataFrame(javaSparkContext.parallelize(uuids), MyCustomDataClass.class) .write() .mode(SaveMode.Append) // 根据需求选择覆盖/追加等模式 .saveAsTable("database_name.table_name");该方式会复用Hive表已有Parquet配置,规避手动配置带来的加密相关问题。
检查依赖版本兼容性
确保Spark、Parquet、Hive的依赖版本匹配。若使用带加密功能的Parquet版本但Spark版本未适配,可能触发此类异常。建议使用官方兼容的依赖组合,比如Spark 3.x搭配Parquet 1.12+版本。
内容的提问来源于stack exchange,提问作者Christopher Settles
相关产品推荐
相关产品推荐

