MaxCompute では、ビジネスロジックの要件を満たすために Python 3 でユーザー定義関数 (UDF) を作成できます。このトピックでは、Python 3 で UDF を作成する方法について説明します。
UDF コードの構造
MaxCompute Studio を使用して Python 3 で UDF コードを作成できます。UDF コードには、次のコンポーネントを含める必要があります。
モジュールのインポート: 必須。
UDF コードには、関数シグネチャをインポートするために使用される
from odps.udf import annotateを含める必要があります。これにより、MaxCompute はコードで定義されている関数シグネチャを識別できます。UDF コードでファイルまたはテーブルを参照する場合、UDF コードにはfrom odps.distcache import get_cache_fileまたはfrom odps.distcache import get_cache_tableを含める必要があります。関数シグネチャ: 必須。
関数シグネチャは
@annotate(<signature>)フォーマットを使用します。signatureパラメーターは、入力パラメーターと戻り値のデータの型を定義します。詳細については、「関数シグネチャとデータの型」をご参照ください。カスタム Python クラス: 必須。
カスタム Python クラスは、UDF コードの組織単位です。このクラスは、ビジネス要件を満たすために使用される変数とメソッドを定義します。UDF コードでは、MaxCompute にインストールされているサードパーティライブラリを参照したり、ファイルやテーブルを参照したりすることもできます。詳細については、「サードパーティライブラリ」または「リソースの参照」をご参照ください。
evaluateメソッド: 必須。evaluate メソッドは、カスタム Python クラスに含まれています。
evaluateメソッドは、UDF の入力パラメーターと戻り値を定義します。各 Python クラスには、evaluateメソッドを 1 つしか含めることができません。
サンプルコード:
# 関数シグネチャモジュールをインポートします。
from odps.udf import annotate
# 関数シグネチャを定義します。
@annotate("bigint,bigint->bigint")
# カスタム Python クラスを定義します。
class MyPlus(object):
# evaluate メソッドを定義します。
def evaluate(self, arg0, arg1):
if None in (arg0, arg1):
return None
return arg0 + arg1制限事項
UDF を使用したインターネットへのアクセス
デフォルトでは、MaxCompute は UDF を使用したインターネットへのアクセスを許可していません。UDF を使用してインターネットにアクセスする場合は、ビジネス要件に基づいて ネットワーク接続申請フォーム に記入し、申請を送信してください。申請が承認されると、MaxCompute のテクニカルサポートチームがお客様に連絡し、ネットワーク接続の確立を支援します。ネットワーク接続申請フォームの記入方法の詳細については、「ネットワーク有効化プロセス」をご参照ください。
UDF を使用した VPC へのアクセス
デフォルトでは、MaxCompute は UDF を使用した VPC 内のリソースへのアクセスを許可していません。UDF を使用して VPC 内のリソースにアクセスするには、MaxCompute と VPC の間にネットワーク接続を確立する必要があります。関連する操作の詳細については、「UDF を使用して VPC 内のリソースにアクセスする」をご参照ください。
UDF、UDAF、または UDTF を使用したテーブルデータの読み取り
UDF、UDAF、または UDTF を使用して、次の種類のテーブルからデータを読み取ることはできません:
スキーマ進化が実行されたテーブル
複雑なデータの型を含むテーブル
JSON データの型を含むテーブル
トランザクションテーブル
注意事項
Python 3 は Python 2 と互換性がありません。同じ SQL 文で Python 2 と Python 3 の両方のコードを使用することはできません。
Python Software Foundation は 2020 年初頭に Python 2 のサポート終了 (EOL) を発表しました。プロジェクトの要件に基づいて UDF を移行することをお勧めします。
開発プロセス
UDF を開発する際には、準備、UDF コードの作成、Python プログラムのアップロード、UDF の作成、UDF のデバッグ、および UDF の呼び出しを行う必要があります。MaxCompute では、MaxCompute Studio、DataWorks、MaxCompute クライアント (odpscmd) など、複数のツールを使用して UDF を開発できます。このセクションでは、MaxCompute Studio、DataWorks、および MaxCompute クライアント (odpscmd) を使用して UDF を開発する方法の例を示します。
MaxCompute Studio の使用
準備
MaxCompute Studio を使用して UDF を開発およびデバッグする前に、MaxCompute Studio をインストールし、MaxCompute プロジェクトに接続する必要があります。詳細については、次のトピックをご参照ください:
UDF コードの作成
[Project] セクションで、[MaxCompute Script Module] の下の [scripts] を右クリックし、 を選択します。
[MaxCompute Python クラスの新規作成] ダイアログボックスで、[名前] フィールドにクラス名を入力し、Kind ドロップダウンリストから [python UDF] を選択して、[OK] をクリックします。
コードエディタで UDF コードを作成します。
from odps.udf import annotate @annotate("string,bigint->string") class GetUrlChar(object): def evaluate(self, url, n): if n == 0: return "" try: index = url.find(".htm") if index < 0: return "" a = url[:index] index = a.rfind("/") b = a[index + 1:] c = b.split("-") if len(c) < n: return "" return c[-n] except Exception: return "Internal error"説明Java ユーザー定義関数 (UDF) をローカルでデバッグする方法の詳細については、「UDF のテスト」をご参照ください。
Python プログラムのアップロードと UDF の作成
scripts フォルダ内の目的の Python プログラムを右クリックし、[Deploy To Server…] を選択します。[Submit resource and register function] ダイアログボックスで、関数の名前を設定し、[OK] をクリックします。詳細については、「Python プログラムをアップロードして MaxCompute UDF を作成する」をご参照ください。
この例では、関数名は UDF_GET_URL_CHAR です。
UDF の呼び出し
左側のナビゲーションウィンドウで、[Project Explore] タブをクリックします。UDF が属する MaxCompute プロジェクトを右クリックし、[Open Console] を選択し、UDF を呼び出すために使用する SQL 文を入力して、Enter キーを押して SQL 文を実行します。サンプル文:
SET odps.sql.python.version=cp37; -- このコマンドは、UDF で Python 3 を有効にするために必要です。 SELECT UDF_GET_URL_CHAR("http://www.taobao.com/a.htm", 1);次の結果が返されます:
+-----+ | _c0 | +-----+ | a | +-----+
DataWorks の使用
準備
DataWorks を使用して UDF を開発およびデバッグする前に、DataWorks をアクティブ化し、DataWorks ワークスペースを MaxCompute プロジェクトに関連付ける必要があります。詳細については、「DataWorks」をご参照ください。
UDF コードの作成
任意の Python 開発ツールで UDF コードを開発し、パッケージ化できます。以下はサンプルコードです。
from odps.udf import annotate @annotate("string,bigint->string") class GetUrlChar(object): def evaluate(self, url, n): if n == 0: return "" try: index = url.find(".htm") if index < 0: return "" a = url[:index] index = a.rfind("/") b = a[index + 1:] c = b.split("-") if len(c) < n: return "" return c[-n] except Exception: return "Internal error"Python プログラムのアップロードと UDF の作成
DataWorks コンソールでパッケージ化したコードパッケージをアップロードし、UDF を作成できます。詳細については、次のトピックをご参照ください:
UDF の呼び出し
UDF を作成した後、DataWorks コンソールで ODPS SQL ノードを作成できます。ODPS SQL ノードで SQL 文を作成して、UDF を呼び出してデバッグできます。ODPS SQL ノードの作成方法の詳細については、「MaxCompute SQL タスクの開発」をご参照ください。サンプル文:
SET odps.sql.python.version=cp37; -- このコマンドは、UDF で Python 3 を有効にするために必要です。 SELECT UDF_GET_URL_CHAR("http://www.taobao.com/a.htm", 1);
MaxCompute クライアント (odpscmd) の使用
準備
MaxCompute クライアントを使用して UDF を開発およびデバッグする前に、MaxCompute クライアントのインストールパッケージ (GitHub) をダウンロードし、MaxCompute クライアントをインストールしてから、設定ファイルを構成して MaxCompute プロジェクトに接続する必要があります。詳細については、「MaxCompute クライアント (odpscmd)」をご参照ください。
UDF コードの作成
任意の Python 開発ツールで UDF コードを開発し、パッケージ化できます。以下はサンプルコードです。
from odps.udf import annotate @annotate("string,bigint->string") class GetUrlChar(object): def evaluate(self, url, n): if n == 0: return "" try: index = url.find(".htm") if index < 0: return "" a = url[:index] index = a.rfind("/") b = a[index + 1:] c = b.split("-") if len(c) < n: return "" return c[-n] except Exception: return "Internal error"Python プログラムのアップロードと UDF の作成
MaxCompute クライアントでパッケージ化した Python プログラムをアップロードし、UDF を作成できます。詳細については、次のトピックをご参照ください:
UDF の呼び出し
UDF を作成した後、SQL 文を作成して UDF を呼び出し、デバッグできます。例:
SET odps.sql.python.version=cp37; -- このコマンドは、UDF で Python 3 を有効にするために必要です。 SELECT UDF_GET_URL_CHAR("http://www.taobao.com/a.htm", 1);
UDF 開発: サードパーティライブラリ Numpy のインストール
NumPy サードパーティライブラリは、MaxCompute の組み込み Python 3 ランタイム環境にはインストールされていません。UDF で NumPy を使用するには、NumPy WHEEL パッケージを手動でアップロードする必要があります。PyPI またはミラーから NumPy パッケージをダウンロードすると、パッケージファイル名は numpy-<バージョン番号>-cp37-cp37m-manylinux1_x86_64.whl になります。パッケージのアップロード方法の詳細については、「リソース操作」または「Python UDF でサードパーティパッケージを使用する」をご参照ください。
Python 3 でサポートされている標準ライブラリの詳細については、「The Python Standard Library」をご参照ください。
関数シグネチャとデータの型
関数シグネチャのフォーマット:
@annotate(<signature>)signature パラメーターは、入力パラメーターと戻り値のデータの型を指定する文字列です。UDF を実行する場合、UDF の入力パラメーターと戻り値のデータの型は、関数シグネチャで指定されたデータの型と一致している必要があります。データの型の一貫性は、セマンティック解析中にチェックされます。データの型が一致しない場合、エラーが返されます。シグネチャのフォーマット:
'arg_type_list -> type'パラメーターの説明:
arg_type_list: 入力パラメーターのデータの型を指定します。複数の入力パラメーターを使用する場合、データの型はカンマ (,) で区切られます。サポートされているデータの型は、BIGINT、STRING、DOUBLE、BOOLEAN、DATETIME、DECIMAL、FLOAT、BINARY、DATE、DECIMAL(precision,scale)、CHAR、VARCHAR です。ARRAY、MAP、STRUCT などの複雑なデータの型や、ネストされた複雑なデータの型もサポートされています。arg_type_listはアスタリスク (*) で表すか、空 ('') のままにすることができます。arg_type_listがアスタリスク (*) で表される場合、任意の数の入力パラメーターが許可されます。arg_type_listが空 ('') の場合、入力パラメーターは使用されません。
type: 戻り値のデータの型を指定します。UDF の場合、値の 1 列のみが返されます。サポートされているデータの型は、BIGINT、STRING、DOUBLE、BOOLEAN、DATETIME、DECIMAL、FLOAT、BINARY、DATE、DECIMAL(precision,scale) です。ARRAY、MAP、STRUCT などの複雑なデータの型や、ネストされた複雑なデータの型もサポートされています。
UDF コードを作成する際、MaxCompute プロジェクトで使用されている MaxCompute データ型エディションに基づいてデータの型を選択できます。MaxCompute データ型エディションと各エディションでサポートされているデータの型の詳細については、「データ型エディション」をご参照ください。
次の表に、有効な関数シグネチャの例を示します。
関数シグネチャ | 説明 |
| 入力パラメーターのデータの型は BIGINT と DOUBLE で、戻り値のデータの型は STRING です。 |
| 任意の数の入力パラメーターが使用され、戻り値のデータの型は STRING です。 |
| 入力パラメーターは使用されず、戻り値のデータの型は DOUBLE です。 |
| 入力パラメーターのデータの型は ARRAY<BIGINT> で、戻り値のデータの型は STRUCT<x:STRING, y:INT> です。 |
| 入力パラメーターは使用されず、戻り値のデータの型は MAP<BIGINT, STRING> です。 |
次の表に、MaxCompute SQL でサポートされているデータの型と Python 3 のデータの型の間のマッピングを示します。データの型の一貫性を確保するために、マッピングに基づいて Python UDF を作成する必要があります。
MaxCompute SQL の型 | Python 3 の型 |
BIGINT | INT |
STRING | UNICODE |
DOUBLE | FLOAT |
BOOLEAN | BOOL |
DATETIME | DATETIME.DATETIME |
FLOAT | FLOAT |
CHAR | UNICODE |
VARCHAR | UNICODE |
BINARY | BYTES |
DATE | DATETIME.DATE |
DECIMAL | DECIMAL.DECIMAL |
ARRAY | LIST |
MAP | DICT |
STRUCT | COLLECTIONS.NAMEDTUPLE |
リソースの参照
Python 2 UDF コードでは、odps.distcache モジュールを使用してファイルまたはテーブルを参照できます。
odps.distcache.get_cache_file(resource_name, mode): 指定されたmodeで指定されたファイルリソースのコンテンツを返します。resource_nameは、MaxCompute プロジェクト内の既存のファイルリソースの名前を指定する文字列です。リソース名が無効であるか、リソースが存在しない場合は、エラーが返されます。mode: オープンモードを指定する STRING です。デフォルト値は't'です。modeが't'の場合、ファイルはテキスト形式で開かれます。modeが'b'の場合、ファイルはバイナリ形式で開かれます。戻り値はファイルのようなオブジェクトです。このオブジェクトが不要になった場合は、
closeメソッドを呼び出して開いているファイルを解放する必要があります。
次のコードは、ファイルを参照する方法を示しています。
from odps.udf import annotate from odps.distcache import get_cache_file @annotate('bigint->string') class DistCacheExample(object): def __init__(self): cache_file = get_cache_file('test_distcache.txt') kv = {} for line in cache_file: line = line.strip() if not line: continue k, v = line.split() kv[int(k)] = v cache_file.close() self.kv = kv def evaluate(self, arg): return self.kv.get(arg)odps.distcache.get_cache_table(resource_name): 指定されたテーブルリソースのコンテンツを返します。resource_name: 現在の MaxCompute プロジェクトに存在するテーブルリソースの名前。リソース名が無効であるか、リソースが存在しない場合は、例外が返されます。テーブルから BIGINT、STRING、DOUBLE、BOOLEAN、DATETIME、FLOAT、CHAR、VARCHAR、BINARY、DATE、DECIMAL、ARRAY、MAP、STRUCT 型のデータを読み取ることができます。戻り値は GENERATOR データの型です。呼び出し元はテーブルを走査してテーブルのコンテンツを取得します。呼び出し元がテーブルを走査するたびに、ARRAY 型のレコードが取得されます。
次のコードは、テーブルを参照する方法を示しています。
from odps.udf import annotate
from odps.distcache import get_cache_table
@annotate('->string')
class DistCacheTableExample(object):
def __init__(self):
self.records = list(get_cache_table('udf_test'))
self.counter = 0
self.ln = len(self.records)
def evaluate(self):
if self.counter > self.ln - 1:
return None
ret = self.records[self.counter]
self.counter += 1
return str(ret)使用上の注意
Python 3 UDF を開発した後、MaxCompute SQL を使用して UDF を呼び出すことができます。Python 3 UDF の呼び出し方法の詳細については、「開発プロセス」をご参照ください。次のいずれかの方法を使用して、Python 3 で UDF を呼び出すことができます:
Python 3 を有効にする
デフォルトでは、MaxCompute プロジェクトで UDF を作成するために Python 2 が使用されます。Python 3 で UDF を作成する場合は、実行する SQL 文の前に次のコマンドを追加します。その後、文をコミットして実行します。
set odps.sql.python.version=cp37;UDF の呼び出し
MaxCompute プロジェクトで UDF を使用する: この方法は、ビルトイン関数の使用方法に似ています。
プロジェクト間で UDF を使用する: プロジェクト A でプロジェクト B の UDF を使用します。次の文に例を示します:
select B:udf_in_other_project(arg0, arg1) as res from table_t;。プロジェクト間の共有の詳細については、「パッケージに基づくプロジェクト間のリソースアクセス」をご参照ください。
Python 2 UDF の移植
Python Software Foundation は 2020 年初頭に Python 2 の EOL を発表しました。したがって、Python 2 UDF を移植することをお勧めします。
新しいプロジェクト、または初めて Python で UDF を作成する既存のプロジェクトでは、すべての Python UDF を Python 3 で作成することをお勧めします。
多くの Python 2 UDF が存在する既存のプロジェクトでは、Python 3 を有効にする際に注意が必要です。Python 2 UDF を Python 3 UDF に置き換える場合は、次の方法を使用します:
Python 3 を使用して新しい UDF を作成し、セッションレベルで新しいジョブに対して Python 3 を有効にします。Python 3 を有効にする方法の詳細については、「Python 3 を有効にする」をご参照ください。
UDF が Python 2 と Python 3 の両方と互換性を持つように、Python 2 UDF を再書き込みします。UDF の再書き込みの詳細については、「Porting Python 2 Code to Python 3」をご参照ください。
説明複数のプロジェクト間で共有されるパブリック UDF を作成する場合は、Python 2 と Python 3 の両方と互換性のある UDF を使用することをお勧めします。