web-dev-qa-db-fra.com

Comment travailler efficacement avec SBT, Spark et les dépendances "fournies"?

Je construis une application Apache Spark dans Scala et j'utilise SBT pour la construire. Voici la chose:

  1. quand je développe sous IntelliJ IDEA, je veux que les dépendances Spark soient incluses dans le chemin de classe (je lance une application régulière avec une classe principale)
  2. quand je conditionne l'application (grâce au plugin sbt-Assembly), je ne veux pas vouloir Spark dépendances être inclus dans mon gros pot
  3. lorsque j'exécute des tests unitaires via sbt test, Je veux que les dépendances Spark soient incluses dans le chemin de classe (comme # 1 mais à partir du SBT)

Pour correspondre à la contrainte n ° 2, je déclare Spark dépendances comme provided:

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

Ensuite, documentation de sbt-Assembly suggère d'ajouter la ligne suivante pour inclure les dépendances pour les tests unitaires (contrainte # 3):

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

Cela me laisse avec la contrainte # 1 qui n'est pas entièrement remplie, c'est-à-dire que je ne peux pas exécuter l'application dans IntelliJ IDEA as Spark ne sont pas récupérées).

Avec Maven, j'utilisais un profil spécifique pour construire le uber JAR. De cette façon, je déclarais les dépendances Spark comme des dépendances régulières pour le profil principal (IDE et tests unitaires) tout en les déclarant comme provided pour le gros emballage JAR. Voir https://github.com/aseigneurin/kafka-sandbox/blob/master/pom.xml

Quelle est la meilleure façon d'y parvenir avec SBT?

25

(Répondre à ma propre question avec une réponse que j'ai obtenue d'un autre canal ...)

Pour pouvoir exécuter l'application Spark d'IntelliJ IDEA, il vous suffit de créer une classe principale dans le src/test/scala répertoire (test, pas main). IntelliJ récupérera les dépendances provided.

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

Merci Matthieu Blanc pour l'avoir signalé.

17

Utilisez le nouveau "Inclure les dépendances avec l'étendue" fournie "" dans une configuration IntelliJ.

IntelliJ config with Provided scope checkbox

12
Martin Tapp

Vous devez faire fonctionner IntellJ.

L'astuce principale ici est de créer un autre sous-projet qui dépendra du sous-projet principal et aura toutes ses bibliothèques fournies dans la portée de compilation. Pour ce faire, j'ajoute les lignes suivantes à build.sbt:

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

Maintenant, je rafraîchis le projet dans IDEA et modifie légèrement la configuration d'exécution précédente afin qu'il utilise le nouveau chemin de classe du module mainRunner:

intellj

Fonctionne parfaitement pour moi.

Source: https://github.com/JetBrains/intellij-scala/wiki/%5BSBT%5D-How-to-use-provided-libraries-in-run-configurations

3
Atais

[Obsolète] Voir la nouvelle réponse "Utilisez la nouvelle 'Inclure les dépendances avec la portée" fournie "dans une configuration IntelliJ." Réponse.

La façon la plus simple d'ajouter des dépendances provided pour déboguer une tâche avec IntelliJ est de:

  • Clic-droit src/main/scala
  • Sélectionnez Mark Directory as...> Test Sources Root

Cela indique à IntelliJ de traiter src/main/scala comme dossier de test pour lequel il ajoute toutes les dépendances marquées comme provided à n'importe quelle configuration d'exécution (débogage/exécution).

Chaque fois que vous effectuez une actualisation SBT, recommencez cette étape car IntelliJ réinitialisera le dossier dans un dossier source normal.

2
Martin Tapp

Une solution basée sur la création d'un autre sous-projet pour exécuter le projet localement est décrite ici .

Fondamentalement, vous devrez modifier le build.sbt fichier avec les éléments suivants:

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")
)

Et puis exécutez le nouveau sous-projet localement avec Use classpath of module: localRunner sous Exécuter la configuration.

1
bertslike

Pour exécuter les travaux spark, la solution générale des dépendances "fournies" fonctionne: https://stackoverflow.com/a/21803413/1091436

Vous pouvez ensuite exécuter l'application à partir de sbt, ou Intellij IDEA, ou toute autre chose.

Cela se résume essentiellement à ceci:

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
0
VasiliNovikov

Vous ne devriez pas regarder SBT pour un paramètre spécifique IDEA. Tout d'abord, si le programme est censé être exécuté avec spark-submit, comment l'exécutez-vous sur IDEA? Je suppose que vous fonctionneriez de manière autonome dans IDEA, tout en l'exécutant via spark-submit normalement. Si tel est le cas, ajoutez manuellement les bibliothèques spark dans IDEA, en utilisant Fichier | Structure du projet | Bibliothèques. Vous verrez toutes les dépendances répertoriées à partir de SBT, mais vous pouvez ajouter des artefacts jar/maven arbitraires en utilisant le signe + (plus). Cela devrait faire l'affaire.

0
Roberto Congiu