为 Snowpark Scala 设置 Jupyter Notebook

本主题介绍如何为 Snowpark 设置 Jupyter Notebook。

本主题内容:

为 Scala 开发设置 Jupyter Notebook

确保设置 Jupyter 以使用 Scala。例如,您可以 安装 Almond 内核 (https://almond.sh/docs/quick-start-install)。

备注

使用 coursier 安装 Almond 内核时,请指定 支持的 Scala 版本。

在新文件夹中创建新 Notebook

Snowpark 库需要访问包含 Scala REPL 生成的类的目录。如果您计划使用多个 Notebook,则必须为每个 Notebook 使用单独的 REPL 类目录。

为了方便给每个 Notebook 设置单独的 REPL 类目录,请为每个 Notebook 创建一个单独的文件夹:

  1. 在 Notebook Dashboard (https://jupyter-notebook.readthedocs.io/en/latest/ui_components.html#notebook-dashboard) 中,单击 New » Folder 为 Notebook 创建新文件夹。

  2. 选中该文件夹旁边的复选框,单击 Rename,然后为该文件夹指定一个新名称。

  3. 单击该文件夹的链接以导航到该文件夹。

  4. 单击 New » Scala,在该文件夹中创建新 Notebook。

为 Snowpark 配置 Jupyter Notebook

接下来,为 Snowpark 配置 Jupyter Notebook。

  1. 在新单元格中,运行以下命令,以便为目录定义变量:

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

    这将执行以下操作:

    • 定义一个 os.Path (https://github.com/com-lihaoyi/os-lib#ospath) 变量和一个 String 变量,用于 Scala REPL 生成的类的目录。

    • 如果该目录尚不存在,系统会创建该目录。

    Scala REPL 会为您编写的 Scala 代码生成类,包括定义 UDFs 的代码。Snowpark 库使用此目录来查找和上传由 REPL 为您的 UDFs 生成的类。

    备注

    如果您使用多个 Notebook,则需要为每个 Notebook 创建和配置单独的 REPL 类目录。为简单起见,可将每个 Notebook 放在单独的文件夹中,如 在新文件夹中创建新 Notebook 中所述。

  2. 在单元格中运行以下命令,为 Scala REPL 配置编译器:

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

    这将执行以下操作:

    • 配置编译器,以便为您先前创建的目录中的 REPL 生成类。

    • 配置编译器,以封装在类(而非对象)内的 REPL 中输入的代码。

    • 将您之前创建的目录添加为 REPL 解析器的依赖项。

  3. 在 Snowpark 中创建一个新会话,并将您之前创建的 REPL 类目录添加为依赖项。例如:

    // Import the Snowpark library from Maven.
    import $ivy.`com.snowflake:snowpark:1.15.0`
    
    import com.snowflake.snowpark._
    import com.snowflake.snowpark.functions._
    
    val session = Session.builder.configs(Map(
        "URL" -> "https://<account_identifier>.snowflakecomputing.cn",
        "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)

    有关 Map 键的说明,请参阅 为 Snowpark Scala 创建会话

  4. 在单元格中运行以下命令,将 Ammonite 内核类添加为 您的 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

    备注

    如果您计划创建的UDFs 具有可通过 Maven 获得的依赖项,可以使用上面定义的 addClass 方法来添加这些依赖项:

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

    如果您需要在 JAR 文件中指定依赖项,请调用 interp.load.cp 为 REPL 解析器加载 JAR 文件,然后调用 session.addDependency,将该 JAR 文件添加为您的 UDFs 的依赖项:

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

验证 Jupyter Notebook 配置

在单元格中运行以下命令,以验证您是否可以定义和调用匿名的用户定义的函数 (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

故障排除

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

如果发生以下错误:

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

删除包含 REPL 类的目录(带有 replClassPath 变量指定路径的目录)的内容,然后重启 Notebook。

语言: 中文