Java UDF ハンドラーの例¶
このトピックには、Javaで記述された UDF ハンドラーコードの簡単な例が含まれています。
Javaを使用して UDF ハンドラーを作成する方法の詳細については、 Java UDF ハンドラーの作成 をご参照ください。
このトピックの内容:
単純なインラインJava UDF の作成と呼び出し¶
次のステートメントは、インラインJava UDF を作成して呼び出します。このコードは、渡された VARCHAR を返します。
この関数は、オプションの CALLED ON NULL INPUT
句を使用して宣言され、入力の値が NULL であっても関数が呼び出されることを示します。(この関数は、この句の有無にかかわらず NULL を返しますが、たとえば空の文字列を返すように、別の方法で NULL を処理するようにコードを変更できます。)
UDF を作成します。
create or replace function echo_varchar(x varchar)
returns varchar
language java
called on null input
handler='TestFunc.echoVarchar'
target_path='@~/testfunc.jar'
as
'class TestFunc {
public static String echoVarchar(String x) {
return x;
}
}';
UDF を呼び出します。
SELECT echo_varchar('Hello');
+-----------------------+
| ECHO_VARCHAR('HELLO') |
|-----------------------|
| Hello |
+-----------------------+
NULL のインラインJava UDF への引き渡し¶
これは、上記で定義された echo_varchar()
UDF を使用します。SQL NULL
値は暗黙的にJava null
に変換され、そのJava null
が返され、暗黙的に SQL NULL
に変換されます。
UDF を呼び出します。
SELECT echo_varchar(NULL);
+--------------------+
| ECHO_VARCHAR(NULL) |
|--------------------|
| NULL |
+--------------------+
配列値の受け渡し¶
Javaメソッドは、次に挙げる2つの方法のいずれかで SQL 配列を受け取ることができます。
Javaの配列機能を使用。
Javaの varargs (引数の数が可変)機能を使用。
どちらの場合も、 SQL コードは ARRAY を渡す必要があります。
注釈
必ず、 SQL 型への有効なマッピングを持つJava型を使用してください。詳細については、 SQL-Javaデータ型マッピング をご参照ください。
ARRAY 経由の引き渡し¶
Javaパラメーターを配列として宣言します。たとえば、次に挙げるメソッドの3番目のパラメーターは文字列配列です。
static int myMethod(int fixedArgument1, int fixedArgument2, String[] stringArray)
以下は包括的な例です。
テーブルを作成してロードします。
CREATE TABLE string_array_table(id INTEGER, a ARRAY); INSERT INTO string_array_table (id, a) SELECT 1, ARRAY_CONSTRUCT('Hello'); INSERT INTO string_array_table (id, a) SELECT 2, ARRAY_CONSTRUCT('Hello', 'Jay'); INSERT INTO string_array_table (id, a) SELECT 3, ARRAY_CONSTRUCT('Hello', 'Jay', 'Smith');UDF を作成します。
create or replace function concat_varchar_2(a ARRAY) returns varchar language java handler='TestFunc_2.concatVarchar2' target_path='@~/TestFunc_2.jar' as $$ class TestFunc_2 { public static String concatVarchar2(String[] strings) { return String.join(" ", strings); } } $$;UDF を呼び出します。
SELECT concat_varchar_2(a) FROM string_array_table ORDER BY id; +---------------------+ | CONCAT_VARCHAR_2(A) | |---------------------| | Hello | | Hello Jay | | Hello Jay Smith | +---------------------+
Varargs経由の引き渡し¶
Varargsの使用は、配列の使用と非常によく似ています。
Javaコードでは、Javaのvarargs宣言スタイルを使用します。
static int myMethod(int fixedArgument1, int fixedArgument2, String ... stringArray)
以下は包括的な例です。この例と前の例(配列の場合)の間における唯一の重要な違いは、メソッドへのパラメーター宣言です。
テーブルを作成してロードします。
CREATE TABLE string_array_table(id INTEGER, a ARRAY); INSERT INTO string_array_table (id, a) SELECT 1, ARRAY_CONSTRUCT('Hello'); INSERT INTO string_array_table (id, a) SELECT 2, ARRAY_CONSTRUCT('Hello', 'Jay'); INSERT INTO string_array_table (id, a) SELECT 3, ARRAY_CONSTRUCT('Hello', 'Jay', 'Smith');UDF を作成します。
create or replace function concat_varchar(a ARRAY) returns varchar language java handler='TestFunc.concatVarchar' target_path='@~/TestFunc.jar' as $$ class TestFunc { public static String concatVarchar(String ... stringArray) { return String.join(" ", stringArray); } } $$;UDF を呼び出します。
SELECT concat_varchar(a) FROM string_array_table ORDER BY id; +-------------------+ | CONCAT_VARCHAR(A) | |-------------------| | Hello | | Hello Jay | | Hello Jay Smith | +-------------------+
インライン UDF からの明示的な NULL の戻り¶
次のコードは、 NULL 値を明示的に返す方法を示しています。Java値 null
は SQL NULL
に変換されます。
UDF を作成します。
create or replace function return_a_null()
returns varchar
null
language java
handler='TemporaryTestLibrary.returnNull'
target_path='@~/TemporaryTestLibrary.jar'
as
$$
class TemporaryTestLibrary {
public static String returnNull() {
return null;
}
}
$$;
UDF を呼び出します。
SELECT return_a_null();
+-----------------+
| RETURN_A_NULL() |
|-----------------|
| NULL |
+-----------------+
OBJECT のインラインJava UDF への引き渡し¶
次の例では、 SQL OBJECT データ型と対応するJavaデータ型(Map<文字列,文字列>
)を使用し、 OBJECT から値を抽出します。この例は、Java UDF に複数のパラメーターを渡すことができることも示しています。
タイプ OBJECT の列を含むテーブルを作成してロードします。
CREATE TABLE objectives (o OBJECT);
INSERT INTO objectives SELECT PARSE_JSON('{"outer_key" : {"inner_key" : "inner_value"} }');
UDF を作成します。
create or replace function extract_from_object(x OBJECT, key VARCHAR)
returns variant
language java
handler='VariantLibrary.extract'
target_path='@~/VariantLibrary.jar'
as
$$
import java.util.Map;
class VariantLibrary {
public static String extract(Map<String, String> m, String key) {
return m.get(key);
}
}
$$;
UDF を呼び出します。
SELECT extract_from_object(o, 'outer_key'),
extract_from_object(o, 'outer_key')['inner_key'] FROM objectives;
+-------------------------------------+--------------------------------------------------+
| EXTRACT_FROM_OBJECT(O, 'OUTER_KEY') | EXTRACT_FROM_OBJECT(O, 'OUTER_KEY')['INNER_KEY'] |
|-------------------------------------+--------------------------------------------------|
| { | "inner_value" |
| "inner_key": "inner_value" | |
| } | |
+-------------------------------------+--------------------------------------------------+
GEOGRAPHY 値のインラインJava UDF への引き渡し¶
次の例では、 SQL GEOGRAPHY データ型を使用しています。
UDF を作成します。
create or replace function geography_equals(x geography, y geography)
returns boolean
language java
packages=('com.snowflake:snowpark:1.2.0')
handler='TestGeography.compute'
as
$$
import com.snowflake.snowpark_java.types.Geography;
class TestGeography {
public static boolean compute(Geography geo1, Geography geo2) {
return geo1.equals(geo2);
}
}
$$;
PACKAGES 句を使用して、 Snowparkパッケージ などのSnowflakeシステムパッケージを指定できます。その場合は、 IMPORTS 句の値としてSnowpark JAR ファイルを含める必要はありません。PACKAGES の詳細については、 CREATE FUNCTION オプションのパラメーター をご参照ください。
データを作成し、そのデータを使用して UDF を呼び出します。
create table geocache_table (id INTEGER, g1 GEOGRAPHY, g2 GEOGRAPHY);
insert into geocache_table (id, g1, g2) select
1, TO_GEOGRAPHY('POINT(-122.35 37.55)'), TO_GEOGRAPHY('POINT(-122.35 37.55)');
insert into geocache_table (id, g1, g2) select
2, TO_GEOGRAPHY('POINT(-122.35 37.55)'), TO_GEOGRAPHY('POINT(90.0 45.0)');
select id, g1, g2, geography_equals(g1, g2) as "EQUAL?"
from geocache_table
order by id;
出力は、次と類似したものになります。
+----+--------------------------------------------------------+---------------------------------------------------------+--------+
| ID | G1 | G2 | EQUAL? |
+----+--------------------------------------------------------|---------------------------------------------------------+--------+
| 1 | { "coordinates": [ -122.35, 37.55 ], "type": "Point" } | { "coordinates": [ -122.35, 37.55 ], "type": "Point" } | TRUE |
| 2 | { "coordinates": [ -122.35, 37.55 ], "type": "Point" } | { "coordinates": [ 90.0, 45.0 ], "type": "Point" } | FALSE |
+----+--------------------------------------------------------+---------------------------------------------------------+--------+
VARIANT 値のインラインJava UDF への引き渡し¶
SQL VARIANT 型の値をJava UDF に渡すと、Snowflakeはその値を Snowparkパッケージ で提供される バリアント 型に変換できます。 Variant
は、Snowparkパッケージバージョン1.4.0以降でサポートされていることに注意してください。
Snowpark Variant
型は、 Variant
型と他のタイプの間で値を変換するためのメソッドを提供します。
Snowpark Variant
型を使用するには、 PACKAGES 句を使用して、 UDF を作成するときにSnowparkパッケージを指定します。その場合は、 IMPORTS 句の値としてSnowpark JAR ファイルを含める必要はありません。PACKAGES の詳細については、 CREATE FUNCTION オプションのパラメーター をご参照ください。
次の例のコードは、 VARIANT 型として保存された JSON データを受け取り、Snowparkライブラリの Variant
型を使用して、 JSON から price
値を取得します。受信した JSON は、 例で使用されるサンプルデータ に表示されている JSON と同様の構造になっています。
create or replace function retrieve_price(v variant)
returns integer
language java
packages=('com.snowflake:snowpark:1.4.0')
handler='VariantTest.retrievePrice'
as
$$
import java.util.Map;
import com.snowflake.snowpark_java.types.Variant;
public class VariantTest {
public static Integer retrievePrice(Variant v) throws Exception {
Map<String, Variant> saleMap = v.asMap();
int price = saleMap.get("vehicle").asMap().get("price").asInt();
return price;
}
}
$$;
Java UDF を使用したファイルの読み取り¶
ハンドラーコードを使用してファイルの内容を読み取ることができます。たとえば、ハンドラーを使用してファイルを読み取り、非構造化データを処理する場合があります。非構造化データの処理とサンプルコードに関する詳細については、 UDF およびプロシージャハンドラーを使用した非構造化データの処理 をご参照ください。
ファイルは、ハンドラーが使用できるSnowflakeのステージである必要があります。
ステージングされたファイルのコンテンツを読み取るために、ハンドラーは次を実行できます。
ファイルパスが IMPORTS 句で静的に指定されている ファイルを読み取ります。実行時に、コードは UDF のホームディレクトリからファイルを読み取ります。
これは、初期化中にファイルにアクセスする場合に役立つ可能性があります。
SnowflakeFile
クラスまたはInputStream
クラスのいずれかのメソッドを呼び出して、動的に指定されたファイルを読み取ります。呼び出し元が指定したファイルにアクセスする必要があるときには、この操作を実行する場合があります。詳細については、このトピック内で次をご参照ください。
SnowflakeFile
は、次のテーブルで説明されているように、InputStream
では利用できない機能を提供します。クラス
入力
メモ
SnowflakeFile
URL フォーマット:
関数の呼び出し元がその所有者でもない場合に、ファイルインジェクション攻撃のリスクを軽減するためのスコープ URL を設定しました。
ファイル URL または UDF 所有者がアクセス権を持っているファイルの文字列パス。
ファイルは、名前付き内部ステージまたは外部ステージに配置されている必要があります。
ファイルサイズなど、追加のファイル属性に簡単にアクセスできます。
InputStream
URL フォーマット:
関数の呼び出し元がその所有者でもない場合に、ファイルインジェクション攻撃のリスクを軽減するためのスコープ URL を設定しました。
ファイルは、内部または外部ステージに配置する必要があります。
前提条件¶
ファイルをコードで使用できるようにするには、Javaハンドラーコードがステージ上のファイルを読み取る前に、次を実行する必要があります。
ハンドラーが使用できるステージを作成する。
外部ステージまたは内部ステージを使用できます。内部ステージを使用する場合は、ユーザーまたは名前付きステージにする必要があります。Snowflakeは現在、 UDF 依存関係のテーブルステージの使用をサポートしていません。ステージの作成の詳細については、 CREATE STAGE をご参照ください。内部ステージ型の選択の詳細については、 ローカルファイルに対する内部ステージの選択 をご参照ください。
ステージから読み取る SQL アクションを実行するロールには、ステージに対する適切な権限を割り当てる必要があることに注意してください。詳細については、 Granting Privileges for User-Defined Functions をご参照ください。
ステージに、コードで読み取られるファイルをコピーする。
PUT コマンドを使用して、ファイルをローカルドライブからステージにコピーできます。コマンドリファレンスについては、 PUT をご参照ください。PUT を使用したファイルのステージングについては、 ローカルファイルシステムからのデータファイルのステージング をご参照ください。
IMPORTS で静的に指定されたファイルの読み取り¶
ハンドラーは、ステージングされたパスが CREATE FUNCTION コマンドの IMPORTS 句で指定されているファイルを読み取ることができます。
IMPORTS 句でファイルを指定すると、Snowflakeはそのファイルをステージから UDF の ホームディレクトリ (別称 インポートディレクトリ)にコピーします。UDF は、ホームディレクトリから実際にファイルを読み取ります。
インポートされたファイルは単一のディレクトリにコピーされ、そのディレクトリ内で一意の名前を付ける必要があるため、ファイルが異なるステージまたはステージ内の異なるサブディレクトリで開始された場合でも、 IMPORTS 句の各ファイルに異なる名前を付ける必要があります。
次の例では、ファイルを読み取るJava UDF を作成して呼び出します。
以下のJavaソースコードは、 readFile
という名前のJavaメソッドを作成します。この UDF はこのメソッドを使用します。
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.stream.Stream;
class TestReadRelativeFile {
public static String readFile(String fileName) throws IOException {
StringBuilder contentBuilder = new StringBuilder();
String importDirectory = System.getProperty("com.snowflake.import_directory");
String fPath = importDirectory + fileName;
Stream<String> stream = Files.lines(Paths.get(fPath), StandardCharsets.UTF_8);
stream.forEach(s -> contentBuilder.append(s).append("\n"));
return contentBuilder.toString();
}
}
次の SQL コードは UDF を作成します。このコードは、Javaソースコードがコンパイルされ、 UDF がインポートする TestReadRelativeFile.jar
という名前の JAR ファイルに配置されていることを前提としています。2番目と3番目のインポートされたファイル my_config_file_1.txt
と my_config_file_2.txt
は、 UDF が読み取ることができる構成ファイルです。
CREATE FUNCTION file_reader(file_name VARCHAR)
RETURNS VARCHAR
LANGUAGE JAVA
IMPORTS = ('@my_stage/my_package/TestReadRelativeFile.jar',
'@my_stage/my_path/my_config_file_1.txt',
'@my_stage/my_path/my_config_file_2.txt')
HANDLER = 'my_package.TestReadRelativeFile.readFile';
このコードは UDF を呼び出します。
SELECT file_reader('my_config_file_1.txt') ...;
...
SELECT file_reader('my_config_file_2.txt') ...;
圧縮形式または非圧縮形式のどちらでファイルにアクセスするかを選択¶
ステージ内のファイルは、圧縮形式または非圧縮形式で保存できます。ユーザーは、ファイルをステージにコピーする前に圧縮するか、 PUT コマンドにファイルを圧縮するように指示できます。
Snowflakeが GZIP 形式で圧縮されたファイルをステージから UDF ホームディレクトリにコピーする場合、Snowflakeはコピーをそのまま書き込むか、Snowflakeはファイルを書き込む前にコンテンツを解凍できます。
ステージ内のファイルが圧縮されていて、 UDF ホームディレクトリのコピーも圧縮する場合は、 IMPORTS 句でファイル名を指定するときに、元のファイル名(例:「MyData.txt.gz」)を IMPORTS サブ句で使用します。例:
... imports = ('@MyStage/MyData.txt.gz', ...)
ステージ内のファイルが GZIP 圧縮されているが、 UDF ホームディレクトリのコピーを解凍したい場合は、 IMPORTS 句でファイル名を指定するときに、「.gz」拡張子を省略します。たとえば、ステージに「MyData.txt.gz」が含まれているが、 UDF に非圧縮形式でファイルを読み取らせたい場合は、 IMPORTS 句に「MyData.txt」を指定します。「MyData.txt」という名前の非圧縮ファイルがまだない場合、Snowflakeは「MyData.txt.gz」を検索し、解凍したコピーを UDF ホームディレクトリの「MyData.txt」に自動で書き込みます。UDF は、圧縮されていないファイル「MyData.txt」を開いて読み取ることができます。
スマート解凍は、 UDF ホームディレクトリ内のコピーにのみ適用されます。ステージ内の元のファイルは変更されません。
圧縮ファイルを処理するための次のベストプラクティスに従ってください。
適切なファイル名の規則に従う。ファイルが GZIP 圧縮形式の場合は、ファイル名の末尾に拡張子「.gz」を含める。ファイルが GZIP 圧縮形式でない場合は、ファイル名を「.gz」拡張子で終わらせない。
拡張子「.gz」だけが異なる名前のファイルは作成しない。たとえば、同じステージとディレクトリに「MyData.txt」と「MyData.txt.gz」の両方を作成することや、「MyData.txt」と「MyData.txt.gz」の両方を CREATE FUNCTION コマンドにインポートすることは避けてください。
ファイルを2回圧縮しない。たとえば、ファイルを手動で圧縮した後、 AUTO_COMPRESS = FALSE を使用せずにそのファイルを PUT すると、ファイルはもう一度圧縮されます。スマート解凍では1回だけ解凍されるため、データ(または JAR)ファイルが UDF ホームディレクトリに保存されるときには、引き続き圧縮されたままになります。
将来、Snowflakeは、スマート解凍を GZIP 以外の圧縮アルゴリズムに拡張する可能性があります。将来の互換性の問題を防ぐために、これらのベストプラクティスを任意のタイプの圧縮を使用するファイルに適用してください。
注釈
JAR ファイルは、圧縮または非圧縮形式でステージに保存することもできます。Snowflakeは、圧縮されたすべての JAR ファイルを自動的に解凍してから、Java UDF で使用できるようにします。
SnowflakeFile
を使用した動的に指定されたファイルの読み取り¶
SnowflakeFile
クラスのメソッドを使用すると、Javaハンドラーコードを使用してステージからファイルを読み取ることができます。 SnowflakeFile
クラスは、SnowflakeのJava UDF ハンドラーが使用できるクラスパスに含まれています。
注釈
ファイルインジェクション攻撃に対するコードの回復性を高めるには、ファイルの場所を UDF に渡す場合、特に関数の呼び出し元がその所有者でもない場合に、スコープ URL を常に使用します。組み込み関数 BUILD_SCOPED_FILE_URL を使用して、スコープ URL を SQL に作成できます。BUILD_SCOPED_FILE_URL の機能の詳細については、 非構造化データの概要 をご参照ください。
UDF コードをローカルで開発するには、 SnowflakeFile
を含んでいるSnowpark JAR をコードのクラスパスに追加します。 snowpark.jar
については、 Snowpark Javaの開発環境の設定 をご参照ください。Snowparkクライアントアプリケーションは、このクラスを使用できないことに注意してください。
SnowflakeFile
を使用する場合は、 SQL で CREATE FUNCTION ステートメントを使用する場合のように、 UDF の作成時に、ステージングされたファイル、または SnowflakeFile
を含んでいる JAR のいずれかを IMPORTS 句で指定する必要はありません。
次の例のコードは、 SnowflakeFile
を使用して、指定されたステージの場所からファイルを読み取ります。 getInputStream
メソッドの InputStream
を使用して、ファイルの内容を String
変数に読み込みます。
CREATE OR REPLACE FUNCTION sum_total_sales(file string)
RETURNS INTEGER
LANGUAGE JAVA
HANDLER = 'SalesSum.sumTotalSales'
TARGET_PATH = '@jar_stage/sales_functions2.jar'
AS
$$
import java.io.InputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import com.snowflake.snowpark_java.types.SnowflakeFile;
public class SalesSum {
public static int sumTotalSales(String filePath) throws IOException {
int total = -1;
// Use a SnowflakeFile instance to read sales data from a stage.
SnowflakeFile file = SnowflakeFile.newInstance(filePath);
InputStream stream = file.getInputStream();
String contents = new String(stream.readAllBytes(), StandardCharsets.UTF_8);
// Omitted for brevity: code to retrieve sales data from JSON and assign it to the total variable.
return total;
}
}
$$;
UDF を呼び出してスコープ URL でファイルの場所を渡し、ファイルインジェクション攻撃の可能性を減らします。
SELECT sum_total_sales(BUILD_SCOPED_FILE_URL('@sales_data_stage', '/car_sales.json'));
注釈
UDF 所有者は、場所がスコープ付き URLs ではないファイルへのアクセス権を持っている必要があります。新しい requireScopedUrl
パラメーターに boolean
値を指定して SnowflakeFile.newInstance
メソッドを呼び出すハンドラーコードにより、これらのステージングされたファイルを読み取ることができます。
次の例では、スコープ付き URL が不要であることを指定し、 SnowflakeFile.newInstance
を使用します。
String filename = "@my_stage/filename.txt";
String sfFile = SnowflakeFile.newInstance(filename, false);
InputStream
を使用した動的に指定されたファイルの読み取り¶
ハンドラー関数の引数を InputStream
変数にすると、ファイルの内容を直接 java.io.InputStream
に読み込むことができます。これは、関数の呼び出し元が引数としてファイルパスを渡す場合に役立ちます。
注釈
ファイルインジェクション攻撃に対するコードの回復性を高めるには、ファイルの場所を UDF に渡す場合、特に関数の呼び出し元がその所有者でもない場合に、スコープ URL を常に使用します。組み込み関数 BUILD_SCOPED_FILE_URL を使用して、スコープ URL を SQL に作成できます。BUILD_SCOPED_FILE_URL の機能の詳細については、 非構造化データの概要 をご参照ください。
次の例のコードには、 InputStream
を受け取り、 int
を返すハンドラー関数 sumTotalSales
があります。実行時に、Snowflakeは file
変数のパスにあるファイルの内容を stream
引数変数に自動で割り当てます。
CREATE OR REPLACE FUNCTION sum_total_sales(file string)
RETURNS INTEGER
LANGUAGE JAVA
HANDLER = 'SalesSum.sumTotalSales'
TARGET_PATH = '@jar_stage/sales_functions2.jar'
AS
$$
import java.io.InputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
public class SalesSum {
public static int sumTotalSales(InputStream stream) throws IOException {
int total = -1;
String contents = new String(stream.readAllBytes(), StandardCharsets.UTF_8);
// Omitted for brevity: code to retrieve sales data from JSON and assign it to the total variable.
return total;
}
}
$$;
UDF を呼び出してスコープ URL でファイルの場所を渡し、ファイルインジェクション攻撃の可能性を減らします。
SELECT sum_total_sales(BUILD_SCOPED_FILE_URL('@sales_data_stage', '/car_sales.json'));
ステージングされた簡単なJava UDF の作成と呼び出し¶
次のステートメントは、単純なJava UDF を作成します。このサンプルは通常、 ファイルの整理 で説明されているファイルとディレクトリの構造に従います。
Javaハンドラーコードを作成しコンパイルする¶
プロジェクトのルートディレクトリ(ここでは
my_udf
)に、ソース.javaファイルを保持するsrc
サブディレクトリと、生成された.classファイルを保持するclasses
サブディレクトリを作成します。次のようなディレクトリ階層が必要です。
my_udf/ |-- classes/ |-- src/
src
ディレクトリに、クラスがmypackage
パッケージにある.javaファイルを保持する、mypackage
というディレクトリを作成します。mypackage
ディレクトリに、ソースコードを含むMyUDFHandler.java
ファイルを作成します。package mypackage; public class MyUDFHandler { public static int decrementValue(int i) { return i - 1; } public static void main(String[] argv) { System.out.println("This main() function won't be called."); } }
プロジェクトのルートディレクトリ(ここでは
my_udf
)から、javac
コマンドを使用してソースコードをコンパイルします。次の例の
javac
コマンドは、MyUDFHandler.java
をコンパイルして、classes
ディレクトリにMyUDFHandler.class
ファイルを生成します。javac -d classes src/mypackage/MyUDFHandler.java
この例には、次の引数が含まれています。
-d classes
--- 生成されたクラスファイルを書き込むディレクトリ。src/mypackage/MyUDFHandler.java
--- .javaファイルへのsource_directory/package_directory/Java_file_name
形式のパス。
コンパイルされたコードを JAR ファイルにパッケージ化する¶
オプションで、プロジェクトのルートディレクトリに、次の属性を含む
my_udf.manifest
という名前のマニフェストファイルを作成します。Manifest-Version: 1.0 Main-Class: mypackage.MyUDFHandler
プロジェクトのルートディレクトリから、
jar
コマンドを実行して、.classファイルとマニフェストを含む JAR ファイルを作成します。次の例の
jar
コマンドは、mypackage
パッケージフォルダーに生成されたMyUDFHandler.class
ファイルをmy_udf.jar
という.jarファイルに配置します。-C ./classes
フラグは、.classファイルの場所を指定します。jar cmf my_udf.manifest my_udf.jar -C ./classes mypackage/MyUDFHandler.class
この例には、次の引数が含まれています。
cmf
--- コマンド引数:c
は JAR ファイルを作成し、m
は指定された.manifestファイルを使用し、f
は JAR ファイルに指定された名前を付けます。my_udf.manifest
--- マニフェストファイル。my_udf.jar
--- 作成する JAR ファイルの名前。-C ./classes
--- 生成された.classファイルを含むディレクトリ。mypackage/MyUDFHandler.class
--- JAR に含める.classファイルのパッケージと名前。
コンパイルされたハンドラーを使用して JAR ファイルをステージにアップロードする¶
Snowflakeで、 UDF ハンドラーを含む JAR ファイルを保存するために、
jar_stage
というステージを作成します。ステージの作成の詳細については、 CREATE STAGE をご参照ください。
PUT
コマンドを使用して、 JAR ファイルをローカルファイルシステムからステージにコピーします。
put file:///Users/Me/my_udf/my_udf.jar @jar_stage auto_compress = false overwrite = true ;
PUT
コマンドをスクリプトファイルに保存してから、 SnowSQL を介してそのファイルを実行できます。
snowsql
コマンドは次のようになります。snowsql -a <account_identifier> -w <warehouse> -d <database> -s <schema> -u <user> -f put_command.sqlこの例では、ユーザーのパスワードが SNOWSQL_PWD 環境変数で指定されていることを前提としています。
コンパイルされたコードをハンドラーとして UDF を作成する¶
UDF を作成します。
create function decrement_value(i numeric(9, 0))
returns numeric
language java
imports = ('@jar_stage/my_udf.jar')
handler = 'mypackage.MyUDFHandler.decrementValue'
;
UDF を呼び出します。
select decrement_value(-15);
+----------------------+
| DECREMENT_VALUE(-15) |
|----------------------|
| -16 |
+----------------------+