Java UDFs の作成

このトピックでは、Javaユーザー定義関数(UDF)を作成してインストールする方法を示します。

Java UDF を記述するときは、Snowflakeが UDF ロジックとして実行するためのSnowflake用Javaコードを記述します。このJavaコードは UDF のハンドラーです。UDF を CREATE FUNCTION で展開し、 UDF に名前を付け、 UDF が呼び出されたときに使用するハンドラーとしてJavaメソッドを指定します。

その他のサンプルコードについては、 Java UDF ハンドラーの例 をご参照ください。

このトピックの内容:

Javaでの UDF ハンドラーの記述

Java UDF ハンドラーを記述するときは、次の要件とガイドラインを使用します。

  • クラスを公開として定義します。

  • クラス内で、 UDF ハンドラーとして使用するパブリックメソッドを少なくとも1つ宣言します。

    インライン UDF の場合は、1つのハンドラーメソッドのみを宣言します。代わりに、クラスを プリコンパイル済み UDF として JAR にパッケージ化する場合は、複数のハンドラーメソッドを宣言し、後で CREATE FUNCTION ステートメントの HANDLER 句を使用して、それぞれをハンドラーとして指定できます。

    必要に応じて、ハンドラーメソッドによって呼び出される他のメソッドを宣言できます。

    各ハンドラーメソッドについては、次の要件とガイドラインを使用します。

    • ハンドラーメソッドを静的または非静的のパブリックとして宣言します。

      メソッドが非静的である場合、クラスは引数なしのコンストラクターを宣言するか、コンストラクターを一切なしにする必要があります。

      Snowflakeは、クラスをインスタンス化するときにコンストラクターに引数を渡しません。コンストラクターがエラーをスローすると、エラーは例外メッセージとともにユーザーエラーとしてスローされます。

    • 適切な戻り型を指定します。

      戻り型は、 SQL-Java型マッピングテーブルJava Data Type 列で指定されたデータタイプの1つである必要があります。戻り型は、 CREATE FUNCTION ステートメントの RETURNS 句で指定された SQL データ型と互換性がある必要があります。

    • 各ハンドラーメソッド引数(存在する場合)が、 SQL-Java型マッピングテーブルJava Data Type 列で指定されたデータ型であることを確認します。

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

    • 各ハンドラーメソッドとそれが呼び出すメソッドで、 Java UDFs に対するSnowflakeによる制約 に準拠します。

Snowflakeでの関数の作成

このセクションの情報は、コードが インライン または プリコンパイル済み のどちらで指定されているかに関係なく、すべてのJava UDFs に適用されます。

以下を含む UDF の側面を指定するために、 CREATE FUNCTION ステートメントを実行する必要があります。

  • UDF の名前。

  • UDF が呼び出されたときに、Snowflakeがハンドラーとして呼び出すJavaメソッドの名前。

UDF の名前は、Javaで記述されたハンドラーメソッドの名前と一致する必要はありません。CREATE FUNCTION ステートメントは、次の図に示すように、 UDF 名をJavaメソッドに関連付けます。

Using the CREATE FUNCTION Statement to Associate the Handler Method With the UDF Name

UDF の名前を選択する場合は、

  • オブジェクト識別子 のルールに従います。

  • 一意の名前を選択するか、 UDF名のオーバーロード のルールに従います。

    重要

    引数の数とデータ型の両方に基づいて関数を区別する SQL UDFs のオーバーロードとは異なり、Java UDFs は、引数の数 のみ に基づいてメソッドを区別します。2つのJavaメソッドの名前と引数の数が同じで、データ型が異なる場合、これらのメソッドの1つをハンドラーとして使用して UDF を呼び出すと、次のようなエラーが生成されます。

    ハンドラー <クラス名>.<ハンドラー名> を使用する関数 <ユーザー定義関数名> に <引数の数> 引数の定義が複数あるため、呼び出すハンドラー「ハンドラー名」の実装を決定できません。

    ウェアハウスが使用可能な場合は、 UDF の作成時にエラーが検出されます。それ以外の場合は、 UDF が呼び出されたときにエラーが発生します。

    一部の SQL データ型は複数のJavaデータ型にマップでき、したがって複数のJava UDF 署名にマップできる可能性があるため、データ型に基づいて解決することは実用的ではありません。

ハンドラーメソッド引数は、名前ではなく位置によって UDF 引数にバインドされます。つまり、最初の UDF 引数は最初のメソッド引数に渡され、2番目の UDF 引数は2番目のメソッド引数に渡されます。

たとえば、以下のコード例では、 SQL UDF 引数 x はJavaメソッド引数 a に対応し、 yb に対応します。

create function add_int_float(x numeric(9, 0), y float)
returns float
language java
handler = 'MyClass.addIntFloat';
public static float addIntFloat(int a, float b) {
  // ...
}

引数のデータ型については、 パラメーターと戻り値型の SQL-Javaデータ型のマッピング をご参照ください。

注釈

スカラー関数(UDFs)には、入力引数に500個の制限があります。

CREATE FUNCTION ステートメントの RUNTIME_VERSION パラメーターを使用して、サポートされているJavaランタイムバージョンを指定することをお勧めします。これは、デフォルトバージョンが将来変更される可能性があるためです。

インライン UDFs とプリコンパイル済み UDFs

次のいずれかの方法で、Java UDF ハンドラーを定義できます。

  • プリコンパイル済み。コンパイル済みJavaハンドラーを JAR にパッケージ化し、Snowflakeが読み取れる場所に配置します。

    CREATE FUNCTION ステートメントは、ハンドラーを含む JAR ファイルの場所を指定します。CREATE FUNCTION を実行する前に、 JAR ファイルをSnowflakeが読み取れる ステージ にコピーします。

  • インライン。UDF 宣言自体にJavaコードを含めます。

    CREATE FUNCTION ステートメント自体が、Javaソースコードを指定します。Snowflakeはソースコードをコンパイルし、コンパイルされたコードを JAR ファイルに保存します。CREATE FUNCTION を実行するときに、 TARGET_PATH 句を使用して結果の JAR ファイルの場所を指定できます。

    • CREATE FUNCTION が JAR ファイルの場所を指定する場合、Snowflakeはコードを1回コンパイルし、将来の使用のために JAR ファイルを保持します。

    • CREATE FUNCTION が JAR ファイルの場所を指定しない場合、Snowflakeは UDF を呼び出す各 SQL ステートメントのコードを再コンパイルし、Snowflakeは SQL ステートメントの終了後に JAR ファイルを自動的にクリーンアップします。

実用的な違い

インラインJava UDF の利点

  • 通常、実装は簡単です。開発ツールを使用してコードが正常に機能することを検証した後、コードを CREATE FUNCTION ステートメントにコピーしてから、ステートメントを実行することでコードを展開できます。コンパイルされた出力を JAR に個別に再パッケージ化してステージ上で更新しなくても、そこでコードを維持し、 CREATE FUNCTION を更新して実行できます。

コンパイル済みJava UDF の利点

  • JAR ファイルはあっても、ソースコードがない場合に使用できます。

  • ソースコードが大きすぎて CREATE FUNCTION ステートメントに貼り付けられない場合に使用できます。(インラインJava UDFs には、ソースコードサイズの上限があります。)

  • プリコンパイル済みJava UDF には、複数のハンドラー関数を含めることができます。複数の CREATE FUNCTION ステートメントは同じ JAR ファイルを参照できますが、 JAR ファイル内で異なるハンドラー関数を指定します。

    インラインJava UDFs には通常、呼び出し可能な関数が1つだけ含まれています。(その呼び出し可能関数は他の関数を呼び出すことができ、それらの他の関数は同じクラスで定義することも、ライブラリ JAR ファイルで定義された他のクラスで定義することもできます。)

  • JAR ファイルをテストまたはデバッグするためのツールまたは環境がある場合は、 JAR ファイルを使用して UDF でほとんどの開発作業をする方が便利な場合があります。これは、コードが大きいか複雑な場合に特に当てはまります。

クラスパスへの依存関係の追加

ハンドラーコードで外部 JAR ファイルにパッケージ化されたクラスが必要な場合は、ハンドラーで使用可能なSnowflake管理のクラスパスにこれらの依存関係を追加できます。次に、Java UDF ハンドラーに表示されるクラスパスに JAR ファイルを追加する方法について説明します。

  1. ハンドラーが使用できるステージを作成する。

    UDF 依存関係には、外部ステージまたは内部ステージを使用できます。内部ステージを使用する場合は、ユーザーまたは名前付きステージにする必要があります。Snowflakeは現在、 UDF 依存関係のテーブルステージの使用をサポートしていません。ステージの作成の詳細については、 CREATE STAGE をご参照ください。内部ステージ型の選択の詳細については、 ローカルファイルに対する内部ステージの選択 をご参照ください。

  2. 依存関係 JAR をステージにコピーする。

    PUT コマンドを使用して、ローカルドライブからステージに JAR をコピーできます。コマンドリファレンスについては、 PUT をご参照ください。PUT を使用したファイルのステージングについては、 ローカルファイルシステムからのデータファイルのステージング をご参照ください。

  3. UDF を作成するときに、依存関係 JAR を参照する。

    CREATE FUNCTION を実行して UDF を作成するときは、すべての依存関係 JAR ファイルのステージ場所およびファイルのパスと名前を IMPORTS 句の値として指定します。実行時に、Snowflakeは JAR をクラスパスに追加します。参照情報については、 CREATE FUNCTION をご参照ください。

    次の例のコードは、 my_udf という UDF を作成し、ステージ @mystage への my_handler_dependency.jar 依存関係を指定します。

    CREATE FUNCTION my_udf(i NUMERIC)
      RETURNS NUMERIC
      LANGUAGE JAVA
      IMPORTS = ('@mystage/dependencies/my_handler_dependency.jar')
      HANDLER = 'MyClass.myFunction'
      AS
      $$
        // Handler code omitted.
      $$
    

インラインJava UDF の作成

インライン UDF の場合、 CREATE FUNCTION ステートメントの一部としてJavaソースコードを指定します。

Javaソースコードを AS 句に入れ、コードを一重引用符またはドル記号のペア($$)で囲みます。ソースコードに一重引用符が埋め込まれている場合などでは、二重ドル記号を使用する方が簡単な場合があります。

次の例のコードは、ハンドラーが TestAddFunc クラスの add メソッドである add UDF を宣言しています。

create function add(x integer, y integer)
returns integer
language java
handler='TestAddFunc.add'
target_path='@~/TestAddFunc.jar'
as
$$
    class TestAddFunc {
        public static int add(int x, int y) {
          return x + y;
        }
    }
$$;

Javaソースコードには、複数のクラスとクラス内の複数のメソッドを含めることができるため、 HANDLER 句は、ハンドラーとして使用するクラスとメソッドを指定します。

インラインJava UDF (プリコンパイル済みJava UDF など)は、 CREATE FUNCTION ステートメントの IMPORTS 句に含まれる JAR ファイルのコードを呼び出すことができます。

CREATE FUNCTION ステートメントの構文の詳細については、 CREATE FUNCTION をご参照ください。

その他の例については、 Java UDF ハンドラーの例 をご参照ください。

プリコンパイル済みJava UDF の作成

ハンドラーに対する既存の JAR の場所を指定する UDF を作成する場合は、次の方法でハンドラーを開発します。

ファイルの整理

Javaコードをコンパイルして JAR ファイルを自分で作成する場合は、以下に示すようにファイルを整理できます。この例では、Javaのパッケージメカニズムの使用が予定されていることを前提としています。

  • developmentDirectory

    • packageDirectory

      • class_file1.java

      • class_file2.java

    • classDirectory

      • class_file1.class

      • class_file2.class

    • manifest_file.manifest(オプション)

    • jar_file.jar

    • put_command.sql

developmentDirectory

このディレクトリには、Java UDF の作成に必要なプロジェクト固有のファイルが含まれています。

packageDirectory

このディレクトリには、コンパイルしてパッケージに含める.javaファイルが含まれています。

class_file#.java

これらのファイルには、 UDF のJavaソースコードが含まれています。

class_file#.class

これらは、.javaファイルをコンパイルすることによって作成された.classファイルです。

manifest_file.manifest

.classファイル(およびオプションで依存関係 JAR ファイル)を JAR ファイルに結合するときに使用される、オプションのマニフェストファイル。

jar_file.jar

UDF コードを含んだ JAR ファイル。

put_command.sql

このファイルには、JAR ファイルをSnowflake ステージ にコピーするための SQL PUT コマンドが含まれています。

Javaコードのコンパイルと JAR ファイルの作成

コンパイルされたJavaコードを含んだ JAR ファイルを作成するには、

  • javacを使用して、.javaファイルを.classファイルにコンパイルします。

    バージョン11.xより新しいコンパイラを使用する場合は、「-release」オプションを使用して、ターゲットバージョンがバージョン11であることを指定できます。

  • .classファイルを JAR ファイルに配置します。複数のクラスファイル(およびその他の JAR ファイル)を JAR ファイルにパッケージ化できます。

    例:

    jar cf ./my_udf.jar MyClass.class
    

    ハンドラークラスがパッケージに含まれている場合はマニフェストファイルが必要であり、そうでない場合はオプションです。次の例では、マニフェストファイルを使用しています。

    jar cmf my_udf.manifest ./my_udf.jar example/MyClass.class
    

    すべての依存関係が含まれているjarファイルをビルドするには、maven-assembly-pluginでMavenの mvn package コマンドを使用できます。maven-assembly-pluginの詳細については、 Mavenの使用方法のページ をご参照ください。

    Snowflakeは、 標準のJavaライブラリ (例: java.util)を自動的に提供します。コードでこれらのライブラリを呼び出す場合は、 JAR ファイルに含める必要はありません。

    ライブラリで呼び出すメソッドは、Javaメソッドと同じ Snowflakeによる制約 に従う必要があります。

JAR ファイルのステージへのコピー

Snowflakeがハンドラーメソッドを含む JAR から読み取るには、 JAR を次に挙げる種類のステージのいずれかにコピーする必要があります。

  • ユーザーまたは名前付き内部ステージ。

    Snowflakeは現在、テーブルステージを使用して UDF ハンドラーを含む JAR ファイルを格納することをサポートしていません。内部ステージの詳細については、 ローカルファイルに対する内部ステージの選択 をご参照ください。

  • 外部ステージ。

JAR ファイルをホストするステージは、 UDF の 所有者 によって読み取り可能である必要があります。

通常、 PUT コマンドを使用して、名前付き内部ステージに JAR をアップロードします。Snowflake GUI を介して PUT コマンドを実行することはできないことに注意してください。 SnowSQL を使用して PUT を実行できます。.jarファイルをステージにコピーするための PUT コマンドの例については、 Java UDF ハンドラーの例 セクションをご参照ください。

ステージの作成の詳細については、 CREATE STAGE をご参照ください。

警告とベストプラクティス

JAR ファイルを削除または名前変更すると、 UDF を呼び出すことができなくなります。

JAR ファイルを更新する必要がある場合は、次を実行します。

  • UDF の呼び出しができない間に更新します。

  • 古い.jarファイルがまだステージにある場合、 PUT コマンドには OVERWRITE=TRUE 句を含める必要があります。

注釈

UDFs に関連して実行するユーザーには、アクションに必要な権限が割り当てられたロールが必要です。詳細については、 ユーザー定義関数の権限の付与 をご参照ください。

最上部に戻る