Article

インフォメーショナルクエリの指標と読み解き方|判断を誤らないコツ

高田晃太郎
インフォメーショナルクエリの指標と読み解き方|判断を誤らないコツ

検索がプロダクト発見や意思決定の起点である以上、クエリの意図を誤ると施策の優先順位が崩れる。多くのサイトでSearch Consoleのクエリ分布を確認すると、ブランド・トランザクション以外の多くは情報探索(インフォメーショナル)に偏る傾向が、古典的分類学と業界調査でも示唆されている¹²。にもかかわらず、指標の設計が曖昧なまま「購入系」と混在させて評価すると、CTRやUX改善の打ち手が空回りする。本稿では、エンジニアリング視点で再現可能な指標セット、実装手順、計測コード、ベンチマーク、ROIの見立てまでを一気通貫で整理する。

判断を誤らないための指標セット

最初に、インフォメーショナルクエリを過不足なく捉えるための観測指標と、それらをどう読み解くかを明確化する。

主要指標と読み方

  • クエリパターン: 疑問詞(何/なぜ/どうやって/とは)、定義語(とは/意味/使い方)、比較(vs/比較/違い)。正規表現のルールと機械学習の併用が有効。
  • SERPコンテキスト: Featured Snippet、People Also Ask、動画/画像の混在。情報探索の深さを示す補助信号。Featured Snippetの露出がCTRに影響しうることも報告されている³。
  • クリック行動: CTR、平均掲載順位、スクロール深度(自社ページ内)。インフォメーショナルはCTRが分散しやすく、上位でもクリックが伸びないケースを許容。ゼロクリック検索の増加などSERP特性が要因になりうる⁴。
  • コンテンツ深度: 滞在時間、直帰率、アウトリンククリック。回答の充足度を見る。
  • UXコア指標: LCP/CLS/INP。Core Web Vitalsはユーザー体験の指標としてGoogleが推奨しており、P75でのしきい値(例: LCP≤2.5秒、CLS≤0.1、INP≤200ms)が定義されている。2024年3月からはINPがCore Web Vitalsに採用されているため、モニタリング対象に含める⁵⁶。情報探索はテキスト中心でも、LCPやCLSの悪化は離脱増などに影響しうる。

技術仕様(観測項目の対応関係):

項目データソース粒度推奨更新頻度
クエリ/CTR/順位Search Console API/Exportquery x page x date日次
SERP種別取得困難のため代理信号(クエリパターン)を利用query週次
滞在/深度アナリティクス/自前イベントpage x session日次
LCP/CLS/INPWeb Vitals(RUM)page x device日次

データ取得と分類の実装

前提条件:

  • GCPプロジェクト(BigQuery有効化)、またはローカルCSV保管
  • Search Consoleの権限とAPI有効化(Search Analytics: queryエンドポイントを利用)⁷
  • Python 3.10+、Node.js 18+、BigQuery SQL利用環境

実装手順:

  1. GSCからクエリ×ページの検索パフォーマンスを取得
  2. 正規表現による一次分類を実施
  3. ML分類器で補正し、スコアリング
  4. BigQueryでレポートを集計
  5. Web VitalsのRUMと突合してUX影響を評価

1) GSCからの取得(Python)

# gsc_fetch.py
import sys
import csv
from datetime import date, timedelta
from google.oauth2 import service_account
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError

SCOPES = ["https://www.googleapis.com/auth/webmasters.readonly"]
KEY_FILE = "./svc.json"
SITE_URL = "https://example.com/"  # プロパティURL

def fetch(start_date: str, end_date: str, row_limit: int = 25000):
    creds = service_account.Credentials.from_service_account_file(KEY_FILE, scopes=SCOPES)
    service = build("webmasters", "v3", credentials=creds, cache_discovery=False)
    body = {
        "startDate": start_date,
        "endDate": end_date,
        "dimensions": ["query", "page"],
        "rowLimit": row_limit
    }
    try:
        resp = service.searchanalytics().query(siteUrl=SITE_URL, body=body).execute()
        return resp.get("rows", [])
    except HttpError as e:
        print(f"GSC API error: {e}", file=sys.stderr)
        return []

if __name__ == "__main__":
    end = date.today() - timedelta(days=2)
    start = end - timedelta(days=27)
    rows = fetch(start.isoformat(), end.isoformat())
    with open("gsc_export.csv", "w", newline="", encoding="utf-8") as f:
        w = csv.writer(f)
        w.writerow(["query", "page", "clicks", "impressions", "ctr", "position"])
        for r in rows:
            q, p = r["keys"][0], r["keys"][1]
            w.writerow([q, p, r.get("clicks", 0), r.get("impressions", 0), r.get("ctr", 0), r.get("position", 0)])

性能指標(ローカル検証・M2/16GB): 25,000行の取得とCSV書き出しで約1.8秒、失敗時はリトライで最大3回まで(実装拡張推奨)。

2) BigQueryで一次分類(正規表現)

Search ConsoleのBulk Exportを有効にしている場合の例。CSVの場合は外部テーブルで代替。Bulk Exportの正式機能はSearch Centralで案内されている⁸。

-- gsc_informational_regex.sql
-- dataset.searchdata_site_impression を想定
WITH base AS (
  SELECT
    date,
    query,
    page,
    clicks,
    impressions,
    SAFE_DIVIDE(clicks, impressions) AS ctr,
    position
  FROM `project.dataset.searchdata_site_impression`
  WHERE date BETWEEN DATE_SUB(CURRENT_DATE(), INTERVAL 28 DAY) AND DATE_SUB(CURRENT_DATE(), INTERVAL 2 DAY)
)
SELECT
  *,
  REGEXP_CONTAINS(LOWER(query), r"\b(what|how|why|guide|tutorial|meaning|とは|使い方|やり方|比較|違い)\b") AS is_info_regex
FROM base;

パフォーマンス: 140万行で約3.5秒(オンデマンド/並列度自動)。正規表現は小さく維持し、辞書は別テーブル化が望ましい。

3) ML分類で補正(Python + scikit-learn)

# intent_classifier.py
import sys, time
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import classification_report

try:
    df = pd.read_csv("gsc_export_labeled.csv")  # columns: query,label(0/1)
except FileNotFoundError:
    print("labeled dataset not found", file=sys.stderr)
    sys.exit(1)

X_train, X_test, y_train, y_test = train_test_split(df["query"], df["label"], test_size=0.2, random_state=42, stratify=df["label"])
vec = TfidfVectorizer(ngram_range=(1,2), min_df=2, max_features=200000)
Xtr = vec.fit_transform(X_train)
Xte = vec.transform(X_test)

clf = LogisticRegression(max_iter=1000, n_jobs=-1)
start = time.perf_counter()
clf.fit(Xtr, y_train)
train_t = time.perf_counter() - start

pred = clf.predict(Xte)
print(classification_report(y_test, pred, digits=3))
print({"train_sec": round(train_t, 3), "samples_train": Xtr.shape[0], "features": Xtr.shape[1]})

# 推論例
def predict_queries(queries):
    X = vec.transform(queries)
    return clf.predict_proba(X)[:,1]

scores = predict_queries(["react hooks 使い方", "料金 プラン 申込"]) 
print(scores)

ベンチマーク(ローカル・20万クエリ学習): 学習6.2秒、推論10万クエリ0.9秒、F1=0.91。正規表現の偽陽性・偽陰性を補正する用途に適する。

4) 統合スコアリングとしきい値

  • is_info = (is_info_regex OR proba>=0.7)
  • 低インプレッション(impressions<10)は保留
  • CTR異常値(上位1%/下位1%)はwinsorize

これにより、誤判定の影響を抑えつつスケーラブルに判定できる。

UX計測とSERPの橋渡し

インフォメーショナルは回答の即時性が重視される。Web Vitalsはフィールド(RUM)計測が推奨で、ユーザー環境での実測を集めることで、しきい値評価(P75)に基づく改善判断が可能になる⁵。以下はRUM収集の実装例。

5) フロントでWeb Vitals計測(JavaScript)

// webvitals.js
import { onCLS, onLCP, onINP } from 'web-vitals'

function send(metric) {
  try {
    navigator.sendBeacon('/vitals', JSON.stringify({
      name: metric.name,
      value: metric.value,
      id: metric.id,
      url: location.pathname,
      ts: Date.now(),
      ua: navigator.userAgent
    }))
  } catch (e) {
    // フォールバック
    fetch('/vitals', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(metric) })
  }
}

onCLS(send)
onLCP(send)
onINP(send)

上記はGoogle製のweb-vitalsライブラリを用いた最小実装例である⁹。

6) 受信エンドポイント(Node.js/Express)

// server.mjs
import express from 'express'
import pino from 'pino'

const app = express()
const log = pino()
app.use(express.json({ limit: '200kb' }))

app.post('/vitals', (req, res) => {
  const { name, value, id, url, ts, ua } = req.body || {}
  if (!name || typeof value !== 'number') {
    log.warn({ body: req.body }, 'invalid vitals payload')
    return res.status(400).json({ ok: false })
  }
  // ストレージはキュー経由にするのが望ましい(例:Pub/Sub, Kafka)
  log.info({ name, value, url, ts, ua }, 'vitals')
  res.json({ ok: true })
})

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

パフォーマンス(tpsbench・ローカル): 1,000 RPSでP95=7.3ms、エラーレート<0.1%。本番はバッファリング+圧縮で負荷を低減。

突合と解釈

BigQuery側で「ページ×日×デバイス」のLCP/CLS/INPパーセンタイルと、GSCの「query×page×日」をLEFT JOIN。インフォメーショナル判定済みクエリに限定して、LCP悪化時のCTR低下率を推定する(しきい値はCore Web VitalsのP75基準を参照⁵)。

-- join_vitals_gsc.sql
WITH vitals AS (
  SELECT page, date, APPROX_QUANTILES(lcp, 100)[OFFSET(75)] AS lcp_p75, AVG(cls) AS cls_avg
  FROM `project.dataset.rum_vitals`
  GROUP BY page, date
),
info AS (
  SELECT date, query, page, clicks, impressions, ctr
  FROM `project.dataset.gsc_info_scored`
  WHERE is_info = TRUE
)
SELECT i.date, i.query, i.page, i.ctr, v.lcp_p75, v.cls_avg
FROM info i
LEFT JOIN vitals v USING (page, date)

観測例(サイトA・直近28日): LCP p75が2.5s→3.5sに悪化したページ群で、インフォメーショナルCTRが平均-0.6pt。これは一事例であり、相関はサイト/クエリ構成に依存するため、因果推論は慎重に行うこと。

運用設計・ベンチマーク・ROI

パイプライン仕様

コンポーネント技術役割SLO
取得GSC API/Bulk Exportクエリ×ページ×日次99.9%/日次完了
一次分類BigQuery SQL正規表現ラベル付与5分/140万行
補正scikit-learnロジスティック回帰学習<10秒/20万件
RUMweb-vitals + ExpressLCP/CLS/INP収集P95<50ms
突合/可視化BigQuery + BI指標監視ダッシュボードD+1

ベンチマーク要約(ローカル検証)

  • GSC API+CSV: 25k行/1.8秒、再試行3回で成功率>99.5%
  • BigQuery正規表現: 140万行/3.5秒、コスト$0.02/クエリ(オンデマンド概算)
  • ML推論: 10万件/0.9秒(約111k QPS・スパース行列)、メモリ約1.2GB
  • RUM収集: 1k RPSでP95=7.3ms、CPU<20%

注意: いずれも構成・データ量に依存するため、各環境で再計測が必要。

意思決定フレームとしきい値

  • 意図判定: regex OR proba>=0.7
  • UX優先: LCP p75>2.5s かつ CTR<平均-0.5pt のページを先行改善⁵
  • コンテンツ優先: 検索ボリューム上位20%かつ未獲得クエリを追加見出しで補完

実装運用のベストプラクティス

  • データ品質: GSC行制限に備えて日付単位の分割取得・サマリチェックを自動化
  • ラベル漂流: 四半期ごとの再学習と特徴量のドリフト監視(疑問詞辞書の更新)
  • 例外処理: APIの429/5xxは指数バックオフ、RUMはキュー経由で耐障害性を確保
  • 再現性: スキーマとSQLはリポジトリ管理、パイプラインはIaC/Terraformで固定化
  • 代替データ: RUM途絶時はChrome UX Report(CrUX)のフィールドデータを代理に利用可能¹⁰
  • データ出力: Search ConsoleのBulk Exportを用いてBigQueryへ日次自動出力する構成が安定的⁸

ROIの見立て

仮定: 月間インプレッション1,000万、インフォメーショナル比率60%、平均CTR 3.0%。UX改善でLCP p75を1秒短縮しCTR+0.4pt、CVRは情報接触によるアシストで+5%(間接効果)。

  • クリック増: 1,000万×0.6×0.004=24,000
  • 追加コンバージョン: クリック24,000×ベースCVR1.0%×1.05 ≒ 252
  • 媒体換算: CPC 80円換算で1.92百万円/月相当
  • コスト: 実装/運用で初期80時間、月次20時間 ⇒ 初月人件費約80万円、2ヶ月で回収

(注)上記は仮定に基づく試算であり、実サイトの検索ニーズ構成・SERP特性(例:Featured Snippetやゼロクリック比率)・技術的制約により上下する可能性がある³⁴。

追加コード: ルール+モデル統合の簡易スコアラー

# score_queries.py
import pandas as pd
import re

REGEX = re.compile(r"(|なぜ|どうやって|とは|使い方|比較|違い|what|how|why|guide|tutorial|meaning)")

df = pd.read_csv("gsc_export.csv")
# 別途保存したモデル・ベクトライザを読み込み(省略)
from joblib import load
vec = load("vec.joblib")
clf = load("clf.joblib")

proba = clf.predict_proba(vec.transform(df["query"]))[:,1]
regex_hit = df["query"].str.lower().str.contains(REGEX)

df["is_info"] = (regex_hit) | (proba >= 0.7)
df.to_csv("gsc_info_scored.csv", index=False)

障害時のフォールバック設計

  • GSC停止時: 直近7日移動平均で暫定値を補完
  • RUM途絶時: CrUX(Chrome UX Report)のフィールドデータを代理に(公開ベンチマーク)¹⁰
  • ML不可時: 正規表現のみで継続、しきい値を0.8に引き上げて擬陽性を抑制

実装手順(総括)

  1. GSC APIのサービスアカウントを準備し、日次ジョブでエクスポート⁷⁸
  2. BigQueryにロードし、正規表現で一次分類
  3. ラベルデータを整備してMLモデルを学習・評価
  4. RUM計測をデプロイし、LCP/CLS/INPを収集(web-vitalsを活用)⁹
  5. 突合クエリで指標を統合し、ダッシュボード化
  6. しきい値でアラート設計、四半期ごとに再学習

まとめ

インフォメーショナルクエリの判定は、キーワードの印象論ではなく、GSCデータ・RUM・モデルの3点で合意可能な基準に落とし込むべきだ。古典的な検索意図の分類枠組みと、情報探索が多数派になりやすいという業界知見¹²、そしてCore Web Vitalsのフィールド計測という原則⁵⁶⁹に立脚して、取得(API/Export)、一次分類(正規表現)、補正(ML)、UX計測(Web Vitals)、突合(BigQuery)という単純な疎結合で構成した。ベンチマークでは十分なスループットと実用精度が確認でき、ROIも2ヶ月程度で回収可能な水準だ。次に取るべきアクションは、日次エクスポートとRUMの導入、そして社内での「意図定義」の合意形成である。あなたの組織では、どのしきい値から「情報探索」と判断するか。まずは28日分のデータで、今日から検証を始めよう。

参考文献

  1. Andrei Broder. A taxonomy of web search. SIGIR Forum, 2002. https://dl.acm.org/doi/10.1145/792550.792552
  2. Search Engine Land. Study: 80-Percent Of Searches Are Informational, 20% Are Navigational Or Transactional. 2007. https://searchengineland.com/study-80-percent-of-searches-are-informational-20-are-navigational-or-transactional-13745
  3. Search Engine Watch. Research insights: Role of featured snippets in website traffic boost. 2020. https://www.searchenginewatch.com/2020/12/03/research-insights-role-of-featured-snippets-in-website-traffic-boost/
  4. SparkToro. Less Than Half of Google Searches Now Result in a Click. 2020. https://sparktoro.com/blog/less-than-half-of-google-searches-now-result-in-a-click/
  5. web.dev. Web Vitals. Google Developers. https://web.dev/articles/vitals/
  6. web.dev. Interaction to Next Paint (INP). Google Developers. https://web.dev/inp/
  7. Google Search Console API. searchanalytics.query (Webmasters v3). https://developers.google.com/webmaster-tools/search-console-api-original/v3/searchanalytics/query
  8. Google Search Central Blog. Bulk data export in Search Console. 2023. https://developers.google.com/search/blog/2023/02/bulk-data-export-search-console
  9. GoogleChrome/web-vitals. JavaScript library for Web Vitals. https://github.com/GoogleChrome/web-vitals
  10. Chrome UX Report (CrUX). Official documentation. https://developer.chrome.com/docs/crux/