无法找到数据源:镶木地板,使用sbt assembly

时间:2016-06-03 21:20:40

标签: apache-spark parquet sbt-assembly

我有以下代码:

val testRDD: RDD[(String, Vector)] = sc.parallelize(testArray)

val sqlContext = new org.apache.spark.sql.SQLContext(sc)
import sqlContext.implicits._

val df = testRDD.toDF()

df.write.parquet(path)

使用以下build.sbt:

libraryDependencies += "org.apache.spark" %% "spark-core" % "1.6.1"
libraryDependencies += "org.apache.spark" %% "spark-sql" % "1.6.1"
libraryDependencies += "org.apache.spark" %% "spark-mllib" % "1.6.1"

// META-INF discarding
mergeStrategy in assembly <<= (mergeStrategy in assembly) { (old) =>
{
  case "reference.conf" => MergeStrategy.concat
  case PathList("META-INF", xs @ _*) => MergeStrategy.discard
  case x => MergeStrategy.first
}
}

当我使用sbt-assembly构建它时(我有addSbtPlugin(&#34; com.eed3si9n&#34;%&#34; sbt-assembly&#34;%&#34; 0.12.0&#34;)) ,然后我运行它,我收到一个错误:

Exception in thread "main" java.lang.ClassNotFoundException: Failed to find data source: parquet. Please find packages at http://spark-packages.org
    at org.apache.spark.sql.execution.datasources.ResolvedDataSource$.lookupDataSource(ResolvedDataSource.scala:77)
    at org.apache.spark.sql.execution.datasources.ResolvedDataSource$.apply(ResolvedDataSource.scala:219)
    at org.apache.spark.sql.DataFrameWriter.save(DataFrameWriter.scala:148)
    at org.apache.spark.sql.DataFrameWriter.save(DataFrameWriter.scala:139)
    at org.apache.spark.sql.DataFrameWriter.parquet(DataFrameWriter.scala:334)
    at InductionService.Application$.main(ParquetTest.scala:65)

但是,如果我使用IntelliJ Idea构建它(正常构建,不像sbt程序集那样胖JAR),并在该IDE中调试它,它实际上是有效的。很明显,我使用sbt程序集构建它的方式有问题,但我不知道如何修复它。有什么想法吗?

我怀疑build.sbt中的merge-inf discard代码可能是原因,但我需要该代码,否则我无法使用sbt-assembly构建。 (它抱怨重复......)

2 个答案:

答案 0 :(得分:2)

我有sae问题。 META-INF中的 services 文件夹存在一些合并问题。 我可以通过在MergeStrategy上添加规则来解决这个问题:

case n if n.contains("services") => MergeStrategy.concat

这就是我所拥有的,现在它起作用了:

assemblyMergeStrategy in assembly := {
  case PathList("javax", "servlet", xs @ _*) => MergeStrategy.first
  case PathList(ps @ _*) if ps.last endsWith ".html" => MergeStrategy.first
  case n if n.contains("services") => MergeStrategy.concat
  case n if n.startsWith("reference.conf") => MergeStrategy.concat
  case n if n.endsWith(".conf") => MergeStrategy.concat
  case meta(_) => MergeStrategy.discard
  case x => MergeStrategy.first
}

答案 1 :(得分:0)

上面的解决方案并不理想,它是部分正确的,您确实需要合并 META-INF/service/.... 带并丢弃 META-INF 中的其他带,但上面的解决方案使用 case n if n.contains("service") 来实现,这太笼统了一个条件。 如果任何重复的文件,不仅在 META-INF 中包含非常常见的“服务”一词,该文件将被连接起来,包括类文件。 如果您的程序或其依赖项之一包含像 com/amazonaws/services/s3/model/AmazonS3Exception 这样的类,就像我的一样,它会将它们连接起来,导致:

java.lang.ClassFormatError: Extra bytes at the end of class file com/amazonaws/services/s3/model/AmazonS3Exception

最好尽可能地限制 concat 子句,给出一个子句“concat META-INF/services,丢弃任何其他 META-INF”,这是一种方法:

assemblyMergeStrategy in assembly := {
  case PathList("META-INF", "services",  _*)  => MergeStrategy.concat
  case PathList("META-INF", _*) => MergeStrategy.discard
  case _ => MergeStrategy.first

}