Scala UDF ハンドラーコーディングの一般的なガイドライン

このトピックでは、Scalaでハンドラーコードを記述するための一般的なガイドラインについて説明します。スカラー関数ハンドラーに固有の情報については、 Scalaによる スカラー UDF の記述 をご参照ください。

プロジェクトの構造化、コードのパッケージ化、依存関係の管理に関する提案については、 Scala UDF ハンドラープロジェクトとパッケージ化 をご参照ください。

ベストプラクティス

  • プラットフォームに依存しないコードを記述します。

    • 特定の CPU アーキテクチャ(例: x86)を想定したコードは避けます。

    • 特定のオペレーティングシステムを想定したコードは避けます。

  • 初期化コードを実行する必要があり、呼び出すメソッドにそのコードを含めることを望まない場合は、初期化コードをハンドラークラスのコンパニオンオブジェクトに入れることができます。

  • インラインハンドラーを使用する場合は、可能な限り CREATE FUNCTION または CREATE PROCEDURE TARGET_PATH パラメーターに値を指定してください。これにより、呼び出しごとに再コンパイルするのではなく、以前に生成されたハンドラーコード出力を再利用するようSnowflakeに促すことができます。詳細については、 インラインハンドラーの使用 をご参照ください。

ハンドラーの記述

Scalaで作成されたハンドラーを使用してスカラー UDF を作成できます。

ハンドラーは、Scala UDF に渡される行ごとに1回呼び出されます。クラスの新しいインスタンスは行ごとに作成されません。Snowflakeは、同じインスタンスのハンドラーメソッドを複数回呼び出すことができます。

コードの実行を最適化するために、Snowflakeのタイムアウトのしきい値は、ハンドラークラスまたはオブジェクトの初期化にかかる時間と、そのハンドラーメソッドの実行にかかる時間とで異なります。Snowflakeは、初期化に時間がかかる可能性があることを前提として、ハンドラークラスまたはオブジェクトを初期化する時間を長くすることができます。これには、 UDF をロードする時間と、ハンドラーメソッドを含むクラスのコンストラクターを呼び出す時間(コンストラクターが定義されている場合)が含まれます。

エラーの処理

例外処理の一般的な手法を使用して例外を処理し、ハンドラーメソッド内のエラーを捕捉できます。

メソッド内で例外が発生し、メソッドによってキャッチされない場合、Snowflakeは例外のスタックトレースを含むエラーを発生させます。

クエリを終了して SQL エラーを生成するために、例外をキャッチせずにスローできます。例:

if (x < 0) throw new IllegalArgumentException("x must be non-negative.")
Copy

デバッグ時に、 SQL エラーメッセージテキストに値を含めることができます。そうするには、

  • Scalaメソッド本体全体をtry-catchブロックに配置します。

  • 捕捉されたエラーのメッセージに引数値を追加します。そして、

  • 拡張メッセージを使用して例外をスローします。

機密データが公開されないようにするには、 JAR ファイルを実稼働環境に展開する前に引数値を削除します。

データ型の選択

ハンドラーを作成するときは、 UDF のパラメーターと戻り値のデータ型(SQL から)に適切にマップされる、パラメーターと戻り値のデータ型(ハンドラーの言語から)を宣言する必要があります。

UDF が呼び出されると、Snowflakeは UDF の引数を SQL パラメーター型からハンドラーのパラメーター型に変換します。値を返すとき、Snowflakeは戻り値をハンドラーの戻り型から UDF の戻り型に変換します。

Snowflake は、SQL 型とScala型の間でサポートされているマッピングに従って、型間の値を変換します。これらのマッピングの詳細については、 SQL-Scalaデータ型マッピング をご参照ください。

Scala変数のデータ型を選択するときは、Snowflakeから送信(およびSnowflakeに返信)される可能性のあるデータの可能な最大値と最小値を考慮に入れます。

CREATE FUNCTION を使用したUDFの作成

CREATE FUNCTIONコマンドを使用してSQLにUDFを作成し、作成したコードをハンドラーとして指定します。コマンドリファレンスについては、 CREATE FUNCTION をご参照ください。

CREATE OR REPLACE FUNCTION <name> ( [ <arguments> ] )
  RETURNS <type>
  LANGUAGE SCALA
  [ IMPORTS = ( '<imports>' ) ]
  RUNTIME_VERSION = 2.12
  [ PACKAGES = ( '<package_name>' [, '<package_name>' . . .] ) ]
  [ TARGET_PATH = '<stage_path_and_file_name_to_write>' ]
  HANDLER = '<handler_class>.<handler_method>'
  [ AS '<scala_code>' ]
Copy

作成したハンドラーコードを UDF に関連付けるには、CREATE FUNCTION を実行するときに次のようにします。

  • LANGUAGE を SCALA に設定します。

  • クラスがステージなどの外部の場所にある場合は、IMPORTS 句の値をハンドラークラスのパスと名前に設定します。

  • RUNTIME_VERSION をコードに必要なScalaランタイムのバージョンに設定します。

  • PACKAGES句の値を、ハンドラークラスに必要な1つ以上のパッケージの名前に設定します(存在する場合)。

  • HANDLER 句の値をハンドラーオブジェクトとメソッドの名前に設定します。

  • ハンドラーコードが CREATE FUNCTION とインラインで指定されている場合は、 AS '<scala_code>' 句が必要です。