Einrichten eines Jupyter Notebook für Snowpark Scala

Unter diesem Thema wird erklärt, wie Sie ein Jupyter-Notebook für Snowpark einrichten.

Unter diesem Thema:

Einrichten von Jupyter-Notebooks zur Scala-Entwicklung

Stellen Sie sicher, dass Jupyter für die Verwendung von Scala eingerichtet ist. Sie können zum Beispiel den Almond-Kernel installieren.

Bemerkung

Wenn Sie coursier verwenden, um den Almond-Kernel zu installieren, geben Sie eine unterstützte Version von Scala an.

Erstellen eines neuen Notebook in einem neuen Ordner

Die Snowpark-Bibliothek benötigt Zugriff auf das Verzeichnis, das die von der Scala-REPL generierten Klassen enthält. Wenn Sie mehrere Notebooks verwenden möchten, müssen Sie für jedes Notebook ein eigenes REPL-Klassenverzeichnis verwenden.

Um die Einrichtung eines separaten REPL-Klassenverzeichnisses für jedes Notebook zu vereinfachen, erstellen Sie für jedes Notebook einen eigenen Ordner:

  1. Klicken Sie in der Notebook-Dashboard auf New » Folder, um einen neuen Ordner für ein Notebook zu erstellen.

  2. Aktivieren Sie das Kontrollkästchen neben dem Ordner, klicken Sie auf Rename, und geben Sie dem Ordner einen neuen Namen.

  3. Klicken Sie auf den Link für den Ordner, um in dem Ordner zu navigieren.

  4. Klicken Sie auf New » Scala, um ein neues Notebook in diesem Ordner zu erstellen.

Konfigurieren des Jupyter-Notebooks für Snowpark

Als Nächstes konfigurieren Sie das Jupyter-Notebook für Snowpark.

  1. Führen Sie in einer neuen Zelle die folgenden Befehle aus, um eine Variable für ein Verzeichnis zu definieren:

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

    Dies bewirkt Folgendes:

    • Definiert eine os.Path-Variable und eine String-Variable für ein Verzeichnis der Klassen, die von der Scala-REPL generiert werden.

    • Erstellt das Verzeichnis, wenn es noch nicht existiert.

    Die Scala-REPL generiert Klassen für den von Ihnen geschriebenen Scala-Code, einschließlich des Codes, der die UDFs definiert. Die Snowpark-Bibliothek verwendet dieses Verzeichnis, um die von der REPL für Ihre UDFs generierten Klassen zu finden und hochzuladen.

    Bemerkung

    Wenn Sie mehrere Notebooks verwenden, müssen Sie für jedes Notebook ein eigenes REPL-Klassenverzeichnis erstellen und konfigurieren. Der Einfachheit halber können Sie jedes Notebook in einen eigenen Ordner speichern, wie unter Erstellen eines neuen Notebook in einem neuen Ordner beschrieben.

  2. Führen Sie die folgenden Befehle in einer Zelle aus, um den Compiler für die Scala-REPL zu konfigurieren:

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

    Dies bewirkt Folgendes:

    • Konfiguriert den Compiler so, dass er Klassen für die REPL in dem Verzeichnis generiert, das Sie zuvor erstellt haben.

    • Konfiguriert den Compiler so, dass Code, der in REPL eingegeben wird, in Klassen und nicht in Objekten gepackt wird.

    • Fügt das zuvor von Ihnen erstellte Verzeichnis als Abhängigkeit des REPL-Interpreters hinzu.

  3. Erstellen Sie eine neue Sitzung in Snowpark, und fügen Sie das REPL-Klassenverzeichnis, das Sie zuvor erstellt haben, als Abhängigkeit hinzu. Beispiel:

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

    Weitere Informationen zu den Map-Schlüsseln finden Sie unter Erstellen einer Sitzung für Snowpark Scala.

  4. Führen Sie die folgenden Befehle in einer Zelle aus, um die Ammonite-Kernelklassen als Abhängigkeiten für Ihre UDF hinzuzufügen:

    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

    Bemerkung

    Wenn Sie vorhaben, UDFs mit Abhängigkeiten zu erstellen, die über Maven verfügbar sind, können Sie diese Abhängigkeiten mit der oben definierten addClass-Methode hinzuzufügen:

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

    Wenn Sie eine Abhängigkeit in einer JAR-Datei angeben müssen, rufen Sie interp.load.cp auf, um die JAR-Datei für den REPL-Interpreter zu laden, und rufen Sie session.addDependency auf, um die JAR-Datei als Abhängigkeit für Ihre UDFs hinzuzufügen:

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

Überprüfen der Konfiguration Ihres Jupyter-Notebooks

Führen Sie die folgenden Befehle in einer Zelle aus, um sicherzustellen, dass Sie eine anonyme benutzerdefinierte Funktion (UDF) definieren und aufrufen können:

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

Problembehandlung

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

Wenn der folgende Fehler auftritt:

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

Löschen Sie den Inhalt des Verzeichnisses, das die REPL-Klassen enthält (das Verzeichnis mit dem durch die Variable replClassPath angegebenen Pfad), und starten Sie den Notebook-Server neu.