【BigQuery】AI関数(AI.GENERATE_TEXT等)でQuota制限エラーが出た原因と3つの回避策

BigQueryから直接GeminiなどのLLMを呼び出せるAI関数(AI.GENERATE_TEXT や ML.GENERATE_TEXT)は、データ分析やテキスト生成をSQLだけで完結できる非常に便利な機能です。

しかし、数万行〜数百万行といった大量のデータに対してこの関数を一括で適用しようとすると、クエリが途中で失敗し、「Quota exceeded」や「RESOURCE_EXHAUSTED」といったエラーが出ることがあります。

この記事では、BigQueryのAI関数でクォータ制限エラーが発生する原因と、具体的な3つの回避策について解説します。

発生するエラーと原因

大量のデータに対してAI関数を実行すると、以下のようなエラーが発生することがあります。

RESOURCE_EXHAUSTED: Quota exceeded for quota metric 'Generate text requests'

または

rateLimitExceeded

これらのエラーが出る原因は、BigQuery自体の制限ではなく、裏側で呼び出している Vertex AI の API クォータ制限に引っかかっているためです。

BigQueryのAI関数は、各行の処理ごとに Vertex AI のモデル(Geminiなど)にリクエストを送信します。Vertex AI には、1分あたりのリクエスト数(RPM)や1分あたりのトークン数(TPM)の上限が設定されており、BigQueryからの同時実行リクエストがこの上限を瞬間的に超えてしまう(バーストする)ことで、エラーとなってしまいます。

対処法1:バッチ処理(イテレーション)で分割する【推奨】

もっとも確実で推奨される解決策は、1回のクエリで全行を処理するのではなく、未処理のデータを数千行ずつ小分けにして繰り返し処理(イテレーション)することです。

これにより、Vertex AIへのリクエストを分散させ、RPM制限の超過を防ぎます。

BigQueryのスクリプト(LOOP)を使った分割例

以下は、WHERE句で未処理のレコードだけを抽出し、一度に1,000行ずつ処理を繰り返す簡易的なSQLスクリプトの例です。

[!NOTE] BigQueryのスクリプトでは、LIMIT句に変数を直接指定するとエラーになります。変数を使いたい場合は、EXECUTE IMMEDIATEでSQL文字列を動的に組み立てる必要があります。

DECLARE batch_size INT64 DEFAULT 1000;
DECLARE unprocessed_count INT64;
DECLARE dml STRING;

-- ループ処理の開始
LOOP
  -- 未処理の行数を取得(例: ai_result が NULL の行)
  SET unprocessed_count = (
    SELECT COUNT(1) FROM `your_project.your_dataset.target_table` WHERE ai_result IS NULL
  );

  -- 未処理がなくなればループ終了
  IF unprocessed_count = 0 THEN
    LEAVE;
  END IF;

  -- EXECUTE IMMEDIATEでLIMITに変数値を埋め込んだSQLを動的生成
  SET dml = FORMAT("""
    UPDATE `your_project.your_dataset.target_table` AS t
    SET t.ai_result = r.generated_text
    FROM (
      SELECT id,
        ml_generate_text_llm_result['candidates'][0]['content']['parts'][0]['text'] AS generated_text
      FROM ML.GENERATE_TEXT(
        MODEL `your_project.your_dataset.your_llm_model`,
        (
          SELECT id, prompt
          FROM `your_project.your_dataset.target_table`
          WHERE ai_result IS NULL
          LIMIT %d
        ),
        STRUCT(0.2 AS temperature, 1024 AS max_output_tokens)
      )
    ) AS r
    WHERE t.id = r.id
  """, batch_size);

  EXECUTE IMMEDIATE dml;

END LOOP;

実運用では、DataformやAirflow(Cloud Composer)を利用して、このバッチ処理を定期実行するパイプラインを組むのが一般的です。

対処法2:クエリ対象データの最適化

そもそも不要なリクエストを送らないように、対象データを極力減らすことも重要です。

  • WHERE句での絞り込み: AI関数を通す必要のない行(すでに分類済みのデータや、ノイズデータなど)は事前に WHERE 句で除外します。
  • 結果のキャッシュ: 一度AIモデルで生成した結果は、別のテーブルに保存(CREATE TABLE ... AS ... または MERGE)しておき、同じ入力に対して何度もAI関数を呼び出さないように設計します。

対処法3:Google Cloudコンソールからのクォータ引き上げ申請

最適化やバッチ分割を行っても、データ規模に対して上限が厳しすぎる場合は、Vertex AI側のクォータの引き上げを申請します。

  1. Google Cloud コンソールの [IAM と管理] > [割り当て] に移動します。
  2. フィルタで「Vertex AI API」または「Agent Platform API」を検索します。
  3. 利用しているモデルの Generate text requests per minute や Tokens per minute の項目を見つけます。
  4. 該当する項目にチェックを入れ、[割り当てを編集] から必要な上限値の引き上げをリクエストします。

[!WARNING] クォータを引き上げると、リクエストが通るようになりますが、それに伴い Vertex AI の従量課金コストも急激に増加する可能性があります。事前にコスト見積もりを行い、予算アラートを設定しておくことを強くおすすめします。

まとめ

BigQueryのAI関数で「Quota exceeded」エラーが出た場合のポイントです。

  • エラーの原因はBigQueryではなく、裏側の Vertex AI (Gemini等) のAPIリクエスト上限(RPM/TPM) によるもの。
  • 1回のクエリで全行を処理せず、LOOPやDataformを使って小分けにバッチ処理するのが基本。
  • 不要な行は事前に除外し、結果は必ずテーブルに保存(キャッシュ)する。

大量のデータをAIで一気に処理できるのは魅力的ですが、システム全体のリソース制限を意識したアーキテクチャ設計を心がけましょう。

参考情報