为 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 创建一个单独的文件夹:
在 Notebook Dashboard (https://jupyter-notebook.readthedocs.io/en/latest/ui_components.html#notebook-dashboard) 中,单击 New » Folder 为 Notebook 创建新文件夹。
选中该文件夹旁边的复选框,单击 Rename,然后为该文件夹指定一个新名称。
单击该文件夹的链接以导航到该文件夹。
单击 New » Scala,在该文件夹中创建新 Notebook。
为 Snowpark 配置 Jupyter Notebook¶
接下来,为 Snowpark 配置 Jupyter Notebook。
在新单元格中,运行以下命令,以便为目录定义变量:
val replClassPathObj = os.Path("replClasses", os.pwd) if (!os.exists(replClassPathObj)) os.makeDir(replClassPathObj) val replClassPath = replClassPathObj.toString()
这将执行以下操作:
定义一个 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 中所述。
在单元格中运行以下命令,为 Scala REPL 配置编译器:
interp.configureCompiler(_.settings.outputDirs.setSingleOutput(replClassPath)) interp.configureCompiler(_.settings.Yreplclassbased) interp.load.cp(replClassPathObj)
这将执行以下操作:
配置编译器,以便为您先前创建的目录中的 REPL 生成类。
配置编译器,以封装在类(而非对象)内的 REPL 中输入的代码。
将您之前创建的目录添加为 REPL 解析器的依赖项。
在 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 创建会话。在单元格中运行以下命令,将 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")
备注
如果您计划创建的UDFs 具有可通过 Maven 获得的依赖项,可以使用上面定义的
addClass
方法来添加这些依赖项:addClass(session, "<dependency_package>.<dependency_class>")
如果您需要在 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>)
验证 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()
故障排除¶
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
删除包含 REPL 类的目录(带有 replClassPath
变量指定路径的目录)的内容,然后重启 Notebook。