このトピックでは、Python で作成された MaxCompute のユーザー定義関数 (UDF) に関するよくある質問 (FAQ) について説明します。
クラスまたはリソースに関する問題
このセクションでは、MaxCompute UDF を呼び出す際に発生する、クラスとリソースに関する一般的な問題について説明します。
-
現象 1: 「
function 'xxx' cannot be resolved」というエラーメッセージが返されます。-
原因:
-
原因 1: 間違ったプロジェクトから MaxCompute UDF を呼び出しています。UDF が現在の MaxCompute プロジェクトに存在しません。たとえば、UDF が開発プロジェクトで登録されているにもかかわらず、本番プロジェクトから呼び出している場合などです。
-
原因 2: MaxCompute UDF のクラスまたはリソースが正しくありません。
-
原因 3: MaxCompute UDF が依存するリソースタイプが正しくありません。 たとえば、PY ファイルのリソースタイプは PY ですが、UDF コード内の
get_cache_fileメソッドでは FILE タイプが必要です。 -
原因 4: MaxCompute UDF が依存するリソースが古くなっています。DataWorks から MaxCompute にリソースをアップロードする際に遅延が発生し、リソースが最新バージョンではない可能性があります。
-
原因 5: Python 環境のバージョンが正しくありません。デフォルトでは、MaxCompute は Python 2 環境でジョブを実行します。Python コードに非 ASCII 文字が含まれている場合、エラーが発生します。
-
-
解決策:
-
原因 1 の解決策: エラーが発生したプロジェクトで、MaxCompute クライアントから
list functions;コマンドを実行して、MaxCompute ユーザー定義関数 (UDF) が存在するかどうかを確認できます。 -
原因 2 の解決策: MaxCompute クライアントで、
desc function <function_name>;コマンドを実行し、出力の Class と Resources が正しいことを確認します。それらが正しくない場合は、
create function <function_name> as <'package_to_class'> using <'resource_list'>;コマンドを実行して関数を再登録します。 このコマンドにおいて、package_to_class は Python_script_name.class_name であり、resource_list には、MaxCompute で参照する必要があるすべてのファイル、テーブル、アーカイブ リソース、またはサードパーティパッケージが含まれます。詳細については、「関数の登録」をご参照ください。
-
原因 3 の対処方法: MaxCompute クライアントで、
desc resource <resource_name>;コマンドを実行し、出力の [Type] が正しいことを確認します。リソースタイプが正しくない場合は、add <file_type> <file_name>;コマンドを実行してリソースを再度追加します。-
UDF コード内で
get_cache_fileを使用してリソースが参照される場合、そのリソースはファイルリソースとなり、リソースタイプは FILE である必要があります。 -
UDF コードで
get_cache_tableを使用してリソースが参照されている場合、そのリソースはテーブルリソースです。リソースタイプは TABLE である必要があります。 -
UDF コードで
get_cache_archiveを使用してリソースが参照されている場合、そのリソースはアーカイブリソースです。リソースタイプは ARCHIVE である必要があります。
詳細については、「リソースの追加」をご参照ください。
-
-
原因 4 の解決策: MaxCompute クライアントで
desc resource <resource_name>;コマンドを実行し、出力で LastModifiedTime を確認することで最終更新時刻を検証できます。 -
原因 5 の解決策: Python コードの先頭に
#coding:utf-8または# -*- coding: utf-8 -*-エンコーディング宣言を追加します。 または、UDF を呼び出す SQL ステートメントの前にset odps.sql.python.version=cp37;ステートメントを追加し、それらを一緒に送信して Python 3 環境でジョブを実行します。
-
-
-
現象 2: MaxCompute UDF で
get_cache_archive('xxx.zip')を使用すると、次のいずれかのエラーメッセージが返されます:IOError: Download resource: xxx.zip failed、odps.distcache.DistributedCacheError、またはfuxi job failed: Download resource failed: xxx.zip。-
原因:
-
原因 1: アーカイブリソースが存在しません。MaxCompute UDF の登録時にアーカイブリソースが指定されていませんでした。
-
原因 2: アーカイブのリソースタイプが正しくありません。ARCHIVE ではありません。
-
原因 3: アーカイブリソースの名前または拡張子が実際のファイルと一致しません。たとえば、アーカイブリソースの名前は xxx.zip ですが、アップロードされたファイルは xxx.tar.gz です。システムはファイルを ZIP 形式で展開しようとするため、展開に失敗します。
-
原因 4: 同じジョブ内の 2 つの UDF が、名前は同じでも異なるプロジェクトにあるリソースに依存しています。
-
-
解決策:
-
原因 1 の解決策:
desc function <function_name>;コマンドをMaxCompute クライアントで実行して、出力の Resources フィールドにエラーメッセージで指定された圧縮リソースパッケージが含まれているかどうかを確認します。含まれていない場合は、
create function <function_name> as <'package_to_class'> using <'resource_list'>;コマンドを実行して関数を再登録します。不足しているアーカイブ リソースを resource_list に追加します。詳細については、「関数の登録」をご参照ください。
-
原因 2 の解決策: MaxCompute クライアントで
desc resource <resource_name>;コマンドを実行し、出力の Type が ARCHIVE であるかどうかを確認します。タイプが ARCHIVE でない場合は、
add archive <file_name>;コマンドを実行してリソースを再度アップロードします。詳細については、「リソースの追加」をご参照ください。
-
原因 3 の解決策: MaxCompute クライアントで、
desc function <function_name>;コマンドを実行し、出力の Resources セクションにある圧縮パッケージリソースの名前と拡張子が、実際のファイル名と拡張子と一致するかどうかを確認します。それらが一致しない場合は、
add archive <file_name>;コマンドを実行してリソースを再度アップロードしてください。file_name は、実際のアーカイブ リソースの名前と拡張子と同じである必要があります。 -
原因 4 の解決策: ジョブが依存するすべての UDF (ビュー内の UDF を含む) を確認します。各 UDF とそれに対応するリソースのプロジェクトと名前を調べます。異なるプロジェクトに同じ名前のリソースが存在する場合は、依存する UDF またはリソースの名前を変更します。
-
-
-
現象 3: MaxCompute UDF で
get_cache_table(table_name)を使用すると、エラーメッセージodps.distcache.DistributedCacheError: Table resource "xxx_table_name" not foundが返されます。-
原因:
-
原因 1: テーブルリソースが存在しません。MaxCompute UDF の登録時にテーブルリソースが指定されていませんでした。
-
原因 2: テーブルのリソースタイプが正しくありません。TABLE ではありません。
-
-
解決策:
-
原因 1 の解決策: MaxCompute クライアント上で、
desc function <function_name>;コマンドを実行し、出力の Resources にエラーメッセージのテーブルリソースが含まれているかどうかを確認します。含まれていない場合は、
create function <function_name> as <'package_to_class'> using <'resource_list'>;コマンドを実行して関数を再登録します。不足しているテーブルリソースを resource_list に追加します。詳細については、「関数の登録」をご参照ください。
-
原因 2 の解決策: MaxCompute クライアントで、
desc resource <resource_name>;コマンドを実行し、出力の [Type] が TABLE であるかどうかを確認します。タイプが TABLE ではない場合、
add table <table_name>;コマンドを実行してテーブルリソースを再度アップロードします。詳細については、「リソースの追加」をご参照ください。
-
-
-
現象 4: MaxCompute UDF がサードパーティパッケージを参照すると、「
ImportError: No module named 'xxx'」というエラーメッセージが返されます。-
原因:
-
原因 1: サードパーティパッケージのリソースタイプが正しくありません。リソースタイプは ARCHIVE である必要があります。
-
原因 2: MaxCompute UDF の登録時にサードパーティパッケージが指定されていませんでした。
-
原因 3: サードパーティパッケージへのパスが MaxCompute UDF コードに追加されていません。
-
原因 4: サードパーティパッケージは WHEEL パッケージですが、ファイルの拡張子が正しくないか、Python 環境のバージョンに対応していません。
-
原因 5: サードパーティパッケージが WHEEL パッケージでも純粋な Python パッケージでもなく、setup.py ファイルを含んでいます。
-
原因 6: MaxCompute UDF の Python ファイル名が、参照したいサードパーティモジュールの名前と競合しています。たとえば、UDF の Python ファイルが A.py の場合、
import Aを実行すると、システムはサードパーティパッケージのモジュールではなく、デフォルトで A.py をインポートします。
-
-
解決策:
-
原因1の解決策: MaxCompute クライアントから
desc resource <resource_name>;コマンドを実行し、出力の Type パラメーターが ARCHIVE であるかどうかを確認します。タイプが ARCHIVE でない場合は、
add archive <file_name>;コマンドを実行して、リソースを再度アップロードします。詳細については、「リソースの追加」をご参照ください。
-
原因 2 の解決策: MaxCompute クライアントを使用して
desc function <function_name>;コマンドを実行し、出力の Resources パラメーターにサードパーティパッケージが含まれているかどうかを確認します。それらが含まれていない場合は、
create function <function_name> as <'package_to_class'> using <'resource_list'>;コマンドを実行して関数を再度登録します。サードパーティのパッケージを resource_list に追加します。詳細については、「関数の登録」をご参照ください。
-
原因 3 の解決策: ユーザー定義関数 (UDF) のコードに、サードパーティパッケージへのパスが追加されているか確認します。 具体的には、コードに
sys.path.insert(0, 'work/path_to_third_party_package')が含まれていることを確認します。 たとえば、モジュール名が A で、対応する Python ファイルが A.py であるとします。 以下の例では、リソースパッケージパスを特定し、パスをコードに追加する方法を説明します。-
Python ファイルが resource_dir フォルダーにあり、resource_dir フォルダーを直接圧縮して resource-of-A.zip にした場合、
sys.path.insertのパスはwork/resource-of-A.zip/resource_dir/になります。 -
Python ファイルが resource_dir フォルダーにあり、このフォルダー内のすべてのファイルを resource-of-A.zip に圧縮した場合、
sys.path.insertのパスはwork/resource-of-A.zip/になります。 -
Python ファイルが resource_dir/path1/path2 フォルダーにあり、resource_dir フォルダー内のすべてのファイルを resource-of-A.zip に圧縮した場合、
sys.path.insertのパスはwork/resource-of-A.zip/path1/path2/になります。
説明デフォルトでは、ARCHIVE リソースは UDF 実行パスを基準とした
./work/ディレクトリに配置されます。 -
-
原因 4 の解決策: Python 2 環境と Python 3 環境では WHEEL ファイルが異なります。Python 2 の場合、WHEEL ファイル名には
cp27-cp27m-manylinux1_x86_64を含める必要があります。Python 3 の場合、WHEEL ファイル名にはcp37-cp37m-manylinux1_x86_64を含める必要があります。適切な WHEEL ファイルをダウンロードしてください。ダウンロードした WHEEL ファイルの拡張子を直接 .zip に変更できます。WHEEL ファイルを別の ZIP ファイルに圧縮する必要はありません。 -
原因 5 の解決策: まず、MaxCompute と互換性のある環境で setup.py ファイルをコンパイルして WHEEL パッケージを生成する必要があります。その後、リソースをアップロードし、関数を登録します。サードパーティパッケージのコンパイル方法の詳細については、「コンパイルが必要なサードパーティパッケージの使用」をご参照ください。
-
原因 6 の解決策: MaxCompute UDF の Python ファイル名を変更します。
-
-
-
現象 5: MaxCompute UDF が Python 3 標準ライブラリを参照すると、「
ImportError: No module named enum」というエラーメッセージが返されます。-
原因: MaxCompute プロジェクトで Python 3 が有効になっていません。デフォルトでは、MaxCompute UDF は Python 2 環境で実行されるため、Python 3 標準ライブラリを認識できません。
-
解決策: UDF を呼び出す SQL 文の前に
set odps.sql.python.version=cp37;文を追加し、それらをまとめて送信します。
-
-
現象 6: 「
ModuleNotFoundError: No module named 'six'」というエラーメッセージが返されます。-
原因: サードパーティパッケージへのパスが
sys.pathに追加されていません。これにより、Python UDF はパッケージをインポートできません。 -
解決策:詳細については、「MaxCompute UDF で Scipy を実行する」をご参照ください。
include_package_path('six.zip')をsys.path.insert(0, 'work/six.zip')に変更します。
-
-
現象 7: 「
failed to get Udf info from xxx.py」というエラーメッセージが返されます。-
原因:ユーザー定義テーブル値関数 (UDTF) またはユーザー定義集計関数 (UDAF) で、ベースクラスをインポートする構文が正しくありません。たとえば、
import odps.udf.BaseUDTFやimport odps.udf.BaseUDAFなどです。 -
解決策:import 文を
from odps.udf import BaseUDTFまたはfrom odps.udf import BaseUDAFに変更します。
-
パフォーマンスに関する問題
-
現象: 「
kInstanceMonitorTimeout」というエラーメッセージが返されます。 -
原因: UDF の処理時間がタイムアウト制限を超えています。デフォルトでは、レコードのバッチ (通常 1,024 件) は 1,800 秒以内に処理する必要があります。この制限は、ワーカーの合計実行時間ではなく、単一のバッチの処理に適用されます。SQL は通常、毎秒 10,000 レコードを超えるデータを処理します。この制限により、UDF での無限ループによる長時間の CPU 使用が防止されます。
-
解決策:
-
MaxCompute UDF コードにログを追加して、無限ループを確認します。 また、ログに時間情報を出力して、1 件のレコードの処理時間が想定どおりかを確認することもできます。 コードに次のログ出力情報を追加します。 ジョブが正常に実行された後、Logview の StdOut でログ情報を表示できます。
-
Python 2 環境
sys.stdout.write('your log') sys.stdout.flush() -
Python 3 環境
print('your log', flush=True)
-
-
実際の計算量が大きく、UDF の実行時間が長くなることが予想される場合は、以下のパラメーターを調整することでタイムアウトエラーを防ぐことができます。
パラメーター
説明
set odps.function.timeout=xxx;UDF の実行時のタイムアウト期間を調整します。デフォルト値は 1800 秒です。必要に応じてこの値を増やすことができます。値は 1 秒から 3600 秒の範囲で指定します。
set odps.sql.executionengine.batch.rowcount=xxx;MaxCompute が一度に処理するデータ行数を調整します。デフォルト値は 1024 です。必要に応じてこの値を減らすことができます。
-
ネットワークに関する問題
-
現象: MaxCompute UDF を呼び出してインターネットにアクセスするとエラーが発生します。
-
原因: MaxCompute UDF はインターネットアクセスをサポートしていません。
-
解決策: ビジネスニーズに基づいて「ネットワーク接続申請書」に記入し、提出してください。MaxCompute のテクニカルサポートチームが速やかに連絡し、ネットワークアクセスを有効にします。フォームの記入方法については、「ネットワークアクセスプロセス」をご参照ください。
サンドボックスに関する問題
-
現象: 「
RuntimeError: xxx has been blocked by sandbox」というエラーメッセージが返されます。 -
原因: Python UDF の一部の関数呼び出しがサンドボックスによってブロックされています。
-
解決策:
-
Python UDF を呼び出す SQL 文の前に、
set odps.isolation.session.enable=true;を追加します。その後、それらをまとめて送信します。 -
Python 3 UDF を使用する場合、
set odps.isolation.session.enable=true;設定はデフォルトで有効になります。
-
エンコーディングに関する問題
このセクションでは、MaxCompute UDF を呼び出す際に発生する一般的なエンコーディングの問題について説明します。
-
現象 1: 「
SyntaxError: Non-ASCII character '\xe8' in file xxx. on line yyy」というエラーメッセージが返されます。-
原因: MaxCompute UDF の Python ファイルに非 ASCII 文字が含まれており、Python 2 環境で実行されているためです。
-
解決策:
-
UDF を呼び出す SQL ステートメントの前に
set odps.sql.python.version=cp37;ステートメントを追加し、それらをまとめて送信して、ジョブを Python 3 環境で実行します。 -
Python 2 インタープリターのデフォルトエンコーディングを UTF-8 に変更します。そのためには、Python ファイルの先頭に以下のコードを追加します。
import sys reload(sys) sys.setdefaultencoding('utf-8')
-
-
-
現象 2: Python 2 UDF を呼び出すと、「
UnicodeEncodeError: 'ascii' code can't encode characters in position x-y: ordinal not in range(128)」というエラーメッセージが返されます。-
原因: 関数シグネチャの戻り値の型は STRING ですが、MaxCompute UDF は UNICODE 型の Python オブジェクトを返します。オブジェクトの名前を ret とします。デフォルトでは、MaxCompute は ASCII エンコーディング形式を使用して戻り値 ret を STR 型に変換しようとし、
str(ret)を返します。ret に ASCII 文字のみが含まれている場合、STR 型に正常に変換されます。ただし、ret に非 ASCII 文字が含まれている場合、変換は失敗し、エラーが返されます。 -
解決策: Python コードの
evaluateメソッドに、次のステートメントを追加します。return ret.encode('utf-8')
-
-
現象 3: Python 3 UDF を呼び出すと、「
UnicodeDecodeError: 'utf-8' codec can't decode byte xxx in position xxx: invalid continuation byte」というエラーメッセージが返されます。-
原因: 関数シグネチャの入力パラメーターの型は STRING です。しかし、Python 3 UDF を呼び出す際、入力文字列を UTF-8 を使用して STR 型の Python オブジェクトにデコードできません。
-
解決策:
-
UTF-8 でエンコードされていない文字列を MaxCompute テーブルに書き込まないようにします。
たとえば、Python 2 UDF は、GBK でエンコードされた STR 型の Python オブジェクトを返します。このオブジェクトは MaxCompute テーブルに書き込むことができますが、Python 3 UDF では読み取ることができません。Python 2 UDF がデータを返す前に、データを UTF-8 エンコーディングに変換します。たとえば、
ret.decode('gbk').encode('utf-8')を返します。 -
SQL ステートメントで、組み込み関数
is_encodingを使用して、UTF-8 でエンコードされていないデータを事前に除外します。次のコードに例を示します。select py_udf(input_col) from example_table where is_encoding(input_col, 'utf-8', 'utf-8') = true; -
Python コードの関数シグネチャで入力パラメーターの型を BINARY に変更します。SQL 文で、STRING 型の列を BINARY 型に変換し、それを Python 3 UDF の入力パラメーターとして使用します。次のコードに例を示します。
select py_udf(cast(input_col as binary)) from example_table;
-
-
関数シグネチャに関する問題
このセクションでは、MaxCompute UDF を呼び出す際に発生する一般的な関数シグネチャの問題について説明します。
-
現象 1: 「
resolve annotation of class xxx for UDTF/UDF/UDAF yyy contains invalid content '<EOF>'」というエラーメッセージが返されます。-
原因: MaxCompute UDF の入力または出力パラメーターは複合データ型ですが、関数シグネチャが無効です。
-
解決策: 関数シグネチャの複合データ型を修正して、シグネチャが有効であることを確認します。関数シグネチャの詳細については、「関数シグネチャとデータ型」をご参照ください。
-
-
現象 2: 「
TypeError: expected <class 'xxx'> but <class 'yyy'> found, value:zzz」というエラーメッセージが返されます。-
原因: 関数シグネチャで指定された戻り値の型が、MaxCompute UDF コードが実際に返すデータ型と一致しません。
-
解決策: 期待される戻り結果を確認します。関数シグネチャまたは MaxCompute UDF コードを修正して、データ型が一致することを確認します。
-
-
現象 3: 「
Semantic analysis exception - evaluate function in class xxx.yyy for user defined function zz does not match annotation ***->***」というエラーメッセージが返されます。-
原因: 関数シグネチャで指定された入力パラメーターの数が、MaxCompute UDF コードの対応するメソッドの入力パラメーターの数と一致しません。
-
解決策: 実際の入力パラメーターの数を確認します。関数シグネチャまたは MaxCompute UDF コードを修正して、入力パラメーターの数が一致することを確認します。
-
サードパーティパッケージに関する問題
-
現象: 「
GLIBCXX_x.x.x not found」というエラーメッセージが返されます。 -
原因: .so 共有ライブラリファイルが依存する GLIBCXX のバージョンが、MaxCompute でサポートされているバージョンよりも新しいためです。GLIBC および CXXABI についても同様です。
-
解決策: 互換性のある WHEEL パッケージを使用するか、互換性のある環境で .so 共有ライブラリファイルを再コンパイルします。MaxCompute のバイナリ実行可能ファイルまたは .so 共有ライブラリファイルでサポートされている依存関係の最新バージョンは以下のとおりです。
GLIBC <= 2.17 CXXABI <= 1.3.8 GLIBCXX <= 3.4.19 GCC <= 4.2.0
UDTF 関連の問題
-
現象: 「
Semantic analysis exception - expect 2 aliases but have 0」というエラーメッセージが返されます。 -
原因: Python UDTF コードで出力列名が指定されていません。
-
解決策: Python UDTF を呼び出す SELECT 文の
as句で列名を指定します。次のコマンドに例を示します。select my_udtf(col0, col1) as (ret_col0, ret_col1, ret_col2) from tmp1;
UDAF 関連の問題
-
現象 1: 「
Script exception - ValueError: unmarshallable object」というエラーメッセージが返されます。-
原因: Python UDAF コード内の
bufferが Marshal オブジェクトではないためです。 -
解決策:
bufferに値を割り当てる場合、その値が Marshal オブジェクトであることを確認してください。 たとえば、Python ユーザー定義集計関数 (UDAF) で LIST 型と DICT 型の 2 つのbufferを使用する場合、new_bufferメソッドはreturn [list(), dict()]のように定義する必要があります。iterate/merge/terminateメソッドでbuffer/pbufferを使用する場合、LIST 型のbufferはbuffer[0]/pbuffer[0]に対応し、DICT 型のbufferはbuffer[1]/pbuffer[1]に対応します。bufferの要素が LIST 型または DICT 型の場合、その要素も Marshal オブジェクトである必要があります。
-
-
現象 2: 「
Python UDAF buffer size overflowed: 2821486749」というエラーメッセージが返されます。-
原因: Python UDAF の
bufferのサイズが、Marshalによる処理後に 2 GB を超えています。bufferは不正に使用されています。bufferのサイズは、データ量と共に増加してはなりません。 -
解決策: Python UDAF のロジックを再設計します。
bufferのサイズは、データ量に応じて増加しないようにする必要があります。たとえば、bufferをlistとして宣言した場合、iterateフェーズおよびmergeフェーズ中にbufferにデータを継続的に追加することはできません。Python UDAF の詳細については、「UDAF の概要」をご参照ください。
-