Как эффективно работать с SBT, Spark и "предоставленными" зависимостями?

Я создаю приложение Apache Spark в Scala, и я использую SBT для его создания. Вот что:

  • когда я разрабатываю IntelliJ IDEA, я хочу, чтобы зависимости Spark были включены в путь к классам (я запускаю регулярное приложение с основным классом)
  • когда я упаковываю приложение (благодаря плагину sbt-assembly), я не хочу, чтобы зависимости Spark были включены в мой полный JAR
  • когда я запускаю модульные тесты через sbt test, я хочу, чтобы зависимости Spark включались в путь к классам (такой же, как # 1, но из SBT).

Чтобы сопоставить ограничение # 2, я объявляю зависимости Spark как provided:

libraryDependencies ++= Seq(
  "org.apache.spark" %% "spark-streaming" % sparkVersion % "provided",
  ...
)

Затем документация по сборке sbt предлагает добавить следующую строку для включения зависимостей для модульных тестов (ограничение # 3):

run in Compile <<= Defaults.runTask(fullClasspath in Compile, mainClass in (Compile, run), runner in (Compile, run))

Это оставляет меня с ограничением # 1 не заполненным, т.е. я не могу запустить приложение в IntelliJ IDEA, поскольку зависимости Spark не подхватываются.

С Maven я использовал конкретный профиль для создания UBER JAR. Таким образом, я объявлял зависимости Spark как регулярные зависимости для основного профиля (IDE и модульные тесты), объявляя их как provided для полной упаковки JAR. См. https://github.com/aseigneurin/kafka-sandbox/blob/master/pom.xml

Каков наилучший способ добиться этого с помощью SBT?

Ответы

Ответ 1

(Отвечая на мой вопрос с ответом, полученным с другого канала...)

Чтобы иметь возможность запускать приложение Spark из IntelliJ IDEA, вам просто нужно создать основной класс в каталоге src/test/scala ( test, а не main). IntelliJ получит зависимости provided.

object Launch {
  def main(args: Array[String]) {
    Main.main(args)
  }
}

Спасибо Matthieu Blanc за то, что указали это.

Ответ 2

Используйте новый "Включить зависимости с" Предоставленной "областью действия" в конфигурации IntelliJ.

IntelliJ config with Provided scope checkbox

Ответ 3

Вы должны заставить IntellJ работать.

Основной трюк здесь заключается в создании другого подпроекта, который будет зависеть от основного подпроекта и будет иметь все предоставленные им библиотеки в области компиляции. Для этого я добавляю следующие строки в build.sbt:

lazy val mainRunner = project.in(file("mainRunner")).dependsOn(RootProject(file("."))).settings(
  libraryDependencies ++= spark.map(_ % "compile")
)

Теперь я обновляю проект в IDEA и немного изменяю конфигурацию предыдущего запуска, чтобы он использовал новый путь к классу модуля mainRunner:

intellj

У меня работает без нареканий.

Источник: https://github.com/JetBrains/intellij-scala/wiki/%5BSBT%5D-How-to-use-provided-libraries-in-run-configurations

Ответ 4

[Устарело] См. Новый ответ "Используйте новую" Включить зависимости с "Предоставленной областью действия" в конфигурацию IntelliJ "." ответ.

Самый простой способ добавить provided зависимости для отладки задачи с IntelliJ - это:

  • Щелкните правой кнопкой мыши src/main/scala
  • Выберите " Mark Directory as... > " Test Sources Root

Это говорит IntelliJ обрабатывать src/main/scala как тестовую папку, для которой он добавляет все зависимости, помеченные как provided для любого запуска конфигурации (отладка/запуск).

Каждый раз, когда вы выполняете обновление SBT, повторяйте эти шаги, поскольку IntelliJ будет сбрасывать папку в обычную исходную папку.

Ответ 5

Решение, основанное на создании другого подпроекта для локального запуска проекта, описано здесь.

В принципе, вам нужно модифицировать файл build.sbt следующим образом:

lazy val sparkDependencies = Seq(
  "org.apache.spark" %% "spark-streaming" % sparkVersion
)

libraryDependencies ++= sparkDependencies.map(_ % "provided")

lazy val localRunner = project.in(file("mainRunner")).dependsOn(RootProject(file("."))).settings(
   libraryDependencies ++= sparkDependencies.map(_ % "compile")
)

А затем запустите новый подпроект локально с помощью Use classpath of module: localRunner в разделе "Конфигурация запуска".

Ответ 6

Вы не должны смотреть на SBT для конкретной настройки IDEA. Прежде всего, если программа должна быть запущена с помощью spark-submit, как вы ее используете на IDEA? Я предполагаю, что вы будете работать как автономно в IDEA, пока запускаете его через искру - подчиняйтесь нормально. Если это так, добавьте вручную библиотеки искры в IDEA, используя File | Project Structure | Libraries. Вы увидите все зависимости, перечисленные в SBT, но вы можете добавить произвольные артефакты jar/maven, используя знак + (плюс). Это должно делать свое дело.

Ответ 7

Для запуска искровых заданий используется общее решение "предоставленных" зависимостей: fooobar.com/questions/170609/...

Это в основном сводится к этому:

run in Compile := Defaults.runTask(fullClasspath in Compile, mainClass in (Compile, run), runner in (Compile, run)).evaluated,
runMain in Compile := Defaults.runMainTask(fullClasspath in Compile, runner in(Compile, run)).evaluated

Ответ 8

Почему бы не обойти sbt и вручную добавить искровые ядра и искровые потоки в качестве библиотек в зависимости от вашего модуля?

  • Откройте диалоговое окно "Структура проекта" (например, ⌘;).
  • В левой панели диалогового окна выберите "Модули".
  • На панели справа выберите интересующий модуль.
  • В правой части диалогового окна на странице "Модуль" выберите вкладку "Зависимости".
  • На вкладке "Зависимости" нажмите "Добавить" и выберите "Библиотека".
  • В диалоговом окне "Выбор библиотек" выберите новую библиотеку, из maven
  • Найдите искровой стержень. Ex org.apache.spark:spark-core_2.10:1.6.1
  • Profit

https://www.jetbrains.com/help/idea/2016.1/configuring-module-dependencies-and-libraries.html?origin=old_help#add_existing_lib