このトピックでは、Python ユーザー定義テーブル関数 (UDTF) の開発、登録、使用方法について説明します。
定義
ユーザー定義テーブル関数 (UDTF) は、0 個、1 個、または複数のスカラー値を入力パラメーターとして受け取ります。これらのパラメーターは可変長です。スカラー関数とは異なり、UDTF は単一の値ではなく、任意の数の行を返すことができます。返される各行には 1 つ以上の列を含めることができ、UDTF の各呼び出しで複数の行または列を出力できます。
制限事項
Realtime Compute for Apache Flink のデプロイおよびネットワーク環境の特性上、Python ユーザー定義関数を開発する際には、以下の制限事項にご注意ください。
-
オープンソース Flink V1.12 以降のみをサポートしています。
-
Python は Flink ワークスペースにプリインストールされています。プリインストールされた Python バージョンでコードを開発してください。
注記
VVR 8.0.11 より前の Realtime Compute エンジンには Python 3.7.9 がプリインストールされており、VVR 8.0.11 以降には Python 3.9.19 がプリインストールされています。以前のバージョンから VVR 8.0.11 以降にアップグレードする場合は、以前のバージョンで開発された PyFlink ジョブを再テスト、デプロイ、実行する必要があります。
-
Flink ランタイムは JDK 8 および JDK 11 のみをサポートしています。Python ジョブがサードパーティの JAR パッケージに依存する場合は、JAR パッケージに互換性があることを確認してください。
-
オープンソース Scala V2.11 のみをサポートしています。Python ジョブがサードパーティの JAR パッケージに依存する場合は、Scala V2.11 に対応する JAR パッケージを使用してください。
-
インライン関数は、VVR 6.0.0 以降でのみサポートされます。
UDTF の開発
Python 関数は、以下のいずれかの方法で開発できます。
-
Python コードをパッケージ化してアップロードし、プラットフォームでコードを登録します。
-
SQL スクリプト内でコードロジックをインライン関数として宣言します。
UDTF のロジックが単純な場合は、Python 関数をインライン関数として開発できます。
コードパッケージを使用した UDTF の開発
UDTF の開発
注記
Flink は、UDX の開発を支援するために、Python ユーザー定義拡張 (UDX) のサンプルプロジェクトを提供しています。サンプルには、Python ユーザー定義スカラー関数、ユーザー定義集計関数 (UDAF)、および UDTF の実装が含まれています。この例では、Windows オペレーティングシステムを使用して UDTF を開発する方法について説明します。
重要
-
登録する UDF 名には、小文字、数字、ハイフン (-) のみを使用できます。アンダースコア (_) やその他の特殊文字は使用できません。
-
Realtime Compute for Apache Flink のマネージド環境には、
splitのような組み込み関数がいくつかプリインストールされています。カスタム関数が組み込み関数と同じ名前の場合、登録に失敗するか、SQL 検証でエラーが発生します。関数名には、my-splitのようなカスタムプレフィックスを使用してください。
-
python_demo-master サンプルパッケージをダウンロードし、コンピューターに解凍します。
-
PyCharm で、[file] > [open] を選択して、解凍した python_demo-master フォルダーを開きます。
-
\python_demo-master\udx\udtfs.py をダブルクリックし、ビジネス要件に基づいて udtfs.py ファイルの内容を変更します。
この例では、my_split は各行の文字列を縦棒 (|) で複数の列に分割します。
from pyflink.table import DataTypes
from pyflink.table.udf import udtf
@udtf(result_types=[DataTypes.STRING(), DataTypes.STRING()])
def my_split(s: str):
splits = s.split("|")
yield splits[0], splits[1]
-
ダウンロードしたパッケージ (\python_demo) 内の udx フォルダーが含まれているディレクトリで、以下のコマンドを実行してファイルをパッケージ化します。
zip -r python_demo.zip udx
\python_demo\ ディレクトリに python_demo.zip パッケージが生成されると、UDTF の開発は完了です。
UDTF の登録
UDTF の登録方法の詳細については、「UDF の管理」をご参照ください。
UDTF の使用
UDTF が登録されると、使用できるようになります。以下の手順を実行してください。
-
Flink SQL ジョブを開発します。詳細については、「ジョブ開発の概要」をご参照ください。
ASI_UDTF_Source テーブルの各行の message フィールドの値は、文字列 aa と縦棒 (|) で連結された後、さらに縦棒 (|) で複数の列に分割されます。
CREATE TEMPORARY TABLE ASI_UDTF_Source (
`message` VARCHAR
) WITH (
'connector'='datagen'
);
CREATE TEMPORARY TABLE ASI_UDTF_Sink (
name VARCHAR,
place VARCHAR
) WITH (
'connector' = 'blackhole'
);
INSERT INTO ASI_UDTF_Sink
SELECT name,place
FROM ASI_UDTF_Source,lateral table(my_split(concat_ws('|', `message`, 'aa'))) as T(name,place);
-
[O&M] > [Deployments] ページで、対象ジョブの [Actions] 列にある [Start] をクリックします。
ジョブが開始されると、ASI_UDTF_Sink テーブルには 2 つの列が含まれます。このデータは、ASI_UDTF_Source テーブルの各行の message フィールドと aa フィールドを縦棒 (|) で連結し、その結果を縦棒 (|) で分割して生成されます。
Python インラインテーブル関数
インライン関数は、CREATE FUNCTION ステートメント内に関数の実装を直接埋め込みます。関数の定義と登録宣言は、同じ SQL ステートメント内で完了します。以下の例では、注文商品を解析するインライン関数を定義します。$$ の間に完全なコードロジックを宣言する必要があります。
CREATE TEMPORARY FUNCTION parse_order_items(items_json STRING)
RETURNS TABLE (
sku STRING,
quantity INT
)
HANDLER 'ParseOrderItems'
AS $$
import json
class ParseOrderItems:
def eval(self, items_json):
if not items_json:
return
try:
items = json.loads(items_json)
except (TypeError, ValueError):
return
if not isinstance(items, list):
return
for item in items:
if not isinstance(item, dict):
continue
sku = str(item.get("sku", "")).strip().upper()
try:
quantity = int(item.get("quantity"))
except (TypeError, ValueError):
continue
if sku and quantity > 0:
yield sku, quantity
$$
LANGUAGE PYTHON;
-
Python ではインデントが重要です。関数本体の第 1 レベルのコードは行頭に記述し、コードブロック内の相対的なインデントが正しいことを確認してください。
-
インライン関数はベクトル化実行をサポートしておらず、非決定性関数として宣言することもできません。
-
一時関数のみ作成できます。