【问题标题】:sbt assembly, including my jarsbt 程序集,包括我的 jar
【发布时间】:2018-09-24 06:58:41
【问题描述】:

我想为我的代码构建一个“胖”罐子。我主要了解如何执行此操作,但我所使用的所有示例都使用 jar 不是本地的想法,并且我不确定如何将我构建的 scala 代码使用的另一个 JAR 包含到我组装的 jar 中。就像我必须包含的这个 JAR 驻留在哪个文件夹中一样?

通常,当我使用 spark-shell 运行当前代码作为测试时,它看起来像这样:

spark-shell --jars magellan_2.11-1.0.6-SNAPSHOT.jar -i st_magellan_abby2.scala 

(jar文件与.scala文件在同一路径)

所以现在我想构建一个 build.sbt 文件,它执行相同的操作并包含该 SNAPSHOT.jar 文件?

name := "PSGApp"
version := "1.0"
scalaVersion := "2.11.8"

resolvers += "Spark Packages Repo" at "http://dl.bintray.com/spark-packages/maven"

//provided means don't included it is there.  already on cluster?

libraryDependencies ++= Seq(
    "org.apache.spark" %% "spark-core" % "2.2.0" % "provided",
    "org.apache.spark" %% "spark-sql" % "2.2.0" % "provided",
    "org.apache.spark" %% "spark-streaming" % "2.2.0" % "provided",
    //add magellan here somehow?

)

那么我应该将 jar 放在 SBT 项目文件夹结构中的什么位置,以便在我运行 sbt 程序集时获取它?是在主/资源文件夹中吗?参考手册说“要包含在主 jar 中的文件”在哪里?

我会在 libraryDependencies 中放什么,以便它知道添加特定的 jar 而不是上网获取它?

最后一件事,我还在我的测试代码中进行了一些导入,现在我将此代码放在一个附加了def main 的对象中。

我有这样的事情:

import sqlContext.implicits._ 就在上面的代码中,它将像这样使用:

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

import sqlContext.implicits._
import org.apache.spark.sql.functions.udf

val distance =udf {(a: Point, b: Point) => 
   a.withinCircle(b, .001f);  //current radius set to .0001
}

我不确定我是否可以将这些导入保留在 def main 中?还是我必须以某种方式将它们移到其他地方? (我猜还在学习 scala 和争论范围)。

【问题讨论】:

    标签: scala apache-spark sbt


    【解决方案1】:

    一种方法是在本地使用程序集插件 (https://github.com/sbt/sbt-assembly) 构建您的 fat jar,然后使用 publishLocal 将生成的 jar 存储到本地 ivy2 缓存中

    这将使它可以根据该项目中的 build.sbt 设置包含在您的其他项目中,例如:

    name := "My Project"
    organization := "org.me"
    version := "0.1-SNAPSHOT"
    

    将在本地提供为"org.me" %% "my-project" % "0.1-SNAPSHOT" SBT 将在尝试从外部 repo 下载之前搜索本地缓存。

    但是,这被认为是不好的做法,因为只有最终项目才应该是一个胖罐子。你永远不应该将一个作为依赖项(很多令人头疼)。

    如果库包含在 PGapp 中,则没有理由让 magellan 项目成为胖罐。只需 publishLocal 无需组装

    另一种方法是将项目作为代码而不是库相互依赖。

    lazy val projMagellan = RootProject("../magellan")
    lazy val projPSGApp = project.in(file(".")).dependsOn(projMagellan)
    

    这使得 projPSGApp 中的编译在 projMagellan 中触发编译。

    不过,这取决于您的用例。

    只是不要陷入必须手动管理 .jar 的情况

    另一个问题:

    import sqlContext.implicits._ 应始终包含在需要数据帧操作的范围内,因此您不应将该导入放在标题中的其他导入附近


    更新

    根据 cmets 中的讨论,我的建议是:

    • 获取 magellan 存储库

    git clone git@github.com:harsha2010/magellan.git

    • 创建一个分支来处理,例如。

    git checkout -b new-stuff

    • 更改您想要的代码
    • 然后更新版本号,例如。

    version := "1.0.7-SNAPSHOT"

    • 在本地发布

    sbt publishLocal

    你会看到类似的东西(一段时间后):

    [info] 将 ivy 发布到 /Users/tomlous/.ivy2/local/harsha2010/magellan_2.11/1.0.7-SNAPSHOT/ivys/ivy.xml

    • 转到您的其他项目
    • build.sbt 更改为包括

    "harsha2010" %% "magellan" % "1.0.7-SNAPSHOT" 在你的libraryDependencies

    现在您对您的库有一个很好的(临时)引用。

    您的 PSGApp 应该构建为一个胖 jar 程序集以传递给 Spark

    sbt clean assembly

    这将拉入自定义构建 jar

    如果 magellan 项目中的更改对世界其他地方有用,您应该推送您的更改并创建一个拉取请求,以便将来您可以只包含该库的最新版本

    【讨论】:

    • 感谢您的回复。我包含 Magellan 的原因是对项目进行了编辑,并在其中使用我们的 Edit 重建了 jar。其次,非常感谢您澄清了隐含的观点。当我把这个小小的测试项目包装到一个 obj 中以便构建到一个 jar 时,我已经把它移到了标题中。知道它不应该是这种方式,我可以将其移回。似乎 RootProject 调用意味着我可以将已编辑的 Magellan 代码“编译”到 PSGApp 中,我读对了吗?如果是这样,我应该在构建结构中的哪个位置放置 magellan 文件夹?
    • 没有 magellan 可以存在于项目文件夹之外(这就是为什么 ../ 引用 PSGApp 根文件夹的 build.sbt 的原因)也可以是绝对路径。
    • 哦,这是个有趣的信息,我将不得不从 github 获取 magellan 项目并进行测试构建。感谢您的信息!
    • 我相信要弄清楚在这里做什么,我想我也想研究 scala 中的多项目构建?似乎是谷歌学习如何做到这一点的正确关键字,到目前为止,我还没有完成具有此功能的 SBT 构建
    • 所以是的,要么使用 MultiProject 构建 scala-sbt.org/1.x/docs/Multi-Project.html 要么在您的 magellan 项目上运行 sbt publishLocal(确保使用 -SNAPSHOT 或不同的版本号然后实时)并将该引用包含在您的 pgapp sbt 中,所以它会找到您本地发布的 jar(在 ivy2 缓存中)由于 magellan 不是您自己的项目,并且可能希望将来用官方版本替换它,我实际上会使用它。
    猜你喜欢
    • 2013-12-06
    • 2017-10-16
    • 1970-01-01
    • 2015-04-28
    • 1970-01-01
    • 2012-02-15
    • 2014-05-30
    • 2016-12-15
    • 1970-01-01
    相关资源
    最近更新 更多