我有以下代码:
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构建。 (它抱怨重复......)
答案 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
}