この記事は何?
Snowflake のSparkっぽい機能 Snowpark を Notebook で使えるようにするところまで一気に書いた記事です
参考 Snowtire:https://github.com/zoharsan/snowtire_v2
早速Notebookを起動するところまで
まずは Snowtire(v2) を clone します
% git clone git@github.com:zoharsan/snowtire_v2.git
% cd snowtire_v2v
次に build します
% docker build --pull -t snowtire .
そして run します(nameは適当につけてください)
% docker run -p 8888:8888 --name spare-0 snowtire:latest
(省略)
[C 12:19:02.007 NotebookApp]
To access the notebook, open this file in a browser:
file:///home/jovyan/.local/share/jupyter/runtime/nbserver-16-open.html
Or copy and paste one of these URLs:
http://ef149ca5921e:8888/?token=hogehogehogehogehogehogehogehogehogehoge
or http://127.0.0.1:8888/?token=hogehogehogehogehogehogehogehogehogehoge
最後に先程表示されたURLをブラウザなどで開きます
open http://127.0.0.1:8888/?token=hogehogehogehogehogehogehogehogehogehoge
Snowparkを動かしましょう!
New から Scala を選んで、 Scala 用の空の Notebook を作成します
Notebookの名前は何でも良いです。
Snowpark 用に環境を設定していきます
参考: Snowpark用Jupyterノートブックの設定 https://docs.snowflake.com/ja/developer-guide/snowpark/quickstart-jupyter.html
Notebook の前準備
最初のセルでは Snowpark が依存するライブラリの Maven リポジトリを使用するようにリポジトリを追加します
import sys.process._
val osgeoRepo = coursierapi.MavenRepository.of("https://repo.osgeo.org/repository/release")
interp.repositories() ++= Seq(osgeoRepo)
2つ目のセルで replClassPath を設定します
今回は /home/jovyan/work/repl
にしてますが、好きなところに設定してください
import sys.process._
val replClassPath = "/home/jovyan/work/repl" // e.g. /home/myusername/replClasses
s"mkdir -p $replClassPath" !
3つ目のセルで replClassPath にクラスを生成するように設定して、依存関係に含めるようにします
interp.configureCompiler(_.settings.outputDirs.setSingleOutput(replClassPath))
interp.configureCompiler(_.settings.Yreplclassbased)
interp.load.cp(os.Path(replClassPath))
これでこの Notebook で Snowpark を使う前準備ができました
Snowpark インストールして実行
下記のような感じで Snowpark 用のセッションを作成できます
// Import the Snowpark library from Maven.
import $ivy.`com.snowflake:snowpark:0.8.0`
import com.snowflake.snowpark._
import com.snowflake.snowpark.functions._
val session = Session.builder.configs(Map(
"URL" -> "https://<account_identifier>.snowflakecomputing.com",
"USER" -> "<username>",
"PRIVATEKEY" -> "<private rsa key copied from your private key file>",
"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)
セッションができたら下記のように Notebook で書いた UDF が Snowflake 側で動くように依存ライブラリとして、 Ammonite を設定します。
これをしないとローカルの Notebook では Ammonite で動くコードを書いたけど、 Snowflake 側は通常のインタプリタのママになって、動かない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")
もう Snowpark を動かせているんですが、念の為 UDF の動作確認をしてみましょう。
class UDFCode extends Serializable {
val appendLastNameFunc = (s: String) => {
s"$s Johnson"
}
}
val appendLastNameUdf = udf((new UDFCode).appendLastNameFunc)
val df = session.sql("select 'Raymond' NAME")
df.withColumn("Full Name", appendLastNameUdf(col("NAME"))).show()
上記を実行すると下記のように表示されれば成功です。
-----------------------------
|"NAME" |"Full Name" |
-----------------------------
|Raymond |Raymond Johnson |
-----------------------------
まとめ
こんな感じならだれでも Snowpark をサクッと始められそうですね!
そういえば、2021年10月5日に Snowflake の開発者向けグローバルイベント BUILD の日本ローカルイベントとして BUILD.local でお話します!
もしよければご視聴ください〜
https://usergroups.snowflake.com/events/details/snowflake-japan-presents-buildlocal-japan-snowparkdexi-ufei-gou-zao-deta-playing-with-unstructured-data-using-snowpark/