任何试图使用sbt-assmbly来创建uber-JAR以作为Spark工作提交的人都可能浪费了大量时间来解决依赖性问题。我一直在使用以下三种方法来完成它,我需要至少几个小时来创建一个有效的构建文件..幸运的是,我可以重用它,直到我必须添加更多依赖项或更改Spark版。我使用的方法是:
将依赖项添加到libraryDependencies时,我使用.exclude()或.excludeAll()调用来包装其条目。这是sbt-assembly readme
我在原始Ivy XML排除列表中添加了一个条目。例如,这对于排除Spark 1.2引入的其中一个Kafka Jars是必要的。我通过在build.sbt中添加以下内容来实现这一点:
ivyXML :=
<dependencies>
<!-- Excluding Original Akke to use the Akka that comes from org.spark-project.akka -->
<!-- I verified that I actually need that, even though I am excluding Spark above... AND MLLIB IS PROVIDED -->
<exclude org="com.typesafe.akka" />
<!-- Already part of commons-beanutils-core -->
<exclude org="commons-beanutils" name="commons-beanutils" />
</dependencies>
&#13;
assemblyExcludedJars in assembly :=
{
val cp = (fullClasspath in assembly).value
cp filter {j => {
j.data.getName.startsWith("spark-core") ||
j.data.getName.startsWith("javax.activation") ||
j.data.getName.startsWith("commons-collections") ||
j.data.getName.startsWith("hadoop")
}}
}
&#13;
今天我偶然发现了一种避免所有麻烦的不同方法。 This blog post建议在违规包中使用MergeStrategy.first或.last。这是代码:
mergeStrategy in assembly <<= (mergeStrategy in assembly) { (old) =>
{
case PathList("javax", "servlet", xs @ _*) => MergeStrategy.last
case PathList("org", "apache", xs @ _*) => MergeStrategy.last
case PathList("com", "esotericsoftware", xs @ _*) => MergeStrategy.last
case "about.html" => MergeStrategy.rename
case x => old(x)
}}
这很有效,但我不喜欢它可能会导致一组来自两个版本的类。例如,如果一个类存在于javax.servlet的1.0版本中,但它在javax.servlet的1.1版本中被删除了。此类不会导致冲突,将被复制。然而,实际上两个冲突的类通常来自相同的版本,但是在不同的组织下发布(例如eclipse-orbit)。因此,合并startegy可以很好地工作,而且代码和麻烦都少得多。事实上,我更倾向于冒险在运行时(当盲目地使用MergeStrategy.first或.last)时遇到问题的可能性很小。你怎么看?
使用MergeStrategy.last与SBT程序集
的缺点