【问题标题】:spark and mill - create an additional task that creates a filtered assemblyspark和mill - 创建一个额外的任务来创建一个过滤的程序集
【发布时间】:2020-02-23 23:39:56
【问题描述】:

我想构建一个mill 作业,允许我通过SparkSample.run 在本地开发和运行 Spark 作业,或者拥有一个完整的 jar 用于本地测试。 在某个时间点,我想将它作为过滤后的程序集(即没有所有与 spark 相关的库,但包含所有项目库)发送到具有正在运行的 Spark 上下文的集群。

我目前使用这个build.sc

import mill._, scalalib._
import mill.modules.Assembly

object SparkSample extends ScalaModule {
  def scalaVersion = "2.12.10"
  def scalacOptions =
    Seq("-encoding", "utf-8", "-explaintypes", "-feature", "-deprecation")

  def ivySparkDeps = Agg(
    ivy"org.apache.spark::spark-sql:2.4.5"
      .exclude("org.slf4j" -> "slf4j-log4j12"),
    ivy"org.slf4j:slf4j-api:1.7.16",
    ivy"org.slf4j:slf4j-log4j12:1.7.16"
  )

  def ivyBaseDeps = Agg(
    ivy"com.lihaoyi::upickle:0.9.7"
  )

  // STANDALONE APP
  def ivyDeps = ivyBaseDeps ++ ivySparkDeps

  // REMOTE SPARK CLUSTER
  // def ivyDeps = ivyBaseDeps
  // def compileIvyDeps = ivySparkDeps
  // def assemblyRules =
  //   Assembly.defaultRules ++
  //     Seq(
  //       "scala/.*",
  //       "org.slf4j.*",
  //       "org.apache.log4j.*"
  //     ).map(Assembly.Rule.ExcludePattern.apply)
}

为了运行和构建一个完整的罐子,我保持原样。

为了创建过滤程序集,我在“STANDALONE APP”下注释ivyDeps 行并取消注释“REMOTE SPARK CLUSTER”下的所有内容。

我觉得为新任务编辑构建文件不是很优雅,所以我尝试将单独的任务添加到build.sc

  def assembly2 = T {
    def ivyDeps = ivyBaseDeps
    def compileIvyDeps = ivySparkDeps
    def assemblyRules =
      Assembly.defaultRules ++
        Seq(
          "scala/.*",
          "org.slf4j.*",
          "org.apache.log4j.*"
        ).map(Assembly.Rule.ExcludePattern.apply)
    super.assembly
  }

但是当我运行SparkSample.assembly2 时,它仍然得到一个完整的程序集,而不是一个过滤的程序集。似乎覆盖ivyDeps 等。人。在任务中不起作用。

mill 可以这样做吗?

【问题讨论】:

    标签: scala apache-spark mill


    【解决方案1】:

    您不能覆盖任务中的定义。仅在本地定义一些 ivyDepscompileIvyDeps 不会神奇地使 super.assembly 使用它们。

    当然,您可以通过查看 super.assemblyJavaModule 中的定义来创建该任务,但您最终会复制和调整更多目标(upstreamAssemblyupstreamAssemblyClasspathtransitiveLocalClasspath 等等on) 并使您的构建文件难以阅读。

    更好的方法是将较轻的依赖项和组装规则设为默认值,并将独立 JAR 的创建移至子模块中。

    import mill._, scalalib._
    import mill.modules.Assembly
    
    object SparkSample extends ScalaModule { outer =>
      def scalaVersion = "2.12.10"
      def scalacOptions =
        Seq("-encoding", "utf-8", "-explaintypes", "-feature", "-deprecation")
    
      def ivySparkDeps = Agg(
        ivy"org.apache.spark::spark-sql:2.4.5"
          .exclude("org.slf4j" -> "slf4j-log4j12"),
        ivy"org.slf4j:slf4j-api:1.7.16",
        ivy"org.slf4j:slf4j-log4j12:1.7.16"
      )
    
      def ivyDeps = Agg(
        ivy"com.lihaoyi::upickle:0.9.7"
      )
    
      def compileIvyDeps = ivySparkDeps
    
      def assemblyRules =
        Assembly.defaultRules ++
          Seq(
            "scala/.*",
            "org.slf4j.*",
            "org.apache.log4j.*"
          ).map(Assembly.Rule.ExcludePattern.apply)
    
      object standalone extends ScalaModule {
        def scalaVersion = outer.scalaVersion
        def moduleDeps = Seq(outer)
        def ivyDeps = outer.ivySparkDeps
      }
    }
    

    创建 Spark 集群 JAR 运行:mill SparkSample.assembly

    创建一个独立的 JAR 运行:mill SparkSample.standalone.assembly

    要创建两者,您只需运行:mill __.assembly

    【讨论】:

    • 我必须将“def finalMainClass = T { 'com.example.SparkSample' }”添加到“standalone”以允许运行“mill SparkSample.standalone.run”。 (现在我需要弄清楚mill如何将主类添加到standalone.assembly清单文件中,然后一切都按我的意愿工作)
    • 那是因为finalMainClass 不用于assembly。如果您使用mainClass(或finalMainClassOpt),它会按预期工作。
    猜你喜欢
    • 1970-01-01
    • 2011-10-08
    • 1970-01-01
    • 2021-04-27
    • 2012-03-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多