Configuration d’un carnet Jupyter pour Snowpark Scala

Cette rubrique explique comment configurer un carnet de notes Jupyter pour Snowpark.

Dans ce chapitre :

Configuration de carnets Jupyter pour le développement Scala

Assurez-vous que Jupyter est configuré pour utiliser Scala. Par exemple, vous pouvez installer le noyau Almond.

Note

Lorsque vous utilisez coursier pour installer le noyau Almond, spécifiez une version de Scala prise en charge.

Créer un nouveau carnet dans un nouveau dossier

La bibliothèque Snowpark nécessite l’accès au répertoire qui contient les classes générées par REPL Scala. Si vous prévoyez d’utiliser plusieurs carnets, vous devez utiliser un répertoire de classe REPL distinct pour chaque carnet.

Pour faciliter la mise en place d’un répertoire de classe REPL distinct pour chaque carnet, créez un dossier séparé pour chaque carnet :

  1. Dans le tableau de bord du carnet, cliquez sur New » Folder pour créer un nouveau dossier pour un carnet.

  2. Cochez la case à cocher à côté du dossier, cliquez sur Rename, et attribuez un nouveau nom au dossier.

  3. Cliquez sur le lien du dossier pour naviguer dans le dossier.

  4. Cliquez sur New » Scala pour créer un nouveau carnet dans ce dossier.

Configuration du carnet Jupyter pour Snowpark

Ensuite, configurez le carnet Jupyter pour Snowpark.

  1. Dans une nouvelle cellule, exécutez les commandes suivantes pour définir une variable pour un répertoire :

    val replClassPathObj = os.Path("replClasses", os.pwd)
    if (!os.exists(replClassPathObj)) os.makeDir(replClassPathObj)
    val replClassPath = replClassPathObj.toString()
    
    Copy

    Cela permet de faire ce qui suit :

    • Définit une variable os.Path et une variable String pour un répertoire pour les classes générées par le REPL de Scala.

    • Crée ce répertoire, s’il n’existe pas déjà.

    Le REPL Scala génère des classes pour le code Scala que vous écrivez, y compris votre code qui définit des UDFs. La bibliothèque Snowpark utilise ce répertoire pour trouver et charger les classes pour vos UDFs qui sont générées par le REPL.

    Note

    Si vous utilisez plusieurs ordinateurs portables, vous devrez créer et configurer un répertoire de classe REPL distinct pour chaque ordinateur portable. Pour simplifier, vous pouvez simplement placer chaque carnet dans un dossier séparé, comme expliqué dans Créer un nouveau carnet dans un nouveau dossier.

  2. Exécutez les commandes suivantes dans une cellule pour configurer le compilateur pour le REPL Scala :

    interp.configureCompiler(_.settings.outputDirs.setSingleOutput(replClassPath))
    interp.configureCompiler(_.settings.Yreplclassbased)
    interp.load.cp(replClassPathObj)
    
    Copy

    Cela permet de faire ce qui suit :

    • Configure le compilateur pour générer des classes pour les REPL dans le répertoire que vous avez créé précédemment.

    • Configure le compilateur pour envelopper le code entré dans le REPL dans des classes, plutôt que dans des objets.

    • Ajoute le répertoire que vous avez créé précédemment comme une dépendance de l’interpréteur REPL.

  3. Créez une nouvelle session dans Snowpark, et ajoutez le répertoire de classe REPL que vous avez créé plus tôt comme dépendance. Par exemple :

    // Import the Snowpark library from Maven.
    import $ivy.`com.snowflake:snowpark:1.9.0`
    
    import com.snowflake.snowpark._
    import com.snowflake.snowpark.functions._
    
    val session = Session.builder.configs(Map(
        "URL" -> "https://<account_identifier>.snowflakecomputing.com",
        "USER" -> "<username>",
        "PASSWORD" -> "<password>",
        "ROLE" -> "<role_name>",
        "WAREHOUSE" -> "<warehouse_name>",
        "DB" -> "<database_name>",
        "SCHEMA" -> "<schema_name>"
    )).create
    
    // Add the directory for REPL classes that you created earlier.
    session.addDependency(replClassPath)

    Voir Création d’une session pour Snowpark Scala pour une explication des clés Map.

  4. Exécutez les commandes suivantes dans une cellule pour ajouter les classes du noyau Ammonite comme dépendances pour votre UDF :

    def addClass(session: Session, className: String): String = {
      var cls1 = Class.forName(className)
      val resourceName = "/" + cls1.getName().replace(".", "/") + ".class"
      val url = cls1.getResource(resourceName)
      val path = url.getPath().split(":").last.split("!").head
      session.addDependency(path)
      path
    }
    addClass(session, "ammonite.repl.ReplBridge$")
    addClass(session, "ammonite.interp.api.APIHolder")
    addClass(session, "pprint.TPrintColors")
    
    Copy

    Note

    Si vous prévoyez de créer des UDFs dont les dépendances sont disponibles via Maven, vous pouvez utiliser la méthode addClass définie ci-dessus pour ajouter ces dépendances :

    addClass(session, "<dependency_package>.<dependency_class>")
    
    Copy

    Si vous devez spécifier une dépendance dans un fichier JAR, appelez interp.load.cp pour charger le fichier JAR pour l’interpréteur REPL, et appelez session.addDependency pour ajouter le fichier JAR comme dépendance pour vos UDFs :

    interp.load.cp(os.Path(<path to jar file>/<jar file>))
    addDependency(<path to jar file>/<jar file>)
    
    Copy

Vérification de la configuration de votre carnet Jupyter

Exécutez les commandes suivantes dans une cellule pour vérifier que vous pouvez définir et appeler une fonction anonyme définie par l’utilisateur (UDF) :

class UDFCode extends Serializable {
  val appendLastNameFunc = (s: String) => {
    s"$s Johnson"
  }
}
// Define an anonymous UDF.
val appendLastNameUdf = udf((new UDFCode).appendLastNameFunc)
// Create a DataFrame that has a column NAME with a single row with the value "Raymond".
val df = session.sql("select 'Raymond' NAME")
// Call the UDF, passing in the values in the NAME column.
// Return a new DataFrame that has an additional column "Full Name" that contains the value returned by the UDF.
df.withColumn("Full Name", appendLastNameUdf(col("NAME"))).show()
Copy

Dépannage

la valeur res<n> n’est pas un membre de ammonite.$sess.cmd<n>.wrapper.Helper

Si l’erreur suivante se produit :

value res<n> is not a member of ammonite.$sess.cmd<n>.wrapper.Helper
Copy

Supprimez le contenu du répertoire contenant les classes REPL (le répertoire dont le chemin est spécifié par la variable replClassPath), et redémarrez le serveur du carnet.