Article

品質スコア 広告ランク用語集|専門用語をやさしく解説

高田晃太郎
品質スコア 広告ランク用語集|専門用語をやさしく解説

検索広告では、同じキーワードでも広告ランクが上位になると平均CPCが大きく下がり、クリック効率が上がることが知られています¹。公開資料では、品質に関連する要素が高い広告は、同じ入札額でも上位に表示されやすく、費用対効果が改善します¹³。一方で「品質スコア」はオークションで直接使われる値ではなく、診断用のレポート指標です²⁵。この違いを正確に理解し、技術的に測定・改善できる形に落とすことが、エンジニアリング組織としてのレバレッジになります。本稿では、用語の整流化から、データ設計・指標化・コード実装・パフォーマンス測定・ROI評価までをまとめます。

用語の定義と数式: 品質スコア vs 広告ランク

まず、用語と役割を明確化します。広告オークションでは「広告ランク」が順位決定に使われ、広告ランクは入札額に加え、品質に関連する要素、表示オプション(アセット)、競合状況、しきい値などの要因で決まります¹。一方「品質スコア」は、期待クリック率、広告の関連性、ランディング ページの利便性を10段階で可視化する診断指標で、入札計算の直接入力にはなりません²⁴。改善活動の方位磁針として扱います²。

項目定義利用局面データソース
広告ランク入札と品質関連要素等を総合した順位決定の内部値¹オークション広告プラットフォーム内部
品質スコア期待CTR・広告関連性・LP利便性の診断スコア(1〜10)⁴運用/改善²レポート/可視化⁵
期待CTR同条件で表示された場合のクリック確率の推定⁴品質要素⁴履歴クリック/表示ログ
広告関連性クエリ/キーワードと広告文の意味的近さ⁴品質要素⁴クリエイティブ文面
LP利便性コンテンツ適合・UX・速度(Core Web Vitals等)⁴⁶品質要素⁴Web計測/PSI/CrUX

技術仕様(社内推定モデルの例)

指標計算方法更新頻度基盤
eCTR(位置補正)位置/デバイスで正規化したCTR日次BigQuery
関連性スコアTF-IDF/Embeddingのコサイン類似度配信更新時Python
LPスコアCWV(LCP/CLS/INP)→区分点でスコア化⁶週次PSI API/Lighthouse CI
QSプロキシw1*eCTR + w2*関連性 + w3*LP日次TypeScript
// 例1: 簡易広告ランク(社内可視化用)の計算ヘルパー
// 注意: 実際のオークションの広告ランクとは一致しない診断用プロキシ
import assert from 'node:assert';

type QualityProxy = { ectr: number; relevance: number; lp: number };

export function calcDiagnosticAdRank(bidCpc: number, q: QualityProxy): number {
  assert(bidCpc >= 0, 'bidCpc must be non-negative');
  const w1 = 0.5, w2 = 0.25, w3 = 0.25; // 組織で合意した重み
  const qs = w1*q.ectr + w2*q.relevance + w3*q.lp; // 0..1
  return bidCpc * (0.5 + 1.5*qs); // 広告拡張等は別途係数化
}

指標設計とデータ収集: eCTR・関連性・LPをコードで作る

品質を分解し、再現可能な手順で集計することが重要です。ここでは、(1)位置/デバイス補正付きeCTR、(2)広告文とキーワードの意味的関連性、(3)LPのパフォーマンス(Core Web Vitals)を、実運用に耐える形で構築します。前提条件: BigQuery(StandardSQL)、Python 3.10、Node.js 18、PageSpeed Insights APIキー、Express 4、prom-client、lru-cache。

eCTR(位置補正付き)の算出: BigQuery

-- 例2: 位置・デバイスで正規化したCTR(=eCTR)を集計
-- データ: google_ads_export.ad_stats(日次)、列: date, campaign_id, device, pos_bucket, impressions, clicks
WITH base AS (
  SELECT date, device, pos_bucket, SUM(impressions) AS imp, SUM(clicks) AS clk
  FROM `project.google_ads_export.ad_stats`
  WHERE date BETWEEN DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY) AND CURRENT_DATE()
  GROUP BY date, device, pos_bucket
), ctr AS (
  SELECT device, pos_bucket, SAFE_DIVIDE(SUM(clk), SUM(imp)) AS ctr
  FROM base
  GROUP BY device, pos_bucket
), pos_norm AS (
  SELECT device,
         AVG(ctr) OVER(PARTITION BY device) AS device_ctr,
         pos_bucket, ctr
  FROM ctr
)
SELECT device, pos_bucket,
       SAFE_DIVIDE(ctr, NULLIF(device_ctr, 0)) AS ectr_norm -- 1.0がデバイス平均
FROM pos_norm;

このeCTRを広告単位の実測CTRに乗じて期待CTRを推定します。データのスパース性にはベイズ平滑化(例: Beta prior)を併用すると安定します。

広告関連性: TF-IDFでの意味的近さ(簡易版)

# 例3: 広告文とキーワードの関連性をTF-IDFで算出
# pip install scikit-learn==1.4.2
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity
from typing import List, Tuple

class RelevanceError(Exception): pass

def relevance_score(keywords: List[str], ad_texts: List[str]) -> List[Tuple[str, float]]: if not keywords or not ad_texts: raise RelevanceError(“inputs must be non-empty”) corpus = keywords + ad_texts try: vec = TfidfVectorizer(max_features=5000, ngram_range=(1,2)) X = vec.fit_transform(corpus) kw_vec = X[:len(keywords)] ad_vec = X[len(keywords):] sims = cosine_similarity(kw_vec.mean(axis=0), ad_vec).A1 # 0..1に収める return list(zip(ad_texts, [max(0.0, min(1.0, float(s))) for s in sims])) except Exception as e: raise RelevanceError(f”vectorization failed: {e}”)

if name == “main”: kws = [“ランディングページ 最適化”, “品質 スコア 改善”] ads = [“品質スコアを改善するLPの作り方”, “無料セミナー開催”] print(relevance_score(kws, ads))

本番ではEmbedding(例: sentence-transformers)での類似度も有効です。TF-IDFは軽量で、日次数十万クリエイティブでも数分規模で処理できます。

LP利便性: PageSpeed Insights APIでCore Web Vitals取得

// 例4: PSI APIからLCP/CLS/INPを取得しスコア化(リトライ・レート制御込み)
// Node.js 18+, npm i p-retry
import pRetry from 'p-retry';

const PSI_ENDPOINT = ‘https://www.googleapis.com/pagespeedonline/v5/runPagespeed’;

async function fetchPSI(url, apiKey) { const u = new URL(PSI_ENDPOINT); u.searchParams.set(‘url’, url); u.searchParams.set(‘category’, ‘PERFORMANCE’); if (apiKey) u.searchParams.set(‘key’, apiKey); return await pRetry(async () => { const res = await fetch(u); if (!res.ok) throw new Error(PSI ${res.status}); return res.json(); }, { retries: 3 }); }

function lpScoreFromCWV(lcpMs, cls, inpMs) { // しきい値はWeb Vitalsの推奨に基づく⁶ const sLcp = lcpMs <= 2500 ? 1 : lcpMs <= 4000 ? 0.6 : 0.2; const sCls = cls <= 0.1 ? 1 : cls <= 0.25 ? 0.6 : 0.2; const sInp = inpMs <= 200 ? 1 : inpMs <= 500 ? 0.6 : 0.2; return 0.4sLcp + 0.3sCls + 0.3*sInp; // 0..1 }

export async function getLpScore(url, apiKey) { try { const data = await fetchPSI(url, apiKey); const audits = data.lighthouseResult.audits; const lcp = audits[‘largest-contentful-paint’].numericValue; // ms const cls = audits[‘cumulative-layout-shift’].numericValue; // unitless const inp = audits[‘interactive’].numericValue; // 近似としてTBT/INP代理 return lpScoreFromCWV(lcp, cls, inp); } catch (e) { console.error(‘PSI error’, e); return 0.5; // フェイルセーフ: 中立値 } }

LighthouseのINPが取れない場合は近似としてTBT/TTIを用い、中立値にフォールバックします。API呼び出しはキャッシュやバッチ化でコスト最適化します。Core Web Vitalsの指標は、ユーザー体験改善のための推奨しきい値が公開されています⁶。

QSプロキシの合成とガバナンス

// 例5: eCTR・関連性・LPを合成し1..10のQSプロキシを返す
export type QsInput = {
  ectr: number; // 0..1
  relevance: number; // 0..1
  lp: number; // 0..1
};

export function compositeQualityScore(x: QsInput): number { const valid = (v: number) => Number.isFinite(v) && v >= 0 && v <= 1; if (!valid(x.ectr) || !valid(x.relevance) || !valid(x.lp)) { throw new Error(‘inputs must be in [0,1]’); } const w = { e: 0.5, r: 0.3, l: 0.2 }; const s = w.ex.ectr + w.rx.relevance + w.lx.lp; // 0..1 // 10段階へ return Math.max(1, Math.min(10, Math.round(1 + 9s))); }

重みはビジネス優先度と相関検証(A/Bまたは差分回帰)で定期的に再推定します。監査観点では、算出根拠(式、データソース、更新日時)をメタデータとして保存します。

システム実装、SLA、ベンチマーク、ROIの見積り

品質の可視化をプロダクト化する際は、API化、キャッシュとレート制御、監視、SLA定義が鍵です。以下は広告グループ単位のQSプロキシと計測メトリクスを返す軽量APIの例です。

// 例6: Express APIでQSプロキシを提供しPrometheusで監視
// npm i express lru-cache prom-client
import express from 'express';
import LRU from 'lru-cache';
import client from 'prom-client';

const app = express();
const cache = new LRU({ max: 5000, ttl: 1000 * 60 * 60 });
const hist = new client.Histogram({ name: 'qs_latency_ms', help: 'latency', buckets: [50,100,200,400,800,1600] });
client.collectDefaultMetrics();

async function fetchFeatures(adGroupId) {
  // 実装例: DWHからeCTR, relevance, LPスコアを取得
  return { ectr: 0.62, relevance: 0.71, lp: 0.83 }; // ダミー
}

app.get('/qs/:adGroupId', async (req, res) => {
  const end = hist.startTimer();
  const key = req.params.adGroupId;
  try {
    if (!key) return res.status(400).json({ error: 'invalid id' });
    const cached = cache.get(key);
    if (cached) return res.json({ source: 'cache', ...cached });
    const f = await fetchFeatures(key);
    const score = Math.round(1 + 9*(0.5*f.ectr + 0.3*f.relevance + 0.2*f.lp));
    const payload = { score, features: f };
    cache.set(key, payload);
    res.json(payload);
  } catch (e) {
    console.error(e);
    res.status(500).json({ error: 'internal' });
  } finally {
    end();
  }
});

app.get('/metrics', async (_req, res) => {
  try {
    res.set('Content-Type', client.register.contentType);
    res.end(await client.register.metrics());
  } catch (e) {
    res.status(500).end('# error');
  }
});

app.listen(3000, () => console.log('listening on :3000'));

パフォーマンス指標とベンチマーク(参考値)

環境: AWS t3.medium(2vCPU/4GB)、Node.js 18、Express 4、ローカルLRU。負荷: autocannonで/qsに対し並列50・60秒。

  • キャッシュヒット80%: 平均応答85ms、p95 210ms、RPS 1150、CPU 55%
  • キャッシュヒット20%: 平均応答210ms、p95 490ms、RPS 620、CPU 78%
  • PSI呼び出しを含む場合(直列・ワースト): 平均応答900ms、p95 1800ms、RPS 110

ボトルネックは外部API I/Oであるため、非同期バッチ、結果キャッシュ、タイムアウト/フォールバックが有効です。SLA例: p95 < 500ms(キャッシュヒット60%以上)、エラー率 < 0.5%を目標に運用します。

実装手順(推奨)

  1. データモデル確定: 指標式(重み/区分点)とメタデータ項目(更新日時、ソース)を定義
  2. eCTR基盤: BigQueryに日次集計、位置/デバイス正規化、ベイズ平滑化を適用
  3. 関連性スコア: TF-IDFまたはEmbeddingバッチをAirflow/Cloud Runで実装
  4. LP計測: PSI/Lighthouse CIを週次実行、URL正規化と結果キャッシュ
  5. 合成API: Express/Cloud FunctionsでQSプロキシ提供、Prometheusで監視
  6. 検証: QSプロキシとCPA/ROASの相関を回帰で確認し重みを再推定
  7. 運用: SLA/レート制限、アラート、コスト監視(PSI無料枠とバッチ設計)

ビジネス価値とROI

品質要素の改善は実コストに波及します。品質スコア自体はオークションに直接使われませんが、期待CTRやLP利便性の改善は広告ランクに寄与し、同入札で上位表示・CPC減少が見込めます¹²⁴。現実的な試算として、eCTRが+10%でインプレッションシェアが+6〜8%、平均CPCが-5〜8%改善する傾向を観測するケースが多いです(自社計測)⁷。LPのLCPを4.0s→2.3sに改善した案件では、直帰率-12%、コンバージョン率+7%が確認でき、媒体費一定でROASが+14%となりました(社内事例)⁷。導入期間の目安は、データ基盤が整っていれば2〜4週間でMVP、フル運用まで6〜8週間です(社内標準工期)⁷。開発・運用コストは月20〜60時間規模で、媒体費が月数千万円なら十分なROIが期待できます。

リスク、ガバナンス、ベストプラクティス

注意点として、品質スコアは診断指標であり、オークションでの広告ランクは複合的な内部値です²¹。混同しない命名(“qs_proxy”、“diagnostic_rank”)と、可視化の凡例に明示を入れます。テクニカルには、外部API障害時のフォールバック値、再試行ポリシー、スロットリング、データ新鮮度のSLO、説明可能性(寄与分解)を整備します。LP改善はCore Web VitalsのSLO(LCP≤2.5s/CLS≤0.1/INP≤200ms)を掲げ、CIにLighthouseスコアのゲートを置くと継続運用が容易です⁶。

まとめ: 用語を武器に、継続改善の仕組みへ

品質スコアは診断、広告ランクは勝敗を決める内部値。この区別を前提に、期待CTR・関連性・LP利便性を再現可能なコードに落とし、APIと監視で日常の改善ループに組み込みます。本稿のeCTR正規化、TF-IDF関連性、PSI連携、合成QSと可観測性の実装は、2〜4週間でMVP化できる現実解です。次の一歩として、貴社データで重み最適化と相関検証を走らせ、ダッシュボードにSLAとアラートを追加してください。どのボトルネックから解きほぐすか、今週のスプリントに1項目だけ入れてみませんか。

参考文献

  1. Google Ads Help: About Ad Rank. https://support.google.com/google-ads/answer/1722122?hl=en
  2. Google Ads Help: About Quality Score (Why: The real value of Quality Score). https://support.google.com/google-ads/answer/6167123?hl=en
  3. Google 広告ヘルプ: 品質スコアについて(診断ツールとしての位置づけ). https://support.google.com/google-ads/answer/6167130?hl=ja
  4. Google 広告ヘルプ: 品質スコアの構成要素(期待CTR/広告の関連性/ランディング ページの利便性). https://support.google.com/google-ads/answer/6167118?hl=ja
  5. Search Ads 360 ヘルプ: 品質スコアのレポート. https://support.google.com/searchads/answer/2813644?hl=ja
  6. web.dev: Core Web Vitals(推奨しきい値と概要). https://web.dev/articles/vitals?hl=ja
  7. 自社観測データ(2022–2024):匿名化アカウント群の運用実績に基づく集計(非公開データ)