ユーザー定義関数(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は整数を返します。
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関数と同様に実行することができます。次の例では、addone
UDFを実行する方法を示しています。
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を作成するには、次の手順に従ってください。
-
UDFが呼び出されたときに実行されるハンドラコードを記述します。このハンドラにはUDFのロジックが含まれます。Java、JavaScript、Python、Scala、SQLなどのサポートされている言語のいずれかで記述することができます。
-
ハンドラコードを
CREATE FUNCTION
のSQL文内にインラインで保持するか、ステージ上で参照するかを選択します。この決定は、コードの複雑さや長さ、および組織のコード管理の慣行によります。 -
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ドキュメンテーションを参照してください。
SnowflakeでUDFを呼び出す
SnowflakeでUDFが作成された後は、他の関数と同様に呼び出すことができます。
UDFの呼び出し
UDFを呼び出す一般的な方法は、他の関数を呼び出す場合と同様です。UDF名の後に括弧を付け、UDFに引数がある場合は括弧内に指定します。引数は名前または位置で指定することができます。
次の例では、3つの文字列を連結するUDFを考えます。
CREATE OR REPLACE FUNCTION udf_concatenate_strings(
first VARCHAR,
second VARCHAR,
third VARCHAR)
RETURNS VARCHAR
LANGUAGE SQL
AS
$$
RETURN first || second || third;
$$;
UDFを呼び出す際には、引数を名前で指定することも、位置で指定することもできます。
SELECT udf_concatenate_strings(
first => 'one',
second => 'two',
third => 'three');
SELECT udf_concatenate_strings(
'one',
'two',
'three');
引数を指定する際には、全ての引数を名前で指定するか、位置で指定する必要があります。名前と位置の混合は使用できません。
UDTFの呼び出し
UDTFもUDFと同様に、名前を使用して呼び出されます。ただし、テーブルを返すため、テーブルキーワードTABLE
を使用し、その後にUDTF名と引数を括弧で囲んで指定します。
次の例では、my_java_udtf
という名前のUDTFを、DATEリテラル'2021-01-16'
を引数として呼び出しています。
SELECT ...
FROM TABLE(my_java_udtf('2021-01-16'::DATE));
UDFと同様に、UDTFの引数は名前または位置で指定することができます。
参考