Traffine I/O

日本語

2022-12-11

SnowflakeにおけるUDF

ユーザー定義関数(UDF)とは

ユーザー定義関数(UDF)は、Snowflakeの重要な構成要素です。UDFは、SQL文で使用するために定義する関数です。組み込みのSQL関数と同様に、UDFは主にSQLの機能を拡張し、言語にネイティブに含まれていない追加の機能やタスクを提供します。

また、UDFはコード内のさまざまな場所から繰り返し呼び出すことができる特定の機能をカプセル化しています。このカプセル化により、コードの再利用性が向上し、Snowflakeを使用するデータベース開発者や管理者にとって貴重なツールとなります。

UDFの種類

Snowflakeでは、スカラー関数とタブラー関数の2つのタイプのUDFを作成することができます。

スカラー関数

スカラー関数は、単一の値を返すUDFの一種です。スカラー関数は、入力行ごとに1つの出力行を生成し、その出力行は単一の列または値から構成されます。この特性により、スカラー関数は行単位でデータを操作するタスクに最適です。

タブラー関数

一方、タブラー関数(またはユーザー定義テーブル関数:UDTF)は、入力行ごとにタブラー値を返します。これらの関数は、スカラー関数よりも複雑な機能を提供します。

UDTFを作成する際には、Snowflakeが要求するインターフェースに準拠したメソッドを記述する必要があります。具体的には、これらのメソッドは次の操作を実行する必要があります。

  • パーティション内の各行を処理する。この操作はUDTFの必要なパートです。
  • 各パーティションごとにハンドラを初期化する。このメソッドはオプションですが、特定のユースケースでは有益です。
  • 各パーティションの処理を終了する。初期化と同様に、この操作もオプションですが、処理の最後でリソースのクリーンアップや計算の最終化に使用できます。

UDFの例

以下の例では、Pythonで書かれたハンドラを含むaddoneという名前のUDFを作成します。このUDFは整数を返します。

sql
CREATE OR REPLACE FUNCTION addone(i int)
RETURNS INT
LANGUAGE PYTHON
RUNTIME_VERSION = '3.8'
HANDLER = 'addone_py'
as
$$
def addone_py(i):
  return i+1
$$;

UDFを作成した後は、組み込みのSQL関数と同様に実行することができます。次の例では、addoneUDFを実行する方法を示しています。

sql
SELECT addone(3);

このSQL文は、addone関数が入力された整数に1を加えるため、4を出力します。

UDFのサポートされる言語

SnowflakeのUDFでは、関数のロジックやハンドラを記述するためにさまざまなプログラミング言語がサポートされています。これにより、開発者は言語とそのランタイム環境の制約内で好みの言語を使用することができます。ハンドラの言語に関係なく、関数はSQLを使用して作成し、ハンドラとハンドラの言語を指定します。

以下の言語は、UDFハンドラの記述にサポートされています。

  • Java
  • JavaScript
  • Python
  • Scala
  • SQL

SnowflakeでUDFを作成する

UDFまたはUDTFの作成には、関数のハンドラを記述し、その後、CREATE FUNCTIONコマンドを使用して関数自体を作成する必要があります。

SnowflakeでUDFを作成するには、以下の手順に従ってください。

  1. UDFが呼び出されたときに実行されるハンドラコードを記述します。このハンドラにはUDFのロジックが含まれます。Java、JavaScript、Python、Scala、SQLなどのサポートされている言語のいずれかで記述することができます。

  2. ハンドラコードをCREATE FUNCTIONのSQL文内にインラインで保持するか、ステージ上で参照するかを選択します。この決定は、コードの複雑さや長さ、および組織のコード管理の慣行によります。

  3. SQLでCREATE FUNCTIONステートメントを実行し、関数のプロパティを指定します。これらのプロパティには、関数の名前、入力引数、戻り値の型、ハンドラ関数などが含まれます。

UDFの作成の構文

UDFの作成の構文は、ハンドラの言語によって異なります。

JavaおよびScalaハンドラ

ハンドラのソースコードがインラインの場合は、以下の構文を使用します。

CREATE [ OR REPLACE ] [ { TEMP | TEMPORARY } ] [ SECURE ] FUNCTION [ IF NOT EXISTS ] <name> ( [ <arg_name> <arg_data_type> ] [ , ... ] )
  [ COPY GRANTS ]
  RETURNS { <result_data_type> | TABLE ( <col_name> <col_data_type> [ , ... ] ) }
  [ [ NOT ] NULL ]
  LANGUAGE { JAVA | SCALA }
  [ { CALLED ON NULL INPUT | { RETURNS NULL ON NULL INPUT | STRICT } } ]
  [ VOLATILE | IMMUTABLE ]
  [ RUNTIME_VERSION = <java_jdk_version> ]
  [ COMMENT = '<string_literal>' ]
  [ IMPORTS = ( '<stage_path_and_file_name_to_read>' [ , ... ] ) ]
  [ PACKAGES = ( '<package_name_and_version>' [ , ... ] ) ]
  HANDLER = '<path_to_method>'
  [ TARGET_PATH = '<stage_path_and_file_name_to_write>' ]
  AS '<function_definition>'

ハンドラーコードがステージ(JARなど)で参照される場合は、以下の構文を使用します。

CREATE [ OR REPLACE ] [ { TEMP | TEMPORARY } ] [ SECURE ] FUNCTION [ IF NOT EXISTS ] <name> ( [ <arg_name> <arg_data_type> ] [ , ... ] )
  [ COPY GRANTS ]
  RETURNS { <result_data_type> | TABLE ( <col_name> <col_data_type> [ , ... ] ) }
  [ [ NOT ] NULL ]
  LANGUAGE { JAVA | SCALA }
  [ { CALLED ON NULL INPUT | { RETURNS NULL ON NULL INPUT | STRICT } } ]
  [ VOLATILE | IMMUTABLE ]
  [ RUNTIME_VERSION = <java_jdk_version> ]
  [ COMMENT = '<string_literal>' ]
  IMPORTS = ( '<stage_path_and_file_name_to_read>' [ , ... ] )
  HANDLER = '<path_to_method>'

JavaScriptハンドラ

CREATE [ OR REPLACE ] [ { TEMP | TEMPORARY } ] [ SECURE ] FUNCTION <name> ( [ <arg_name> <arg_data_type> ] [ , ... ] )
  [ COPY GRANTS ]
  RETURNS { <result_data_type> | TABLE ( <col_name> <col_data_type> [ , ... ] ) }
  [ [ NOT ] NULL ]
  LANGUAGE JAVASCRIPT
  [ { CALLED ON NULL INPUT | { RETURNS NULL ON NULL INPUT | STRICT } } ]
  [ VOLATILE | IMMUTABLE ]
  [ COMMENT = '<string_literal>' ]
  AS '<function_definition>'

Pythonハンドラ

ソースコードがインラインの場合は、以下の構文を使用します。

CREATE [ OR REPLACE ] [ { TEMP | TEMPORARY } ] [ SECURE ] FUNCTION [ IF NOT EXISTS ] <name> ( [ <arg_name> <arg_data_type> ] [ , ... ] )
  [ COPY GRANTS ]
  RETURNS { <result_data_type> | TABLE ( <col_name> <col_data_type> [ , ... ] ) }
  [ [ NOT ] NULL ]
  LANGUAGE PYTHON
  [ { CALLED ON NULL INPUT | { RETURNS NULL ON NULL INPUT | STRICT } } ]
  [ VOLATILE | IMMUTABLE ]
  RUNTIME_VERSION = <python_version>
  [ COMMENT = '<string_literal>' ]
  [ IMPORTS = ( '<stage_path_and_file_name_to_read>' [ , ... ] ) ]
  [ PACKAGES = ( '<package_name>[==<version>]' [ , ... ] ) ]
  HANDLER = '<function_name>'
  AS '<function_definition>'

ハンドラーコードが(モジュールなどの)ステージ上で参照される場合は、以下の構文を使用します。

CREATE [ OR REPLACE ] [ { TEMP | TEMPORARY } ] [ SECURE ] FUNCTION [ IF NOT EXISTS ] <name> ( [ <arg_name> <arg_data_type> ] [ , ... ] )
  [ COPY GRANTS ]
  RETURNS { <result_data_type> | TABLE ( <col_name> <col_data_type> [ , ... ] ) }
  [ [ NOT ] NULL ]
  LANGUAGE PYTHON
  [ { CALLED ON NULL INPUT | { RETURNS NULL ON NULL INPUT | STRICT } } ]
  [ VOLATILE | IMMUTABLE ]
  RUNTIME_VERSION = <python_version>
  [ COMMENT = '<string_literal>' ]
  IMPORTS = ( '<stage_path_and_file_name_to_read>' [ , ... ] )
  [ PACKAGES = ( '<package_name>[==<version>]' [ , ... ] ) ]
  HANDLER = '<module_file_name>.<function_name>'

SQLハンドラ

CREATE [ OR REPLACE ] [ { TEMP | TEMPORARY } ] [ SECURE ] FUNCTION <name> ( [ <arg_name> <arg_data_type> ] [ , ... ] )
  [ COPY GRANTS ]
  RETURNS { <result_data_type> | TABLE ( <col_name> <col_data_type> [ , ... ] ) }
  [ [ NOT ] NULL ]
  [ VOLATILE | IMMUTABLE ]
  [ MEMOIZABLE ]
  [ COMMENT = '<string_literal>' ]
  AS '<function_definition>'

UDF作成のパラメータ

Snowflakeでは、UDFの作成時に必要なパラメータとオプションのパラメータが用意されています。これらのパラメータを使用すると、UDFの動作をカスタマイズしたり、プロパティを制御したりすることができます。これらのパラメータの詳細については、元のコンテンツにリンクされている公式のSnowflakeドキュメンテーションを参照してください。

https://docs.snowflake.com/en/sql-reference/sql/create-function#required-parameters
https://docs.snowflake.com/en/sql-reference/sql/create-function#optional-parameters

SnowflakeでUDFを呼び出す

SnowflakeでUDFが作成された後は、他の関数と同様に呼び出すことができます。

UDFの呼び出し

UDFを呼び出す一般的な方法は、他の関数を呼び出す場合と同様です。UDF名の後に括弧を付け、UDFに引数がある場合は括弧内に指定します。引数は名前または位置で指定することができます。

次の例では、3つの文字列を連結するUDFを考えます。

sql
CREATE OR REPLACE FUNCTION udf_concatenate_strings(
    first VARCHAR,
    second VARCHAR,
    third VARCHAR)
  RETURNS VARCHAR
  LANGUAGE SQL
  AS
  $$
    RETURN first || second || third;
  $$;

UDFを呼び出す際には、引数を名前で指定することも、位置で指定することもできます。

sql
SELECT udf_concatenate_strings(
  first => 'one',
  second => 'two',
  third => 'three');
sql
SELECT udf_concatenate_strings(
  'one',
  'two',
  'three');

引数を指定する際には、全ての引数を名前で指定するか、位置で指定する必要があります。名前と位置の混合は使用できません。

UDTFの呼び出し

UDTFもUDFと同様に、名前を使用して呼び出されます。ただし、テーブルを返すため、テーブルキーワードTABLEを使用し、その後にUDTF名と引数を括弧で囲んで指定します。

以下の例では、my_java_udtfという名前のUDTFを、DATEリテラル'2021-01-16'を引数として呼び出しています。

sql
SELECT ...
  FROM TABLE(my_java_udtf('2021-01-16'::DATE));

UDFと同様に、UDTFの引数は名前または位置で指定することができます。

参考

https://docs.snowflake.com/en/sql-reference/udf-overview
https://docs.snowflake.com/en/developer-guide/udf/udf-creating-sql
https://docs.snowflake.com/en/sql-reference/sql/create-function
https://docs.snowflake.com/en/developer-guide/udf/udf-calling-sql

Ryusei Kakujo

researchgatelinkedingithub

Focusing on data science for mobility

Bench Press 100kg!