Google Ad Manager REST API と BigQuery の連携によるレポート自動化システムの構築

はじめに

こんにちは、トモニテで開発を担当している吉田です。
デジタル広告の運用において、広告パフォーマンスの分析とレポート作成は重要な業務の一つです。しかし、弊社では手動でレポートを作成しており、営業活動に集中する時間を削ってしまう課題がありました。

本記事では、Google Ad Manager(GAM)の REST API と BigQuery を連携させ、レポート作成を自動化するシステムの構築事例について、紹介します。

背景:セールスレポート作成の課題

ビジネス課題

セールスチームが Google Ad Manager の広告レポートを手動で作成する際、以下の課題に直面していました。

  • レポート作成工数の嵩み: 現状 30 分〜1 時間程度の工数が発生
  • データ抽出の複雑さ: GAM から直接データを取得する手間
  • 営業活動時間の減少: レポート作成に時間を取られ、営業活動に集中できない

期待される成果

レポート作成の自動化により、以下の成果を期待しました。

  • 工数削減: レポート作成時間の短縮
  • 営業活動の強化: レポート作成時間を営業活動に充て、売上貢献の向上
  • データ活用の効率化: BigQuery での SQL による柔軟なデータ抽出

技術選定:REST API の採用

既存システムの課題

社内の別サービスでは、Google Ad Manager の SOAP API を使用していました。しかし、以下の理由から REST API(現在 Beta 版)で実装することを決定しました。

項目 SOAP API REST API
実装の複雑さ XML ベースで複雑 JSON ベースでシンプル
エラーハンドリング 複雑な XML パースが必要 標準的な HTTP ステータスコード
デバッグの容易さ XML ログの可読性が低い JSON ログで直感的
メンテナンス性 古い技術スタック モダンな技術スタック
ドキュメント 限定的 豊富で分かりやすい

REST API の選択理由

  1. 開発効率の向上: JSON ベースのシンプルな実装
  2. 保守性の向上: モダンな技術スタックによる将来性
  3. エラー処理の簡素化: 標準的な HTTP レスポンスの活用
  4. チーム開発の効率化: より直感的な API 設計

注意: Google Ad Manager REST API は現在 Beta 版のため、本番環境での使用には注意が必要です。API の仕様変更や制限事項について、公式ドキュメントを定期的に確認することをお勧めします。

システムアーキテクチャ

全体構成

  1. Cloud Run: メイン処理コンテナ
    • GAM REST API を呼び出してレポートデータを取得
    • 取得したデータを BigQuery に格納
  2. GAM REST API: 広告データの提供
  3. BigQuery: データの保存と分析

データフロー

  1. 実行開始: Cloud Run が HTTP リクエストまたはイベントで実行
  2. 日付抽出: リクエストから対象日付を取得
  3. レポート生成: GAM API を使用してレポートデータを取得
  4. BigQuery 挿入: 取得したデータを BigQuery に保存

GAM REST API の実装詳細

API クライアントの初期化

from google.ads import admanager_v1


client = admanager_v1.ReportServiceClient()

レポート定義の作成

GAM REST API では、レポートの構造を詳細に定義する必要があります。

def create_report_definition(target_date: date, dimensions: list, metrics: list) -> admanager_v1.Report:
    """GAMレポートの定義を作成"""
    report = admanager_v1.Report()

    
    report.report_definition.dimensions = dimensions
    report.report_definition.metrics = metrics
    report.report_definition.report_type = admanager_v1.types.Report.ReportType.HISTORICAL

    
    report.report_definition.filters = [
        admanager_v1.types.Report.Filter(
            field_filter=admanager_v1.types.Report.Filter.FieldFilter(
                field=admanager_v1.types.Report.Field(
                    dimension=admanager_v1.types.Report.Dimension.AD_UNIT_NAME
                ),
                operation=admanager_v1.types.Report.Filter.Operation.MATCHES,
                values=[
                    admanager_v1.types.Report.Value(string_value="PREFIX_.*")
                ]
            )
        )
    ]

    
    report.report_definition.date_range.fixed = admanager_v1.types.Report.DateRange.FixedDateRange(
        start_date=date_pb2.Date(
            year=target_date.year,
            month=target_date.month,
            day=target_date.day
        ),
        end_date=date_pb2.Date(
            year=target_date.year,
            month=target_date.month,
            day=target_date.day
        )
    )

    return report

レポートの実行とデータ取得

def create_and_run_report(client: admanager_v1.ReportServiceClient, report: admanager_v1.Report) -> str:
    """GAMレポートを作成して実行"""
    
    request = admanager_v1.CreateReportRequest(
        parent=f"networks/{NETWORK_ID}",
        report=report,
    )
    create_response = client.create_report(request=request)
    report_id = create_response.report_id

    
    run_request = admanager_v1.RunReportRequest(
        name=f"networks/{NETWORK_ID}/reports/{report_id}"
    )
    operation = client.run_report(request=run_request)
    run_result = operation.result()

    return run_result.report_result

データの抽出と変換

GAM API から取得したデータを Pandas DataFrame に変換する処理です。

def extract_dimension_value(dim_value) -> any:
    """ディメンション値を抽出"""
    if dim_value.string_value:
        return dim_value.string_value
    elif dim_value.int_value:
        return dim_value.int_value
    elif dim_value.double_value:
        return dim_value.double_value
    
    else:
        return None

def extract_metric_value(primary_value) -> any:
    """メトリクス値を抽出"""
    if primary_value.int_value:
        return int(primary_value.int_value)
    elif primary_value.double_value:
        return primary_value.double_value
    else:
        return None

def fetch_report_data(client: admanager_v1.ReportServiceClient, report_result_name: str, column_names: list[str]) -> pd.DataFrame:
    """レポートデータを取得してDataFrameに変換"""
    fetch_request = admanager_v1.FetchReportResultRowsRequest(
        name=report_result_name
    )

    rows_response = client.fetch_report_result_rows(request=fetch_request)

    rows_list = []
    for row in rows_response:
        row_data = []

        
        for dim_value in row.dimension_values:
            row_data.append(extract_dimension_value(dim_value))

        
        for metric_group in row.metric_value_groups:
            for primary_value in metric_group.primary_values:
                row_data.append(extract_metric_value(primary_value))

        rows_list.append(row_data)

    df = pd.DataFrame(rows_list, columns=column_names)
    return df

BigQuery との連携設計

スキーマ設計の考え方

BigQuery へのデータ保存では、以下の設計思想を採用しました。

  1. 日付別テーブル分割: パフォーマンスとコスト最適化
  2. 型安全性の確保: 適切なデータ型の設定
  3. 効率的なクエリ: 分析に適したスキーマ設計

スキーマ定義

以下のスキーマ定義は一例です。実際のプロジェクトでは、ビジネス要件や分析ニーズに応じて適切なカラム名とデータ型を設定してください。

DIMENSION_SCHEMA = [
    bigquery.SchemaField("date", "INTEGER"),
    bigquery.SchemaField("advertiser_name", "STRING"),
    bigquery.SchemaField("advertiser_id", "INTEGER"),
    bigquery.SchemaField("order_name", "STRING"),
    bigquery.SchemaField("order_id", "INTEGER"),
    bigquery.SchemaField("line_item_type", "STRING"),
    bigquery.SchemaField("line_item_name", "STRING"),
    bigquery.SchemaField("line_item_id", "INTEGER"),
    bigquery.SchemaField("ad_unit", "STRING"),
    bigquery.SchemaField("ad_unit_id", "INTEGER"),
    bigquery.SchemaField("demand_channel_name", "STRING"),
    bigquery.SchemaField("creative_name", "STRING"),
    bigquery.SchemaField("creative_id", "INTEGER"),
]


METRICS_SCHEMA = [
    bigquery.SchemaField("total_impressions", "INTEGER"),
    bigquery.SchemaField("total_clicks", "INTEGER"),
    bigquery.SchemaField("total_ctr", "FLOAT"),
]

BigQuery へのデータ挿入

def insert_df_to_bigquery(df: pd.DataFrame, target_date: date, bigquery_schema: list[bigquery.SchemaField], table_name: str):
    """Pandas DataFrameをBigQueryに挿入"""
    client = bigquery.Client()

    job_config = bigquery.LoadJobConfig(
        schema=bigquery_schema,
        write_disposition=bigquery.WriteDisposition.WRITE_TRUNCATE,
    )

    date_str = target_date.strftime('%Y%m%d')
    table_id = f"{PROJECT_ID}.{DATASET}.{table_name}_{date_str}"

    job = client.load_table_from_dataframe(df, table_id, job_config=job_config)
    job.result()

Cloud Run の実装

メイン処理の実装

@cloud_event
def main(cloud_event: CloudEvent) -> None:
    """Cloud Run のエントリーポイント"""
    try:
        
        target_date = extract_target_date(cloud_event)

        
        df = get_gam_report_data(dimensions, metrics, column_names, target_date)

        
        insert_df_to_bigquery(df, target_date, schema, table_name)

        print("レポート処理が完了しました")

    except Exception as e:
        print(f"処理でエラーが発生しました: {e}")
        raise e

運用面での工夫

Cloud Run のデプロイと実行

Cloud Run のデプロイは gcloud コマンドで行い、以下の設定で実行されます。

  • Region: asia-northeast1
  • Runtime: Python 3.13
  • Memory: 512MB
  • Trigger: HTTP

手動実行のためのコマンド

運用効率を向上させるため、以下のような手動実行用のコマンドを作成しました。

  • 単独日付指定: 特定の日付のレポートを生成
  • 範囲指定: 開始日から終了日までの期間でレポートを一括生成

これらのコマンドにより、スケジュール実行以外にも必要に応じて柔軟にレポートを生成できるようになっています。

システムの実行方式

システムは Cloud Run として実装されており、様々な実行パターンに対応できます。例えば、以下のような方法があります。

  • 手動実行: HTTP トリガーによる直接実行
  • スケジュール実行: Cloud Scheduler による定期実行
  • イベント駆動: Pub/Sub や Eventarc を経由した実行

ブログ内で言及はしていませんが、弊社では Cloud Scheduler から Pub/Sub トピックを起動し、サブスクリプションを通じて Cloud Run を定期実行する仕組みを構築しています。この仕組みにより、毎日決まった時間にレポートデータが自動的に更新され、手動作業を大幅に削減できています。

実装で得られた知見

1. GAM REST API の特徴

メリット:

  • JSON ベースで直感的な実装
  • 豊富なドキュメントとサンプルコード
  • 標準的な HTTP エラーハンドリング

注意点:

  • レポート実行は非同期処理のため、完了待ちが必要
  • 大量データの場合はページネーションが必要
  • レート制限に注意が必要

2. BigQuery との連携

最適化のポイント:

  • 日付別テーブル分割によるクエリ性能向上
  • 適切なスキーマ設計によるストレージコスト削減
  • WRITE_TRUNCATE モードによる冪等性の確保

成果と今後の展望

期待される成果

  1. 工数削減: レポート作成時間の短縮(現状 30 分〜1 時間)
  2. 営業活動の強化: レポート作成時間を営業活動に充て、売上貢献の向上
  3. データ活用の効率化: BigQuery での SQL による柔軟なデータ抽出

まとめ

Google Ad Manager REST API と BigQuery の連携により、セールスレポート作成の自動化を実現しました。

このシステムにより、セールスチームが営業活動により多くの時間を割けるようになり、結果として売上の向上に貢献することが期待されます。

同様の課題を抱えている組織の参考になれば幸いです。

参考

developers.google.com

googleapis.dev

googleapis.dev

cloud.google.com




元の記事を確認する

関連記事