🔍

エラーメッセージからBigQueryエディタURLを生成する

2024/12/07に公開

この記事はBigQuery Advent Calendar 2024 7日目の記事です。

はじめに

本記事では、BigQueryをPythonで操作する基本的なコード例とともに、エラー処理を効率化する方法を解説します。

BigQueryをPythonで操作する基本的なコード例

まずは、PythonでBigQueryに接続し、テーブルからデータを取得するシンプルな例を紹介します。このコードは、エラー処理なしの基本的な流れを示しています。
※事前に設定が必要なBigQueryの認証設定については説明を割愛します

test.py
from google.cloud import bigquery

try:
  # BigQueryクライアントの初期化
  client = bigquery.Client()

  # クエリの定義
  query_string = """
    SELECT count(*) AS count FROM project_id.dataset_id.table_id
  """

  # クエリの実行
  query_job = client.query(query_string)
  query_result = query_job.result()

  # データをDataFrameとして取得
  df = query_result.to_dataframe()
  print(df)

except Exception as e:
  print(e)

コードの解説

  1. BigQueryクライアントの初期化: bigquery.Client()を使ってクライアントを作成します。認証情報が必要です。
  2. クエリの実行: client.query()でSQLクエリを実行し、結果を取得します。
  3. 結果の変換: クエリ結果をto_dataframe()でPandas DataFrame形式に変換し、データを操作可能にします。

実行結果

結果(成功例)
$ python test.py

   count
0     21
結果(エラー例)
$ python test.py

400 Invalid project ID 'project_id'. Project IDs must contain 6-63 lowercase letters, digits, or dashes. Some project IDs also include domain name separated by a colon. IDs must start with a letter and may not end with a dash.; reason: invalid, location: project_id.dataset_id.table_id, message: Invalid project ID 'project_id'. Project IDs must contain 6-63 lowercase letters, digits, or dashes. Some project IDs also include domain name separated by a colon. IDs must start with a letter and may not end with a dash.

Location: US
Job ID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

エラー発生時に、取得したLocationJob IDを下記のURLに埋め込んでアクセスするとBigQueryのエディタ画面からエラー特定しやすくなります。
今回の記事はLocationJob IDを取得してURLをログ表示するそんな記事です。以上

https://console.cloud.google.com/bigquery?project={project_id}&j=bq:{location}:{job_id}&page=queryresults

BigQueryエディタ

エディタURLを生成する機能を組み込む

上記のコードはシンプルですが、エラーが発生した場合に十分な情報を提供しません。次に、エラーハンドリングを強化した例を紹介します。

エディタURLを生成する機能を追加したコード

以下のコードは、handle_bq_error関数を利用して、エラー内容とBigQueryエディタへのリンクを出力します。

from google.cloud import bigquery

def handle_bq_error(error, message=None):
    """
    BigQueryエラーを処理する関数。
    エラーメッセージを抽出し、関連するBigQueryエディタのリンクを生成してログに出力する。

    :param error: BigQueryエラーオブジェクト
    :param message: 任意の追加メッセージ(デフォルトは None)
    :raises Exception: 詳細メッセージを含む例外
    """
    # エラー内容を抽出し、改行区切りでメッセージを結合
    error_msg = "\n".join([item["message"] for item in error.errors])

    # エラーがジョブに関連している場合、BigQueryエディタURLを生成
    if hasattr(error, "query_job"):
        location = error.query_job.location
        project_id = error.query_job.project
        job_id = error.query_job.job_id

        # エディタでジョブの詳細を確認するためのリンク
        bq_console_url = f"https://console.cloud.google.com/bigquery?project={project_id}&j=bq:{location}:{job_id}&page=queryresults"
        print(f"\033[31m[ERROR]\033[0m BigQuery Job Link: {bq_console_url}")
    else:
        # ジョブ情報が存在しない場合の処理
        print("\033[31m[ERROR]\033[0m No query job information available in the error.")

    # エラーメッセージを出力
    print(f"\033[31m[ERROR]\033[0m {error_msg}")

    # 例外をスロー
    raise Exception(message or error_msg)


try:
    # BigQueryクライアントの初期化
    client = bigquery.Client()

    # 実行するクエリを定義
    query_string = """
      SELECT count(*) AS count FROM project_id.dataset_id.table_id
    """

    # クエリを実行
    query_job = client.query(query_string)

    # クエリ結果を取得
    query_result = query_job.result()

    # 結果をPandas DataFrameに変換
    df = query_result.to_dataframe()

    # 結果を出力
    print(df)

# エラーが発生した場合にエラーハンドリングを実行
except Exception as e:
    handle_bq_error(e, "BigQueryでエラーが発生しました")

改善後結果(エラー例)
$ python test.py

[ERROR] BigQuery Job Link: https://console.cloud.google.com/bigquery?project=project_id&j=bq:US:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx&page=queryresults

改善点

  • エラー発生時にエディタURLを生成し、ジョブの詳細を直接確認できる。
  • 複数のエラーを結合して出力し、問題の全体像を把握しやすくしている。

おわりに

今回紹介したhandle_bq_error関数をプロジェクトに組み込むことで、エラー原因の特定やデバッグが多少効率的になります。
エラー表示は今回printで書いてますが適宜好きなものに書き換えてください。

小ネタ

エラー出力、色つくと見やすいですね

print(f"\033[31m[ERROR]\033[0m " + "This is an error message.")
print(f"\033[33m[WARNING]\033[0m " + "This is a warning message.")
print(f"\033[32m[INFO]\033[0m " + "This is an informational message.")
print(f"\033[34m[DEBUG]\033[0m " + "This is a debug message.")

参考

https://cloud.google.com/bigquery/docs/error-messages?hl=ja
https://github.com/dbt-labs/dbt-bigquery

Discussion