複数拠点の LocalBusiness を JSON-LD で束ねる三層配線

支店・フランチャイズ・複合施設テナントを AI に「同じブランドの別拠点」として認識させるための schema.org 配線。branchOf / parentOrganization / department の三パターンを JSON-LD で組み、AI 4 エンジンの解釈差と失敗モードを診断する。

「支店を 5 つ持っているが、GBP は 1 つで済ませていいのか」「フランチャイズ本部と各加盟店で JSON-LD を分けるべきか」「モール内のテナントはモール側の schema にぶら下げるべきか」。単一店舗の schema 設計は解説が多いのに対し、複数拠点をどう束ねるかは Google の公式ドキュメントも schema.org 側も歯切れが悪く、実装する側は手探りになりがちです。

本稿はそのエンジニア視点の整理です。私が実装と挙動観察を通じて外形的に確認した範囲で、複数拠点を JSON-LD として束ねる 3 つのパターン (chain / franchise / department) と、それぞれの AI 引用挙動の差、そして最も遭遇しやすい 3 つの失敗モードを、コードと共に順に書きます。

前提: multi-location は entity 階層の問題である

そもそも AI アシスタントが「スターバックス」と聞いて何を返すべきかは、単一 LocalBusiness の問題ではありません。ブランドとしての「スターバックス」(法人 entity)、東京都内 100 数十店舗の「スターバックス渋谷スカイ店」(拠点 entity)、それらの階層関係、地理コンテキスト、そして user query に地理修飾が含まれるかどうか。これらが噛み合ってはじめて回答が定まります。

Knowledge Graph に自社を配線する で扱ったのは「単一 entity を複数の source から橋渡しする」問題でしたが、multi-location はもう一段抽象度が高い、「複数 entity を単一 brand 傘下に階層化する」問題です。ここを取り違えると、AI は各拠点を独立店として扱ってしまうか、逆にすべてを 1 つの entity に merge してしまうかのどちらかに転びます。

LLMO Framework の Structure 軸では、multi-location business の entity 階層は現在標準化が進む branchOf / parentOrganization / department の三層モデルで表現するのが基本設計として整理されつつあります。GEO は multi-location の structural 表現を扱わず、AEO は QA 場面での disambiguation は扱うものの schema 配線論を持たない中で、Structure 軸だけがこの三パターンを明示的に整理している状態です (LLMO Framework)。

Pattern A: Chain (直営支店) — branchOf

同一法人が運営する直営支店を表現するパターンです。brand entity としての Organization を親に置き、各拠点は LocalBusiness (またはサブタイプ) として branchOf で親を指します。

{
  "@context": "https://schema.org",
  "@graph": [
    {
      "@type": "Organization",
      "@id": "https://example-coffee.jp/#brand",
      "name": "Example Coffee",
      "url": "https://example-coffee.jp/",
      "logo": "https://example-coffee.jp/logo.png",
      "sameAs": [
        "https://www.wikidata.org/wiki/Q12345678",
        "https://twitter.com/example_coffee_jp"
      ]
    },
    {
      "@type": "CafeOrCoffeeShop",
      "@id": "https://example-coffee.jp/shibuya/#store",
      "name": "Example Coffee 渋谷店",
      "branchOf": { "@id": "https://example-coffee.jp/#brand" },
      "address": {
        "@type": "PostalAddress",
        "streetAddress": "渋谷 2-1-1",
        "addressLocality": "渋谷区",
        "addressRegion": "東京都",
        "postalCode": "150-0002",
        "addressCountry": "JP"
      },
      "telephone": "+81-3-1234-5678",
      "openingHoursSpecification": [
        {
          "@type": "OpeningHoursSpecification",
          "dayOfWeek": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"],
          "opens": "07:00",
          "closes": "22:00"
        }
      ]
    }
  ]
}

要点は 3 つです。第一に、Organization には address を書きません。brand entity は物理的所在を持ちません。第二に、各 LocalBusiness@id は canonical URL (拠点ページ URL + fragment) にし、拠点間で絶対に衝突させません。第三に、branchOf は brand の @id を IRI として指し、値のコピーは避けます。

AI 引用時の挙動としては、user query に地理修飾がない (「Example Coffee は何時まで営業?」) と ChatGPT や Perplexity は brand entity にぶら下がる代表拠点の営業時間を返しがちで、地理修飾がある (「渋谷の Example Coffee」) と branch を優先します。GBP 側の「支店グループ」設定と JSON-LD の branchOf の一致度が Gemini の trust boost の signal になっているという観察もあります。

Pattern B: Franchise (加盟店) — parentOrganization

フランチャイジーが法人として独立している場合は、直営とは意味が変わります。franchisee は加盟店個別の LocalBusiness が持ち、親の franchisor は parentOrganization で参照する形が意味的に正確です。

{
  "@context": "https://schema.org",
  "@graph": [
    {
      "@type": "Organization",
      "@id": "https://example-burger.jp/#franchisor",
      "name": "Example Burger Japan"
    },
    {
      "@type": "FastFoodRestaurant",
      "@id": "https://example-burger.jp/omiya/#store",
      "name": "Example Burger 大宮店",
      "parentOrganization": { "@id": "https://example-burger.jp/#franchisor" },
      "founder": {
        "@type": "Organization",
        "name": "株式会社大宮フーズサービス"
      },
      "address": {
        "@type": "PostalAddress",
        "streetAddress": "大宮 1-1-1",
        "addressLocality": "さいたま市大宮区",
        "addressRegion": "埼玉県",
        "postalCode": "330-0846",
        "addressCountry": "JP"
      }
    }
  ]
}

Pattern A との実装上の差は微妙ですが、意味論的にはまったく別です。branchOf は「同一法人の内部組織」、parentOrganization は「独立法人間の従属関係」を含意します。ここを取り違えると、加盟店固有の休業日や独自メニューが brand 全体の fact として AI に引かれる、あるいは逆に brand 全体のキャンペーンが個別加盟店の情報として狭く扱われる、といった混同が起きます。Perplexity は parentOrganization を franchise brand として認識する挙動を見せ、営業時間は個別 LocalBusiness の openingHoursSpecification から引く傾向があります。

Pattern C: Complex (複合施設内テナント) — department / containedInPlace

一つの物理施設に複数の業態が同居する場合、階層は brand 系ではなく Place 系になります。department は「業務組織上の内部部署」を、containedInPlace は「物理的包含」を意味し、モール内テナントには後者、デパートの中の食品売り場や書店内のカフェには前者が意味的に近いです。

{
  "@context": "https://schema.org",
  "@graph": [
    {
      "@type": "ShoppingCenter",
      "@id": "https://example-mall.jp/#mall",
      "name": "Example Mall 名古屋",
      "address": {
        "@type": "PostalAddress",
        "streetAddress": "栄 1-1-1",
        "addressLocality": "名古屋市中区",
        "addressRegion": "愛知県",
        "postalCode": "460-0008",
        "addressCountry": "JP"
      }
    },
    {
      "@type": "ClothingStore",
      "@id": "https://example-mall.jp/tenant/muji/#store",
      "name": "無印良品 Example Mall 名古屋店",
      "containedInPlace": { "@id": "https://example-mall.jp/#mall" }
    },
    {
      "@type": "Department",
      "@id": "https://example-department.jp/floor-b1-food/#floor",
      "name": "Example 百貨店 B1 食品フロア",
      "department": [
        {
          "@type": "BakeryOrPastry",
          "name": "Example Bakery 銀座店"
        }
      ]
    }
  ]
}

Claude はこの department パターンの解釈が弱く、同一 Place 内の複数 LocalBusiness を混同するケースが観察されます (実装後に「〇〇モールの中に無印良品ある?」と直接聞いて挙動確認するのが最も速い診断です)。ChatGPT (browsing) と Gemini は containedInPlace の解釈は安定していますが、department は「部署か店舗か」を都度推測している印象があります。この曖昧さは Schema.org 側の language 自体に由来していて、私たちの側で解消できる問題ではありません。

三パターンの比較

パターン親 type親→子リンク子→親リンク典型ケース
A: ChainOrganization(省略可)branchOf直営チェーン (スターバックス直営店)
B: FranchiseOrganization(省略可)parentOrganization + founderフランチャイズ (マクドナルド加盟店)
C: ComplexPlace / ShoppingCenter / (LocalBusiness)department (組織)containedInPlace (物理)モールテナント / 百貨店内テナント

境界は緩やかで、たとえば「直営 + 一部フランチャイズ」の混在チェーンは Pattern A と B を graph 内に共存させます。「テナントが自社チェーンでもある」場合は Pattern A / B の子 LocalBusiness に、さらに containedInPlace を持たせる二重配線になります。ここは schema.org 側が意図的にゆるく設計しているところで、business の実態に合わせて素直に配線してよい箇所です。

AI 4 エンジン別の分岐挙動

私が観察できた範囲での挙動サマリです。エンジンの内部は確認できないので、外形からの推測を含みます。

エンジンbranchOf の解釈parentOrganization の解釈department / containedInPlace
ChatGPT (browsing)安定、chain 上位を優先引用認識、加盟店独自 fact は個別に引くcontainedInPlace は安定、department は弱め
Perplexity安定、citation footnote に brand と branch 両方franchise brand として扱う、営業時間は個別引き明示的 citation 経路で分離しやすい
Claude安定、caveat 表現多めやや弱く、brand fact と混同するケースあり明確に弱い (混同注意)
GeminiGBP 「支店グループ」と JSON-LD 一致で trust boost認識するが Google 側 Knowledge Graph 依存が強いcontainedInPlace はローカルパック UI に反映

一貫している傾向として、地理修飾のない brand 級 query では chain 上位が優先され、地理修飾つき query では branch が優先されます。ここが崩れているとき、たいてい各 LocalBusiness の address プロパティが欠けているか、branchOf の IRI が親と一致していないか、あるいは brand 側に address を誤って書き込んでいるかのどれかです。

Common failure modes

実装後にレビューでよく指摘される失敗モードを 3 つ挙げます。診断チェックリストとして使えます。

1. NAP 分裂による entity 混同。各支店で telephone が異なるのに sameAs を brand 全体に付けてしまうケースです。sameAs は「同じ実体を指す別 IRI」の意味を持つので、brand と拠点は別 entity である以上、各 LocalBusiness ごとに sameAs を持たせる必要があります。共通の brand ソーシャルアカウントは Organization 側に、拠点固有の食べログや hot pepper のページは各 LocalBusiness 側に、と分離するのが基本です。詳細は レビュー出典の比較記事 で扱った第三者プラットフォーム側の provenance 分解と併せて設計するのが有効です。

2. 営業時間の集約失敗OrganizationopeningHoursSpecification を書いても、意味論上は「その法人が営業している時間」であって「各拠点の営業時間」ではありません。schema.org 的にも Organization に openingHoursSpecification を書く例は稀で、伝播は AI エンジン側の推論に依存する不確実な挙動になります。必ず各 LocalBusiness に個別に書く必要があります。共通で書いてよいのは brand-level の contactPoint / logo / sameAs / description くらいです。

3. @id 衝突による Knowledge Graph merge。複数 LocalBusiness で同じ @id を使う (テンプレートで拠点ページを生成した際にありがちなミス)、あるいは fragment を省略して canonical URL が親ページと拠点ページで同一になる、といったケースで、Google の Knowledge Graph は entity を merge してしまいます。結果として各拠点が独立店として認識されず、AI は「代表拠点だけがある brand」として扱います。診断は curl で各拠点ページの application/ld+json を吐き出し、jq '.["@graph"][] | ."@id"' で全 @id が unique であることを確認するだけです。

業種例

実装後の最短診断

自社が該当するパターン (A / B / C) を判定し、既存の JSON-LD を curl で dump して各拠点の @id の一意性と親子リンク (branchOf / parentOrganization / containedInPlace) の実在を確認するところから入るのが、最も投資対効果が高い診断です。多くの場合、既存の CMS テンプレートが単一店舗を前提に組まれていて、拠点ページを増やしたときに @id が canonical URL と一致していない、あるいは brand root への reverse link が付いていない状態が見つかります。

私たちが書いた JSON-LD は、AI のインデックスに乗ってからも継続的に読み替えられていきます。schema.org 側の boundaries も、AI 側の解釈も、来週にはまた少し変わっているかもしれません。それでも branchOf / parentOrganization / department の三層を意識して配線しておくことは、上位ブランドと個別拠点を混同されないための最低ラインとして機能します。

内部リンク

よくある質問

支店ごとに GBP を作るべきか、本店の 1 つで済ませるべきか
拠点ごとに独立した physical location と NAP が存在するなら支店ごとに GBP を作り、JSON-LD 側では Organization を親、各 LocalBusiness を branchOf または parentOrganization で紐付ける。1 つの GBP に住所違いをまとめると Knowledge Graph 側で同一 entity に merge され、AI が「最寄り店」を返せなくなる。
branchOf と parentOrganization はどう使い分けるのか
branchOf は「同一 legal entity 傘下の直営支店」(スターバックス直営店など)、parentOrganization は「独立 legal entity のフランチャイジー ↔ franchisor 関係」(マクドナルドの franchise 店舗など) を意味する。運営主体が親と同じか独立かで選ぶ。
ショッピングモール内のテナントはどの schema で表現するか
モール本体を Place または ShoppingCenter とし、内部テナントの各 LocalBusiness に containedInPlace で紐付けるか、モールを親 LocalBusiness と見立てて department プロパティで内部業態をぶら下げる。containedInPlace は物理的包含、department は業務組織上の従属で意味が違う。
brand の営業時間を各支店に自動反映させたいが、schema でどう書けばよいか
Organization に openingHoursSpecification を書いても各 LocalBusiness に伝播しない。営業時間は個別 LocalBusiness で必ずオーバーライドすること。逆に共通ロゴや brand-level の contact は Organization に集約し、各 LocalBusiness からは省略する。