注: 以下の翻訳の正確性は検証されていません。AIPを利用して英語版の原文から機械的に翻訳されたものです。
このガイドでは、Python トランスフォームで利用可能なデバッグ手法の概要を説明します。エラーと例外の詳細については、Python ドキュメント ↗を参照してください。
デバッガーは、Python トランスフォームの問題を特定して解決するために役立つツールです。ブレークポイントを設定してトランスフォームの実行を一時停止し、変数の確認、DataFrame の表示、関数やライブラリの理解に役立てることができます。
使用する IDE のデバッガーについて、詳しくはこちらをご覧ください。
Python のトレースバックは、エラーに至るまでの関数呼び出しの順序を含むエラーメッセージで、ほかのプログラミング言語ではスタックトレースとも呼ばれます。Python では、処理されていない例外が発生するとトレースバックが出力され、最後の呼び出しが一番下に表示されます。
Python トランスフォームの実行時の失敗は、ほとんどの場合トレースバックとして表示されるため、その読み方を理解することが重要です。
次のコード例を見てみましょう。
Copied!1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20class Stats(object): nums = [] def add(self, n): self.nums.append(n) def sum(self): return sum(self.nums) def avg(self): return self.sum() / len(self.nums) def main(): stats = Statistics() stats.add(1) stats.add(2) stats.add(3) print(stats.avg())
このコードを実行すると、次のトレースバックが出力されます。
Copied!1 2 3 4 5 6Traceback (most recent call last): File "test.py", line 26, in <module> main() File "test.py", line 16, in main stats = Statistics() NameError: global name 'Statistics' is not defined
ほかのプログラミング言語のスタックトレースとは異なり、Python のトレースバックでは最後の呼び出しが末尾に表示されます。下から上に読むと、トレースバックには次の情報が表示されています。
NameError ↗。Python の組み込み例外クラス ↗は数多くありますが、コードで独自の例外クラスを定義することもできます。global name 'Statistics' is not defined。このメッセージには、デバッグに最も役立つ情報が含まれています。File "test.py", line 26, in <module> に続いて、該当するコード行(16行目)が表示されます。このトレースバックから、例外は test.py の main メソッドの16行目で発生していることがわかります。具体的には、エラーの原因となっているコード行は stats = Statistics() で、スローされた例外は NameError です。このことから、Statistics という名前が存在しないと推測できます。コード例を振り返ると、Statistics ではなく Stats という名前を使用するべきだったと考えられます。
ロギングには、次の方法を使用できます。
print 文。この方法は標準(軽量)トランスフォームでサポートされていますが、Spark トランスフォームではサポートされていません。INFO レベル以上のログのみです。ログは、VS Code の出力、および Builds アプリケーションのアクション > ログを見るから確認できます。
次のコード例では、デバッグに役立つログを出力する方法を示します。
Copied!1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16from transforms.api import transform, Input, Output import polars as pl import logging log = logging.getLogger(__name__) @transform.using( output=Output("/path/output"), input=Input("/path/input"), ) def my_compute_function(output, input): input_df = input.polars() log.info("Number of rows: %d", input_df.height) print("Number of columns: " + str(input_df.width)) output.write_table(input_df)
Copied!1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17from transforms.api import transform, Input, Output import polars as pl import logging log = logging.getLogger(__name__) @transform.using( output=Output("/path/output"), input=Input("/path/input"), ) def my_compute_function(ctx, output, input): conn = ctx.duckdb().conn input_df = conn.sql("SELECT * FROM input").fetchdf() log.info("Number of rows: %d", input_df.shape[0]) print("Number of columns: " + str(input_df.shape[1])) output.write_table(input_df)
Copied!1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16from transforms.api import transform, Input, Output import pandas as pd import logging log = logging.getLogger(__name__) @transform.using( output=Output("/path/output"), input=Input("/path/input"), ) def my_compute_function(output, input): input_df = input.pandas() log.info("Number of rows: %d", input_df.shape[0]) print("Number of columns:" + str(input_df.shape[1])) output.write_table(input_df)
Copied!1 2 3 4 5 6 7 8 9 10 11 12 13 14 15from transforms.api import transform_df, Input, Output from myproject.datasets import utils import logging log = logging.getLogger(__name__) @transform_df( Output("/path/output"), input=Input("/path/input"), ) def my_compute_function(input): log.info("Number of rows: %d", input.count()) log.info("Number of columns: %d", len(input.columns)) return input
Spark トランスフォームでログを扱う方法の詳細については、Spark のロギングを参照してください。
テレメトリの統計タブを使用すると、メモリー不足(OOM)エラーやビルドの遅延など、リソースに関連する問題を診断できます。このタブにはメモリーと CPU の使用率のグラフが表示され、トランスフォームがメモリー律速なのか、CPU 律速なのか、あるいは割り当てられたリソースよりも少ないリソースしか使用していないのかを確認できます。
ビルドメトリクスにアクセスするには、次の手順に従います。
メモリーと CPU の使用率メトリクスの解釈について、詳しくはこちらをご覧ください。
テレメトリの統計タブは、軽量コンピュートエンジンを使用するトランスフォームで利用できますが、Spark トランスフォームでは利用できません。