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を作成します。
```sql
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と外部リソースを使用してJava UDTFを作成する2つの方法を提供しています。
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を作成します。
```sql
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列または複数列をユーザー定義のロジックにより単一のスカラーデータに集約することができます。通常はGROUP BYステートメントと併用され、各GROUPに対して集約後の結果を1つ返します。
Java UDAFの作成
Java UDAFの使用シナリオの柔軟性に対応するため、URLと外部リソースを使用してJava UDAFを作成する2つの方法を提供しています。
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を作成します。
```sql
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の分散機能を利用して各ノードに配布します。これは、安定性と一定のパフォーマンス要件が求められるシナリオに適しています。
説明
OceanBaseデータベースV4.4.2 BP2バージョン以降、Python UDFの実行は独立したサブプロセスで行われ、observerメインプロセスに影響を与えません。サブプロセスは制限されたセキュリティ環境で動作し、高リスクなシステムコールが無効化され、ネットワークアクセス権限がなく、サンドボックス環境外部のファイルシステムにアクセスすることができません。
Python環境のインストール
OceanBaseデータベースにおけるPython依存パッケージのバージョン、アーキテクチャ要件、およびダウンロードURLは以下の表のとおりです:
|プラットフォーム|アーキテクチャ|ダウンロードURL| |--|--|--| |EL7| x86_64| https://mirrors.aliyun.com/oceanbase/development-kit/el/7/x86_64/devdeps-python3-3.13.3-152026052814.el7.x86_64.rpm| |EL7| aarch64| https://mirrors.aliyun.com/oceanbase/development-kit/el/7/aarch64/devdeps-python3-3.13.3-152026052814.el7.aarch64.rpm| |AL8| x86_64| https://mirrors.aliyun.com/oceanbase/development-kit/al/8/x86_64/devdeps-python3-3.13.3-152026052814.al8.x86_64.rpm| |AL8| aarch64| https://mirrors.aliyun.com/oceanbase/development-kit/al/8/aarch64/devdeps-python3-3.13.3-152026052814.al8.aarch64.rpm|
OceanBaseデータベースにおけるpyarrow依存パッケージのバージョン、アーキテクチャ要件、およびダウンロードURLは以下の表のとおりです:
PyArrowはEL7とAL8を区別せず、アーキテクチャ(x86_64 / aarch64)とglibcのバージョンのみを区別します。
以下では、AL8環境を例に、完全なインストール手順を示します。
以下のコマンドを実行して、Python依存パッケージをダウンロードします。
wget https://mirrors.aliyun.com/oceanbase/development-kit/al/8/x86_64/devdeps-python3-3.13.3-152026052814.al8.x86_64.rpm以下のコマンドを実行して、パッケージ内のすべてのファイルを現在のディレクトリに解凍します。
rpm2cpio devdeps-python3-3.13.3-132025070111.al8.x86_64.rpm | cpio -divPython関連ライブラリファイルのインストール先に移動する
cd usr/local/oceanbase/deps/devel/python3pipを使用したPyArrowの自動インストール
PyArrowは、Apache ArrowプロジェクトのPythonでの公式実装ライブラリであり、高性能で多言語対応のメモリ内データ処理および交換ツールです。その核心的な価値は、ビッグデータ分析、機械学習、およびシステム間のデータ交換に対して、標準化された高効率な基盤となるフォーマットを提供することにあります。
```shell
bin/python3.13 -m ensurepip
bin/python3.13 -m pip install pyarrow
```
前のコマンドと同様に、デフォルトでダウンロードするソースには wheel パッケージが含まれていないため、自動的にソースコードパッケージ(例:pyarrow-24.0.0.tar.gz)がダウンロードされます。この場合、ミラーソースを指定してインストールできます。コマンドは以下のとおりです:
```shell
bin/python3.13 -m pip install pyarrow --only-binary=pyarrow -i https://mirrors.aliyun.com/pypi/simple/
```
パブリックネットワークにアクセスできない場合は、以下の手順でPyArrowを手動でダウンロードしてインストールすることもできます。
パブリックネットワークにアクセス可能な環境で、pyarrowのwheelパッケージをダウンロードします。
wget https://mirrors.aliyun.com/pypi/packages/b3/93/10a48b5e238de6d562a411af6467e71e7aedbc9b87f8d3a35f1560ae30fb/pyarrow-23.0.1-cp313-cp313-manylinux_2_28_x86_64.whlPyArrow Python wheelパッケージを解凍し、OceanBase開発環境のPythonライブラリディレクトリにインストールする
unzip pyarrow-23.0.1-cp313-cp313-manylinux_2_28_x86_64.whl -d usr/local/oceanbase/deps/devel/python3/lib/python3.13/site-packages/
システムテナント内で、ob_python_home パラメータをPythonのインストールパスに設定する必要があります。コマンドは以下のとおりです:
obclient> ALTER SYSTEM STE ob_python_home ="devdeps_python_path/usr/local/oceanbase/deps/devel/python3";
ここで、devdeps_python_pathはdevdeps-python3依存パッケージが存在するディレクトリを抽出します。
Python環境のインストールが完了したら、以下のコマンドを使用して、テナントでPython UDF機能を有効にできます。
obclient> ALTER SYSTEM STE ob_enable_python_udf = TRUE tenant tenant_name;
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 が同じであると、上書きが発生し、有効になるのは1つのPythonクラスのみとなります。
type:外部UDFのタイプを表します。現在、odpsjar、UDAFJar、UDTFJar、Pythonをサポートしています。file:Pythonスクリプトが配置されているURLを表します。
作成が完了すると、Python UDFをPL/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)