0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

会社サイトが3つに増えたら、AIから「別々の会社」に見えていた——schema.org @id で名寄せした話

0
Last updated at Posted at 2026-08-21

起きていたこと

不動産会社のWeb面を運用している。コーポレートサイト、サービスサイト、LPの3ドメイン構成で、それぞれに JSON-LD(schema.org)を実装していた。

ある日、3ドメインの構造化データを突き合わせて気づいた。同じ会社なのに、@id が3系統に割れていた。

サイトA: "@id": "https://a.example.jp/#organization"
サイトB: "@id": "https://b.example.jp/#organization"
サイトC: "@id": "https://c.example.jp/#company"

人間が読めば同じ会社だが、機械にとって @id は実体の識別子そのものだ。識別子が違えば別実体。検索エンジンとLLMクローラーには「よく似た3つの会社」が見えていたことになる。

さらに悪いことに、住所の書式(ビル名の有無)、電話番号の書式(045-...+81-45-...)、代表者名の表記まで媒体ごとに揺れていた。名寄せの手がかりも壊れていた。

方針:正典(canonical)を1つ決めて、全ドメインから参照する

RDFの発想と同じで、実体の @id はどのページに書かれていても1つのURIであるべきだ。

  1. 会社・代表者・住所の「正典URI」をコーポレートサイト側に定める
    • 会社: https://a.example.jp/#organization
    • 代表: https://a.example.jp/#representative
  2. 他ドメインのJSON-LDは、実体を定義せず参照する
    • LPの publisherabout には {"@id": "https://a.example.jp/#organization"} とだけ書く
    • LP固有の実体(WebPageFAQPage)だけをLPのURIで定義する
  3. NAP(名称・住所・電話)の値は1か所のソースから生成する
    • 電話番号は国番号付きの国際表記に統一する
      schema.org/telephone+81-45-287-1058 のような区切り付きも許容する。
      厳密な E.164 は +81452871058 と区切りなし。どちらを採るにせよ全ドメインで同一の文字列にする)
    • 住所は番地・ビル名まで省略しない

実装で効いた小技

参照だけのノードには型を書かない

参照側で @type まで書くと、正典側と型の食い違いが起きたときに矛盾ノードが生まれる。参照は {"@id": "..."} の1プロパティに徹する。

@graph の実体数をテストで固定する

JSON-LDは壊れても画面に出ない。開発者ツールにもエラーが出ない。だからCIで守るしかない。

test('正典の@graphに未解決の@id参照がない', async () => {
  const graph = await fetchJsonLd(CANONICAL_URL)
  const defined = new Set(graph.map(n => n['@id']))
  const refs = collectIdRefs(graph) // ネストを走査して {"@id": ...} を集める
  for (const r of refs) {
    expect(defined.has(r) || EXTERNAL_CANONICAL_IDS.has(r)).toBe(true)
  }
})

このテストは後日、リファクタで #company に「逆戻り」しかけた変更を実際に検知した。書いた瞬間より、忘れた頃に効く。

検証は必ず公開URLで行う

編集画面のプレビューやローカルのビルド結果ではなく、curl で公開URLを取得してパースする。CMSやホスティングのパイプラインで何が起きるかは、出口でしか確認できない。

# grep -oP は GNU grep 限定で、かつ `.` が改行に一致しないため
# 整形済み(複数行)の JSON-LD を取り逃がす。複数ブロックある場合も json.tool は失敗する。
# 全ブロックを取り出して1件ずつ検証する。
curl -s https://a.example.jp/ | python - <<'EOF'
import sys, json, re
html = sys.stdin.read()
blocks = re.findall(
    r'<script[^>]+type=["\']application/ld\+json["\'][^>]*>(.*?)</script>',
    html, re.S | re.I)
assert blocks, "JSON-LD が1件も無い"
for b in blocks:
    json.loads(b)          # 壊れていれば例外で落ちる
print(f"OK: {len(blocks)} blocks")
EOF

結果

  • 3ドメインの会社・代表者・住所の @id が1系統に統一された
  • sameAs で宣言していたSNSプロフィールとの対応も、単一実体にぶら下がる形になった
  • 統一後、LLM系クローラー向けの到達性テスト(各UAでの取得検証)でも、どのドメイン経由でも同一実体として辿れることを確認した

まとめ

  • @id は「ページの飾り」ではなく実体の識別子。ドメインをまたぐなら正典を1つ決めて参照に徹する
  • 表記揺れ(電話・住所・代表者名)は名寄せを壊す。値は1か所から生成する
  • JSON-LDの破損は画面に出ない。公開URLに対するCIテストでしか守れない

執筆・運用:株式会社HY(神奈川県横浜市西区/相続・空き家・終活の不動産相談窓口)
本記事は、自社が実際に運用する3ドメインの構造化データを1系統へ統一した際の作業記録です。
会社情報:https://hyconsulting2021.jp/

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?