spark saveastable,位于s3 bucket的根本原因nullpointerexception

5rgfhyps  于 2021-05-24  发布在  Spark
关注(0)|答案(1)|浏览(518)

我正在使用spark3.0.1,我的分区表存储在s3中。请在这里找到问题的描述。
创建表

Create table root_table_test_spark_3_0_1 (
    id string,
    name string
)
USING PARQUET
PARTITIONED BY (id)
LOCATION  's3a://MY_BUCKET_NAME/'

在第二次运行时导致nullpointerexception的代码

Seq(MinimalObject("id_1", "name_1"), MinimalObject("id_2", "name_2"))
      .toDS()
      .write
      .partitionBy("id")
      .mode(SaveMode.Append)
      .saveAsTable("root_table_test_spark_3_0_1")

当配置单元元存储为空时,一切正常,但问题发生在spark尝试执行此操作时 getCustomPartitionLocationsInsertIntoHadoopFsRelationCommand 阶段(在第二次运行时(例如)
实际上,它调用以下方法:from( org.apache.hadoop.fs.Path )

/**Adds a suffix to the final name in the path.*/
public Path suffix(String suffix) {
    return new Path(getParent(), getName()+suffix);
}

但是 getParent() 当我们在根目录下时,将返回null,从而导致nullpointerexception。我现在想的唯一选择是重写此方法,执行以下操作:

/**Adds a suffix to the final name in the path.*/
public Path suffix(String suffix) {
    return (isRoot()) ? new Path(uri.getScheme(), uri.getAuthority(), suffix) : new Path(getParent(), getName()+suffix);
}

有什么问题吗 LOCATION 一个spark配置单元的表是否在根级别?有解决办法吗?是否存在任何已知问题?
我的运行时不允许我重写path类并修复 suffix 方法,我无法从bucket的根目录中移动数据,因为它已经存在2年了。
出现这个问题是因为我正在从spark 2.1.0迁移到spark 3.0.1,而检查自定义分区的行为出现在spark 2.2.0中(https://github.com/apache/spark/pull/16460)
整个上下文有助于理解问题,但基本上你可以很容易地重现它

val path: Path = new Path("s3a://MY_BUCKET_NAME/")
println(path.suffix("/id=id"))

仅供参考。hadoop公共版本是2.7.4,请在这里找到完整的stacktrace

NullPointerException
at org.apache.hadoop.fs.Path.<init>(Path.java:104)
    at org.apache.hadoop.fs.Path.<init>(Path.java:93)
    at org.apache.hadoop.fs.Path.suffix(Path.java:361)
    at org.apache.spark.sql.execution.datasources.InsertIntoHadoopFsRelationCommand.$anonfun$getCustomPartitionLocations$1(InsertIntoHadoopFsRelationCommand.scala:262)
    at scala.collection.TraversableLike.$anonfun$flatMap$1(TraversableLike.scala:245)
    at scala.collection.mutable.ResizableArray.foreach(ResizableArray.scala:62)
    at scala.collection.mutable.ResizableArray.foreach$(ResizableArray.scala:55)
    at scala.collection.mutable.ArrayBuffer.foreach(ArrayBuffer.scala:49)
    at scala.collection.TraversableLike.flatMap(TraversableLike.scala:245)
    at scala.collection.TraversableLike.flatMap$(TraversableLike.scala:242)
    at scala.collection.AbstractTraversable.flatMap(Traversable.scala:108)
    at org.apache.spark.sql.execution.datasources.InsertIntoHadoopFsRelationCommand.getCustomPartitionLocations(InsertIntoHadoopFsRelationCommand.scala:260)
    at org.apache.spark.sql.execution.datasources.InsertIntoHadoopFsRelationCommand.run(InsertIntoHadoopFsRelationCommand.scala:107)
    at org.apache.spark.sql.execution.datasources.DataSource.writeAndRead(DataSource.scala:575)
    at org.apache.spark.sql.execution.command.CreateDataSourceTableAsSelectCommand.saveDataIntoTable(createDataSourceTables.scala:218)
    at org.apache.spark.sql.execution.command.CreateDataSourceTableAsSelectCommand.run(createDataSourceTables.scala:166)

谢谢

g6baxovj

g6baxovj1#

看起来像是Spark代码调用的情况 Path.suffix("something) 因为根路径没有父路径,所以会触发一个npe
长期修复
文件jira on issues.apache.org against hadoop;提供带有test for fix suffix()的修补程序,以便在根路径上调用时正确降级。最适合所有人
不要将根路径用作表的目标。
两个都做
选项#2应该避免关于如何创建/提交表等的其他意外情况…有些代码可能会失败,因为尝试删除路径的根(这里是s3a://some bucket)不会删除根,是吗?
换言之:根目录到处都有“奇怪”的语义;大多数情况下,您在本地fs上都不会注意到这一点,因为您从未尝试将/用作工作目的地,因此会惊讶地发现rm-rf/与rm-rf/subdir等不同。spark、hive等从未被编写为将/用作工作目的地,因此您会看到失败。

相关问题