Java UDF
Java UDFとは、Java言語で実装されたユーザー定義関数(User-Defined Function)のことです。Java UDFをサポートすることで、豊富なJavaエコシステム製品をOceanBaseデータベースに統合し、UDFの開発効率を向上させることができます。
Java UDF関数の作成
以下のコードをコンパイルしてmy_add.jarとしてパッケージ化すると、OBServerでJava UDFを作成できます。例:
package org.example;
public class MyAdd {
public Integer evaluate(Integer a, Integer b) {
if (a == null || b == null) {
return null;
}
return a + b;
}
}
Java UDFの作成
Java UDFの使用シナリオの柔軟性に対応するため、URLと外部リソースの2つの方法でJava UDFを作成できます。
URLからJava UDFを作成する
以下のSQLステートメントを実行して、my_add という名前のJava UDFを作成します。
CREATE FUNCTION my_add(x int, y int)
RETURNS int
PROPERTIES (
symbol = 'org.example.MyAdd',
type = 'odpsjar',
file = '<URL to Jar>'
);
ここで:
symbol:指定されたエントリクラス名を表します。type:外部UDFのタイプを表します。現在、odpsjar、UDAFJar、UDTFJar、Pythonをサポートしています。file:Jarパッケージが配置されているURLを表します。
作成が成功すると、PL UDFのようにJava UDFを使用できます。使用例は以下のとおりです:
obclient> CREATE FUNCTION my_add(x int, y int)
-> RETURNS int
-> PROPERTIES (
-> symbol = 'org.example.MyAdd',
-> type = 'odpsjar',
-> file = 'http://******/my_add.jar'
-> );
Query OK, 0 rows affected (0.113 sec)
obclient> SELECT my_add(1, 2);
+--------------+
| my_add(1, 2) |
+--------------+
| 3 |
+--------------+
1 row in set (0.021 sec)
外部リソースを使用したJava UDFの作成
OBServerは、Java UDF Jarパッケージなど外部ストアドプロシージャの依存リソースを外部リソースとして管理します。JarパッケージはDBMS_JAVA.LOADJAVAシステムパッケージ関数を使用してOBServerにアップロードし、作成したJava UDFでこのJarパッケージに対応する外部リソースを参照します。
外部リソースのアップロードとUDFの作成には厳密な順序要件はありません。UDFが呼び出される時点でリソースがアップロード済みであればよいのです。また、1つの外部リソースは複数のUDFで使用できます。
操作手順は以下のとおりです:
Jarパッケージのアップロード
DBMS_JAVA.LOADJAVAを呼び出し、Jarパッケージを外部リソースとしてOBServerにアップロードします。String url = "<URL to Jar>"; InputStream is = new URL(url).openStream(); // conn is a connection to OceanBase PreparedStatement ps = conn.prepareStatement("call dbms_java.loadjava(? ,? ,? )"); ps.setString(1, "my_add_jar"); ps.setBlob(2, is); ps.setString(3, "my add UDF jar"); ps.execute();Java UDFの作成
以下のSQLステートメントを実行して、my_addという名前のJava UDFを作成します。
CREATE FUNCTION my_add(x int, y int) RETURNS int PROPERTIES ( symbol = 'org.example.MyAdd', type = 'odpsjar', file = 'my_add_jar' );ここで:
symbol:指定されたエントリクラス名を表します。type:外部UDFのタイプを表します。現在、odpsjar、UDAFJar、UDTFJar、Pythonをサポートしています。file:Jarパッケージに対応する外部リソース名を表します。
作成が成功すると、PL UDFのようにJava UDFを使用できます。使用例は以下のとおりです:
obclient> CREATE FUNCTION my_add(x int, y int)
-> RETURNS int
-> PROPERTIES (
-> symbol = 'org.example.MyAdd',
-> type = 'odpsjar',
-> file = 'my_add_jar'
-> );
Query OK, 0 rows affected (0.118 sec)
obclient> SELECT my_add(1, 2);
+--------------+
| my_add(1, 2) |
+--------------+
| 3 |
+--------------+
1 row in set (0.005 sec)
Java UDTF
Java UDTFとは、Java言語で実装されたユーザー定義テーブル関数(Java User-Defined Table Function)を指します。UDTFと一般的なUDFの最大の違いは、一般的なUDFがスカラー値、すなわち1行のデータを返すのに対し、UDTFは複数行のデータを返すことができる点です。
Java UDTFの作成
Java UDTFのユースケースの柔軟性に対応するため、URLと外部リソースを使用した2つの方法でJava UDTFを作成できます。
URLからJava UDTFを作成する
以下のコードをコンパイルしてmy_split.jarとしてパッケージ化すると、OBServerでJava UDTFを作成できます。例:
package my.test;
public class MySplit {
public String[] process(String str) {
if (str == null) return null;
return str.split(" ");
}
}
Java UDTFの作成
CREATE FUNCTION my_split(x longtext)
RETURNS varchar(1024)
PROPERTIES (
symbol = 'my.test.MySplit',
type = 'UDTFJar',
file = 'http://******/my_split.jar'
);
外部関数を作成する際に、typeをUDTFJarに指定することでJava UDTFを作成できます。その後、SQLステートメント内でtable functionと組み合わせて使用でき、単一スカラークエリとして、または他のテーブルとjoin操作を行うこともできます。
Java UDTF関数の呼び出し
呼び出し例:
テーブル
t1を作成し、いくつかのデータを挿入します。obclient> CREATE TABLE t1(a int, b decimal(10, 2), c1 varchar(32));obclient> INSERT INTO t1 VALUES (1, 2.1, 'hello oceanbase'), (2, 2.2, 'hello UDTF') ;以下のコマンドを実行してJava UDTFを呼び出します。
obclient> SELECT t1.a,t1.b, COLUMN_VALUE FROM t1, table(my_split(t1.c1)); +------+------+--------------+ | a | b | COLUMN_VALUE | +------+------+--------------+ | 1 | 2.10 | hello | | 1 | 2.10 | oceanbase | | 2 | 2.20 | hello | | 2 | 2.20 | UDTF | +------+------+--------------+
外部リソースを使用してJava UDTFを作成する
OBServerは、Java UDTF Jarパッケージなどの外部ストアドプロシージャの依存リソースを外部リソースとして管理します。JarパッケージはDBMS_JAVA.LOADJAVAシステムパッケージ関数を使用してOBServerにアップロードし、作成したJava UDTFでこのJarパッケージに対応する外部リソースを参照する必要があります。
操作手順は以下のとおりです:
Jarパッケージのアップロード
DBMS_JAVA.LOADJAVAを呼び出して、Jarパッケージを外部リソースとしてOBServerにアップロードします。Java UDTFの作成
以下のSQLステートメントを実行して、
my_splitという名前のJava UDTFを作成します。CREATE FUNCTION my_split(x int, y int) RETURNS int PROPERTIES ( symbol = 'my.test.MySplit', type = 'UDTFJar', file = 'my_split_jar' );ここで:
symbol:指定されたエントリクラス名を表します。type:外部UDFのタイプを表します。現在、odpsjar、UDAFJar、UDTFJar、Pythonをサポートしています。file:Jarパッケージに対応する外部リソース名を表します。
作成が成功すると、PL UDFのようにJava UDTFを使用できます。使用例は以下のとおりです:
obclient> SELECT t1.a,t1.b, COLUMN_VALUE FROM t1, table(my_split(t1.c1));
+------+------+--------------+
| a | b | COLUMN_VALUE |
+------+------+--------------+
| 1 | 2.10 | hello |
| 1 | 2.10 | oceanbase |
| 2 | 2.20 | hello |
| 2 | 2.20 | UDTF |
+------+------+--------------+
Java UDAF
Java UDAFとは、Java言語で実装されたユーザー定義集約関数(Java User-Defined Aggregate Function)を指します。 UDAFは、複数行のデータにおける1列または複数列を、ユーザー定義のロジックに基づいて1つのスカラーデータに集約することができます。通常は GROUP BY ステートメントと併用され、各 GROUP ごとに集約後の結果を返します。
Java UDAFの作成
Java UDAFの使用シナリオの柔軟性に対応するため、URLと外部リソースを使用した2つの方法でJava UDAFを作成できます。
URLからJava UDAFを作成する
以下のJavaコードをコンパイルしてmy_avg.jarとしてパッケージ化し、OBServerでJava UDAFを作成できます。例:
package my.test;
public class MyAvg {
private double sum = 0;
private double count = 0;
public void iterate(Double x) {
sum += x;
count += 1;
}
public void merge(MyAvg other) {
sum += other.sum;
count += other.count;
}
public Double terminate() {
return sum / count;
}
}
Java UDAFの作成
CREATE FUNCTION my_avg(x double)
RETURNS double
PROPERTIES (
symbol = 'my.test.MyAvg',
type = 'UDAFJar',
file = 'http://******/my_avg.jar'
);
Java UDAF関数の呼び出し
呼び出し例は以下のとおりです:
テーブル
tを作成し、いくつかのデータを挿入します。obclient> CREATE TABLE t(a int, b int);obclient> INSERT INTO t VALUES(1, 10),(2, 100),(1, 20),(2, 200),(3, 0);以下のコマンドを実行してJava UDAFを呼び出します。
obclient> SELECT my_avg(b) FROM t GROUP BY a; +--------------+ |my_avg(b) | +--------------+ |15.0 | +--------------+ |150.0 | +--------------+ |0.0 | +--------------+
外部リソースを使用したJava UDAFの作成
OBServerは、Java UDAF Jarパッケージなど外部ストアドプロシージャの依存リソースを外部リソースとして管理します。JarパッケージはDBMS_JAVA.LOADJAVAシステムパッケージ関数を使用してOBServerにアップロードし、作成したJava UDAFでこのJarパッケージに対応する外部リソースを参照します。
操作手順は以下のとおりです:
Jarパッケージのアップロード
DBMS_JAVA.LOADJAVAを呼び出し、Jarパッケージを外部リソースとしてOBServerにアップロードします。Java UDAFの作成
以下のSQLステートメントを実行して、
my_avgという名前のJava UDAFを作成します。CREATE FUNCTION my_avg(x int, y int) RETURNS int PROPERTIES ( symbol = 'my.test.MyAvg', type = 'UDAFJar', file = 'my_avg_jar' );ここで:
symbol:指定されたエントリクラス名を表します。type:外部UDFのタイプを表します。現在、odpsjar、UDAFJar、UDTFJar、Pythonをサポートしています。file:Jarパッケージに対応する外部リソース名を表します。
作成が成功すると、PL UDFと同様にJava UDAFを使用できます。使用例は以下のとおりです:
obclient> SELECT my_avg(b) FROM t GROUP BY a;
+--------------+
|my_avg(b) |
+--------------+
|15.0 |
+--------------+
|150.0 |
+--------------+
|0.0 |
+--------------+
Python UDF
Python UDFとは、Python言語で実装されたユーザー定義関数を指します。
OceanBaseデータベースでは、Python UDFを作成する際には、Pythonスクリプトとエントリクラスを指定するだけです。実行時には、OBServerがエントリクラスをインスタンス化し、そのevaluateメソッドを呼び出します。
以下のvarcharUrl.pyを例に、Python UDFを作成します:e
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
"""
# @File : varcharUrl.py
"""
class varcharUrl(object):
def evaluate(self, c1, c2):
if c1 == None:
return c2
if c2 == None:
return c1
return c1 + c2
上記のvarcharUrl.pyスクリプトは標準的なOceanBaseスタイルであり、ODPSスタイルもサポートしています。ODPS UDFのPythonスクリプトは、直接OceanBaseに移行できます。スクリプトの例は以下のとおりです:
#!/usr/bin/env python3e
# -*- coding:utf-8 -*-
"""
# @File : varcharUrl_ODPS.py
"""
from odps.udf import annotate
@annotate("string, string -> string")
class varcharUrl(object):
def evaluate(self, c1, c2):
if c1 == None:
return c2
if c2 == None:
return c1
return c1 + c2
Python UDFの作成
Python UDFの使用シナリオの柔軟性に対応するため、OceanBaseはURLと外部リソースの2つの方法でPython UDFを作成できます。URLから作成されるPython UDFは、Pythonスクリプトとデータベースの結合がなく、Python UDFを含むSQLが実行されるたびにURLから最新バージョンのPythonスクリプトを取得します。これは、デバッグなどPythonスクリプトを頻繁に更新するシナリオに適していますが、追加のパフォーマンスオーバヘッドが発生します。外部リソースから作成されるPython UDFは、Pythonスクリプトを外部リソースとしてデータベース内に保存し、OceanBaseの分散機能を利用して各ノードに配布します。これは、安定性と一定のパフォーマンス要件があるシナリオに適しています。
URLを使用してPython UDFを作成する
以下のSQLステートメントを実行して、varchar_test という名前のPython UDFを作成します。
obclient> CREATE FUNCTION varchar_test(c1 varchar(1000), c2 varchar(1000))
RETURNS varchar(1000)
PROPERTIES (
symbol = 'varcharUrl',
type = 'Python',
file = '<URL to Python>'
);
ここで:
symbol:指定されたエントリクラス名を表します。説明
symbolは大文字小文字を区別し、class_nameとmodule_name.class_nameの2つの形式をサポートしています。class_nameを定義する場合、OceanBaseは内部で一意のmodule_nameを生成し、各Pythonクラスの一意性を保証します。module_name.class_nameの場合、ユーザーがその一意性を保証する必要があります。そうでない場合、同じステートメント内で2つの異なるUDFを呼び出すと、2つのUDF定義におけるmodule_name.class_nameが同じ場合、上書きが発生し、有効になるPythonクラスは1つだけになります。type:外部UDFのタイプを表します。現在、odpsjar、UDAFJar、UDTFJar、Pythonをサポートしています。file:Pythonスクリプトが配置されているURLを表します。
作成が成功すると、PL UDFを使用するようにPython UDFを使用できます。使用例は以下のとおりです:
obclient> CREATE FUNCTION varchar_test(c1 varchar(1000), c2 varchar(1000))
-> RETURNS varchar(1000)
-> PROPERTIES (
-> symbol = 'varcharUrl',
-> type = 'Python',
-> file = 'http://*****/varcharUrl.py'
-> );
Query OK, 0 rows affected (0.289 sec)
obclient> SELECT varchar_test('OceanBase', '海扬数据库');
+----------------------------------------------+
| varchar_test('OceanBase', '海扬数据库') |
+----------------------------------------------+
| OceanBase海扬数据库 |
+----------------------------------------------+
外部リソースを使用したPython UDFの作成
OBServerは、Pythonスクリプトなど外部ストアドプロシージャの依存リソースを外部リソースとして管理します。PythonスクリプトはDBMS_PYTHON.LOADPYHONシステムパッケージ関数を使用してOBServerにアップロードし、作成するPython UDFでこのPythonスクリプトに対応する外部リソースを参照します。
外部リソースのアップロードとUDFの作成には厳密な順序要件はありません。UDFが呼び出される時点でリソースがアップロード済みであればよいのです。また、一つの外部リソースは複数のUDFで使用できます。
操作手順は以下の通りです:
Pythonスクリプトのアップロード
DBMS_PYTHON.LOADPYHONを呼び出して、Pythonスクリプトを外部リソースとしてOBServerにアップロードできます。スクリプトファイルの例は以下の通りです:String url = "<URL to Python>"; InputStream is = new URL(url).openStream(); // conn is a connection to OceanBase PreparedStatement ps = conn.prepareStatement("call DBMS_PYTHON.LOADPYHON(? ,? ,? )"); ps.setString(1, "varchar_test_script"); ps.setBlob(2, is); ps.setString(3, "varcharUrl Python script"); ps.execute();作成が成功すると、DBAユーザーは現在のテナントで
DBA_OB_EXTERNAL_resourcesビューをクエリして、そのテナントのすべての外部リソースを取得するか、SYSテナントにログインしてCDB_OB_EXTERNAL_resourcesをクエリして、すべてのテナントの外部リソースを取得できます。Python UDFの作成
以下のSQLステートメントを実行して、
varchar_testという名前のPython UDFを作成します:obclient> CREATE FUNCTION varchar_test(c1 varchar(1000), c2 varchar(1000)) RETURNS varchar(1000) PROPERTIES ( symbol = 'varcharUrl', type = 'Python', file = 'varchar_test_script' );ここで:
symbol:指定されたエントリクラス名を表します。type:Pythonの型を表します。現在はPython型のみサポートしています。file:Pythonスクリプトに対応する外部リソース名です。
作成が成功すると、PL UDFのようにPython UDFを使用できます。使用例は以下の通りです:
obclient> CREATE FUNCTION varchar_test(c1 varchar(1000), c2 varchar(1000))
-> RETURNS varchar(1000)
-> PROPERTIES (
-> symbol = 'varcharUrl',
-> type = 'Python',
-> file = 'varchar_test_script'
-> );
Query OK, 0 rows affected (0.221 sec)
obclient> SELECT varchar_test('OceanBase', '海扬数据库');
+----------------------------------------------+
| varchar_test('OceanBase', '海扬数据库') |
+----------------------------------------------+
| OceanBase海扬数据库 |
+----------------------------------------------+
1 row in set (0.060 sec)