Engineering overview · Google Ads schema
Google Ads P0 與延伸欄位落地總覽
一次看懂這次新增哪些 DB table/欄位、為什麼需要,以及 dashboard-mcp 與 ad-report-agent 查詢時不能忽略的資料語意。
從 P0 欄位到可持續查詢的正式資料層#
本次從 ad-report 原始文件中的 P0 需求出發,不只補齊 schema,也補上實作後確認不可缺少的資料正確性與同步能力。
26 個原始 P0 + 2 個延伸欄位
Campaign 與 Ad group 的 rate-only metrics
TrueView + 25%/50%/75%/100%
已包含獨立 attributes/rate 同步、每日排程、手動回填與 partition 維護。新增欄位不是只有 DB 結構,而是能持續寫入與重跑。
所有新增欄位都允許 NULL。Google 沒有提供、欄位不適用或實體不存在時,空值不等於同步失敗,也不等於數值 0。
既有 DB table 新增欄位#
| DB table | 新增欄位 | 範圍 | 主要使用者/原因 |
|---|---|---|---|
googleads__ad_metrics |
video_trueview_view_rate |
原始 P0 | Ad Report Agent 需要觀看率;採 Google Ads API v24 正式名稱。 |
googleads__ad_metrics |
video_quartile_p25_rate、p50、p75、p100 |
原始 P0 | Agent/MCP 需要 25%~100% 影音觀看率。 |
googleads__ad_campaign |
advertising_channel_type、advertising_channel_sub_type |
原始 P0 | 辨識 Search、Display、PMAX、Demand Gen 等 campaign 類型,取代 dashboard-mcp 的臨時 dim_campaign。 |
googleads__ad_campaign |
bidding_strategy_type、status |
原始 P0 | 解釋出價策略與啟用狀態,取代臨時表。 |
googleads__ad_campaign |
optimization_score |
原始 P0 | 提供 campaign 層最佳化分數。 |
googleads__ad_campaign |
start_date_time、end_date_time |
原始 P0 | 提供投放期間;名稱跟隨 Google Ads API v24。 |
googleads__ad_campaign |
budget_amount、target_cpa、target_roas |
原始 P0 | 分析預算與出價目標。 |
googleads__ad_campaign |
budget_id |
延伸 · 正確性 | 共用預算須依 ID 去重;沒有 ID 時,實測直接加總會高估 5.1%。 |
googleads__ad_group |
status、group_type |
原始 P0 | 提供 ad group 狀態與類型;避免與 ad 的 type 混淆。 |
googleads__ad_group |
cpc_bid、cpm_bid、target_cpa、target_roas |
原始 P0 | 提供 ad group 層出價與目標值。 |
googleads__ad |
ad_type、status、final_urls、ad_strength |
原始 P0 | 支援廣告格式、狀態、到達網址及素材強度分析。 |
googleads__keyword |
match_type |
原始 P0 | 支援 EXACT/PHRASE/BROAD 關鍵字分析。 |
googleads__ad_account |
optimization_score |
延伸 · 完整性 | 帳號層分數依花費加權;API v24 未提供還原權重,不能用 campaign 平均代替。 |
名稱與型別注意事項#
| 來源/舊名稱 | Dashboard DB 名稱 | 查詢注意事項 |
|---|---|---|
video_view_rate | video_trueview_view_rate | v24 已不接受舊名稱;值為 0~1,顯示百分比時才乘 100。 |
start_date/end_date | start_date_time/end_date_time | DB 是 CharField,格式為帳號時區的 YYYY-MM-DD HH:MM:SS。 |
budget_amount_micros | budget_amount | 已除以 10⁶,保存帳號幣別金額。 |
target_cpa_micros | target_cpa | 已除以 10⁶,保存帳號幣別金額。 |
cpc_bid_micros/cpm_bid_micros | cpc_bid/cpm_bid | 已除以 10⁶,保存帳號幣別金額。 |
ad_group.type | group_type | 避免和 googleads__ad.ad_type 混淆。 |
keyword_match_type | match_type | 已位於 keyword table,不重複保留 keyword_ 前綴。 |
final_urls | final_urls | PostgreSQL array,不是單一字串。 |
target_roas | target_roas | Ratio;例如 4.0 代表 400%。 |
budget_amount、target_cpa、cpc_bid、cpm_bid 都已換算成帳號幣別。dashboard-mcp 與 ad-report-agent 不可再次除以 10⁶。
新增 campaign/ad group rate-only table#
Rate 的正確值與資料層級綁定。為避免從 ad 明細錯誤聚合回上層,新增兩張只保存 daily rate 的 partition table。
| 新資料表 | 一筆資料/唯一鍵 | 保存內容 | 新增原因 |
|---|---|---|---|
googleads__ad_campaign_metrics |
campaign_id × date |
Campaign 單日的 5 個影音 rate | 從 ad × date × device 聚合的誤差實測可達 −64%~+53%。 |
googleads__ad_group_metrics |
group_id × date |
Ad group 單日的 5 個影音 rate | Ad group rate 同樣不能由 ad 層可靠還原。 |
只保存 rate,不複製可加總量
- Chosen
- 新表保存 TrueView 與四段 quartile rate。
- Why
- 這些值無法從 ad 層資料精確還原。
- Boundary
- Impressions、clicks、cost 仍以
googleads__ad_metrics為唯一來源。 - Write rule
- 只寫入至少一個影音 rate 有值的實體/日期。
Partition 與欄位#
兩張表都依 date 做 range partition,並對實體 ID + date 設 unique constraint,可安全重跑。Migration 另建立兩張 default partition 子表,讓年度 partition 尚未建立時仍有安全承接區。
| 資料表 | 欄位 | 用途 |
|---|---|---|
googleads__ad_campaign_metrics | id、campaign_id、date | Primary key、campaign 關聯與 partition key。 |
| 同上 | video_trueview_view_rate、四個 video_quartile_* | Campaign 層單日觀看率。 |
googleads__ad_group_metrics | id、group_id、date | Primary key、ad group 關聯與 partition key。 |
| 同上 | video_trueview_view_rate、四個 video_quartile_* | Ad group 層單日觀看率。 |
沒有 account rate table:Google 的 account 資源不支援 quartile 欄位。也沒有 search term rate table,因為實測沒有影音資料。
各層影音 rate 要查哪裡#
| 層級 | 正確資料來源 | 可否跨列直接聚合 |
|---|---|---|
| Ad | googleads__ad_metrics | 不可;每列是一個 ad 在某日、某裝置的資料。 |
| Campaign | googleads__ad_campaign_metrics | 查單日原始值;不可 SUM rate。 |
| Ad group | googleads__ad_group_metrics | 查單日原始值;不可 SUM rate。 |
| Account | Campaign rate + 可取得的正確分母,或直接查 Google API | 不可平均 campaign rate。 |
AVG(ad rate)它不等於 campaign/ad group rate。資料庫缺少 Google 計算 quartile rate 所需的完整分母。排除 NULL 只能避免把「無資料」當成 0,不能讓簡單平均變成精確上層 rate。
為資料正確性多做的工作#
下列補強不全是原始 P0 欄位,但缺少任何一項,都可能讓 Agent/MCP 產生錯誤答案或讓新欄位停止更新。
| 補強項目 | 新增 DB 欄位/表 | 原因 |
|---|---|---|
Campaign 新增 budget_id | 是 | 共用預算必須先依 budget_id 去重,不能直接 SUM(budget_amount)。 |
Account 新增 optimization_score | 是 | Campaign 分數平均與帳號真值實測相差 +2.5%/−3.1%,且方向不一致。 |
| Campaign/ad group rate-only table | 是 | 上層 rate 無法從 ad metrics 準確聚合。 |
target_cpa/target_roas 補巢狀取值 | 否 | 避免漏掉 MAXIMIZE_CONVERSIONS/MAXIMIZE_CONVERSION_VALUE 的目標值。 |
| Account ID 同時支援純數字與連字號 | 否 | 避免 DB/API ID 格式不同而沒有更新到 attributes。 |
| Attributes 獨立同步與每日排程 | 否 | 屬性只保存目前狀態,不是逐日資料,因此獨立於 metrics 流程更新。 |
| Rate 獨立同步與限流 | 否 | Staging 對齊既有 metrics 抓 D2;prod 抓 D0~D7,吸收 Google 近日延遲回填。 |
| 新表加入 partition 建立流程 | 是,屬於表結構 | 避免資料長期落入 default partition。 |
| 手動 attributes/rate commands | 否 | 支援 staging 驗證、歷史回填與失敗後冪等重跑。 |
Campaign 預算的正確加總方式#
SELECT sum(budget_amount)
FROM (
SELECT DISTINCT budget_id, budget_amount
FROM googleads__ad_campaign
WHERE account_id = %s
AND status = 'ENABLED'
AND budget_id IS NOT NULL
) AS budgets;
如何判讀空值與資料時間#
NULL 的意思是「目前沒有可用資料」,可能是不適用、沒有設定或 Google 未提供。驗收同步結果時,不應要求所有欄位 100% 有值;製作報表時,也不可把空值改成數值 0。
哪些空值是正常的#
| 情況 | DB 中的正常結果 | 代表的意思 |
|---|---|---|
| 非影音廣告 | 五個影音 rate 為 NULL | 不適用影音觀看率,不是觀看率為 0%。 |
| PMAX/SMART | 可能只有 view rate,quartile rate 為 NULL | Google 沒有提供完整四段觀看率。 |
| PMAX/SMART 偽 ad group/ad | 屬性可能全部為 NULL | Dashboard 為維持階層建立實體,但 Google 沒有對應的真實實體。 |
| Demand Gen ad group | group_type 可能為 NULL | 只有類型未提供,不能把整個 ad group 判定為同步失敗。 |
| Campaign 未設定結束日 | end_date_time 為 NULL | Campaign 沒有指定結束時間。 |
| 未使用對應出價策略 | target_cpa 或 target_roas 為 NULL | 該出價目標不適用,不代表目標值為 0。 |
| 停用 campaign | optimization_score 可能為 NULL | Google 可能不提供停用 campaign 的分數。 |
| 某實體當天沒有影音資料 | 新 rate table 沒有該列 | 當天沒有可保存的 rate,不代表排程一定失敗。 |
為什麼 NULL 不能當 0#
| 資料列 | Rate | 實際語意 |
|---|---|---|
| 影音廣告 A | 50% | 有影音資料,觀看率是 50%。 |
| 非影音廣告 B | NULL | 不適用影音觀看率。 |
若把廣告 B 的 NULL 當成 0% 再平均,就會憑空建立一個 0% 觀看率並把真實結果拉低。正確做法是排除 B;但若要 campaign/ad group 正式數值,仍應直接查對應層級 rate table。
哪些資料能回查某一天#
Metrics
Ad/campaign/ad group metrics 每天各自保存,可回答某一天的花費、點擊或影音 rate。
Attributes
Account/campaign/ad group/ad 每次同步更新同一列,只能回答最近同步時的狀態、預算與出價設定。
例如現在查到 campaign 的 status = 'PAUSED',只能知道最近一次同步時是暫停狀態,不能據此判斷上週是否也暫停。若要分析屬性歷史變化,未來必須另外建立每日快照。
Migration 對照#
| Migration | DB 變更 |
|---|---|
0009_add_video_rate_metrics | googleads__ad_metrics 新增 5 個影音 rate。 |
0010_add_campaign_and_account_attributes | Campaign 新增 11 欄;account 新增 optimization_score。 |
0011_add_adgroup_ad_attributes | Ad group 新增 6 欄;ad 新增 4 欄。 |
0012_add_keyword_match_type | Keyword 新增 match_type。 |
0013_add_level_rate_metrics_tables | 新增 campaign/ad group rate partition table。 |
若文件與程式碼出現差異,以 backend/apps/ad/platforms/googleads/models.py 為準。