🦔

RDFSとSHACLの使い分け:rangeとpropertyShapeの関係を理解する

に公開

はじめに

RDF(Resource Description Framework)でデータを扱う際、「RDFS(RDF Schema)」と「SHACL(Shapes Constraint Language)」という2つの仕組みが出てきます。どちらもプロパティやクラスの制約を定義できますが、目的も動作も全く異なります

この記事では、特に混乱しやすい以下の疑問に答えます:

  • rdfs:domain / rdfs:range と SHACL の sh:class / sh:datatype は何が違うのか?
  • RDFS の range と異なる SHACL 制約を設定してもいいのか?
  • range がクラス(foaf:Person)なのに SHACL でデータ型(xsd:string)を指定するのは問題ないか?

1. RDFSとSHACLの根本的な違い

RDFS:推論(Inference)のため

RDFS は**「もしこのプロパティが使われたら、こういう知識が導き出せる」**という宣言です。

# RDFS スキーマ定義
ex:author rdfs:domain ex:Book ;
          rdfs:range ex:Person .

意味:

  • ex:author が使われたら、主語(subject)は自動的に ex:Book のメンバーと推論される
  • 目的語(object)は自動的に ex:Person のメンバーと推論される
# 元のデータ
ex:book1 ex:author ex:john .

# 推論エンジンが自動的に導き出す知識
ex:book1 a ex:Book .      # domain から推論
ex:john a ex:Person .     # range から推論

特徴:

  • ✅ 新しい知識を生成する(推論エンジンが実行)
  • ✅ Open World Assumption(世界は開かれている)
  • ✅ エラーという概念はない
  • ✅ 「もし使われたら、これも真である」という宣言

SHACL:検証(Validation)のため

SHACL は**「既存のデータがこのルールに従っているかチェック」**する制約です。

# SHACL 制約定義
ex:BookShape
  a sh:NodeShape ;
  sh:targetClass ex:Book ;
  sh:property [
    sh:path ex:author ;
    sh:class ex:Person ;      # ← "値は ex:Person でなければならない"
    sh:minCount 1 ;           # ← "少なくとも1つ必要"
    sh:maxCount 3             # ← "最大3つまで"
  ] .

意味: 「データはこのルールに従うべき」

# テストデータ
ex:book1 ex:author "John Smith" .   # 違反! Person ではなく文字列

# 検証結果(バリデーションレポート)
sh:ValidationReport [
  sh:conforms false ;
  sh:result [
    sh:resultSeverity sh:Violation ;
    sh:focusNode ex:book1 ;
    sh:resultPath ex:author ;
    sh:value "John Smith" ;
    sh:resultMessage "Value is not a member of class ex:Person"
  ]
] .

特徴:

  • ✅ ルール違反を検出する(検証エンジンが実行)
  • ✅ Closed World Assumption的(ルールに明示されたものを検証)
  • ✅ エラーレポートを生成
  • ✅ 「データはこうあるべき」という制約

2. 両者の比較表

観点 RDFS domain/range SHACL property shape
目的 意味定義・推論 データ検証
動作 新しい知識を生成 ルール違反を検出
哲学 Open World Closed World的
タイミング スキーマ設計時 データ登録・検証時
実行主体 推論エンジン 検証エンジン
結果 推論されたトリプル バリデーションレポート
柔軟性 より緩い より厳密

3. 実践的な使い分け

パターン1:RDFS で意味を定義、SHACL で品質を保証

これが最も推奨される組み合わせです。

# 1. RDFS で意味を定義(語彙レベル)
ex:hasContact rdfs:domain ex:Person ;
              rdfs:range ex:ContactInfo ;
              rdfs:label "連絡先を持つ" .

# 2. SHACL でデータ品質を保証(プロファイルレベル)
ex:PersonShape
  a sh:NodeShape ;
  sh:targetClass ex:Person ;
  sh:property [
    sh:path ex:hasContact ;
    sh:class ex:ContactInfo ;  # RDFS の range と対応
    sh:minCount 1 ;            # しかし、SHACL では「必須」を追加
    sh:maxCount 3              # さらに「最大3件」という制約も追加
  ] .

ex:ContactInfoShape
  a sh:NodeShape ;
  sh:targetClass ex:ContactInfo ;
  sh:property [
    sh:path ex:email ;
    sh:datatype xsd:string ;   # データ型指定
    sh:pattern "^[^@]+@[^@]+$" ;  # メール形式の正規表現
    sh:minCount 1
  ] .

パターン2:プロファイルごとに異なる制約

同じ語彙を、用途に応じて異なる制約で使えます。

# 語彙は汎用的に定義
ex:author rdfs:range foaf:Agent .  # 人 or 組織

# 論文プロファイル - 個人のみ必須
:PaperProfile
  sh:property [
    sh:path ex:author ;
    sh:class foaf:Person ;  # Agent より厳しい
    sh:minCount 1
  ] .

# 報告書プロファイル - 組織のみ必須
:ReportProfile
  sh:property [
    sh:path ex:author ;
    sh:class foaf:Organization ;  # Agent より厳しい
    sh:minCount 1
  ] .

# 書籍プロファイル - どちらでもよい
:BookProfile
  sh:property [
    sh:path ex:author ;
    sh:class foaf:Agent ;  # range と同じ
    sh:minCount 1
  ] .

4. よくある疑問Q&A

Q1: RDFS の range と異なる SHACL 制約を設定できますか?

A: はい、できますし、推奨される場合も多いです。

ただし、SHACL は range と同じか、より厳しい制約にすべきです。

✅ 推奨パターン:サブクラスで絞り込む

# RDFS - 広い範囲
ex:creator rdfs:range foaf:Agent .   # 人 or 組織

# SHACL - より具体的
:ProfileShape
  sh:property [
    sh:path ex:creator ;
    sh:class foaf:Person ;  # ✅ Agent のサブクラスに絞り込み
    sh:minCount 1
  ] .

✅ 推奨パターン:リテラル型を具体化

# RDFS - 一般的なリテラル
ex:value rdfs:range rdfs:Literal .

# SHACL - データ型を具体的に
:ProfileShape
  sh:property [
    sh:path ex:value ;
    sh:datatype xsd:integer ;  # ✅ Literal を integer に具体化
    sh:minInclusive 0
  ] .

⚠️ 避けるべきパターン:range より広くする

# RDFS
ex:author rdfs:range foaf:Person .

# SHACL
:ProfileShape
  sh:property [
    sh:path ex:author ;
    sh:class foaf:Agent  # ⚠️ Person より広い(推奨されない)
  ] .

論理的に矛盾はしませんが、混乱を招きます。

Q2: range がクラスなのに SHACL でデータ型を指定するのは問題ですか?

A: はい、これは意味的な矛盾です。絶対に避けてください。

❌ 問題のある例

# 語彙定義 - クラス(URI参照)を期待
ex:author rdfs:range foaf:Person .

# プロファイル - データ型(リテラル)を要求
:ProfileShape
  sh:property [
    sh:path ex:author ;
    sh:datatype xsd:string  # ❌ 矛盾!
  ] .

なぜ問題か:

  • rdfs:range foaf:Person: 値は foaf:Person のインスタンス(URI参照
  • sh:datatype xsd:string: 値は文字列リテラル

この2つは型として互換性がありません

# RDFS に従ったデータ(URI参照)
ex:book1 ex:author <http://example.org/person/john> .
# ✅ RDFS的にOK、❌ SHACL的にNG

# SHACL に従ったデータ(文字列リテラル)
ex:book1 ex:author "John Doe" .
# ❌ RDFS的にNG、✅ SHACL的にOK

# → どちらにも従うデータは存在しない!

✅ 正しいパターン1:URI参照を使う

# 語彙
ex:author rdfs:range foaf:Person .

# プロファイル
sh:property [
  sh:path ex:author ;
  sh:class foaf:Person ;      # ✅ range と一致
  sh:nodeKind sh:IRI ;        # URI参照であることを明示
  sh:minCount 1
] .

# データ
ex:book1 ex:author <http://example.org/person/john> .
<http://example.org/person/john> a foaf:Person ;
  foaf:name "John Doe" .

✅ 正しいパターン2:リテラルを使う

# 語彙
ex:authorName rdfs:range xsd:string .  # リテラル

# プロファイル
sh:property [
  sh:path ex:authorName ;
  sh:datatype xsd:string ;    # ✅ range と一致
  sh:minCount 1 ;
  sh:maxLength 200
] .

# データ
ex:book1 ex:authorName "John Doe" .

✅ 推奨パターン:両方提供する

# 語彙 - 2つの別プロパティを定義
ex:author rdfs:range foaf:Person .     # URI参照用
ex:authorName rdfs:range xsd:string .  # 文字列ラベル用

# プロファイル
sh:property [
  sh:path ex:author ;
  sh:class foaf:Person ;
  sh:nodeKind sh:IRI
] ;
sh:property [
  sh:path ex:authorName ;
  sh:datatype xsd:string ;
  sh:minCount 1  # こちらは必須
] .

# データ
ex:book1 ex:author <http://example.org/person/john> ;
         ex:authorName "John Doe" .

Q3: 型カテゴリの整合性とは?

A: RDFS range と SHACL 制約は同じ「型カテゴリ」でなければなりません。

rdfs:range SHACL 制約 型カテゴリ 評価
foaf:Person sh:class foaf:Person クラス ↔ クラス ✅ 整合
foaf:Person sh:class foaf:Agent クラス ↔ クラス ⚠️ より緩い
foaf:Agent sh:class foaf:Person クラス ↔ クラス ✅ より厳しい(推奨)
foaf:Person sh:datatype xsd:string クラス ↔ データ型 矛盾
xsd:string sh:datatype xsd:integer データ型 ↔ データ型 矛盾
rdfs:Literal sh:datatype xsd:string データ型 ↔ データ型 ✅ 具体化(推奨)

5. 実際のアプリケーションでの活用例

ケース:メタデータ管理システム

# === 語彙管理画面で定義(RDFS) ===

# 汎用的なプロパティを定義
myv:subject
  rdfs:domain myv:Resource ;
  rdfs:range skos:Concept ;    # 広く「概念」を受け入れる
  rdfs:label "主題" .

myv:creator
  rdfs:domain myv:Resource ;
  rdfs:range foaf:Agent ;      # 人 or 組織
  rdfs:label "作成者" .

myv:format
  rdfs:domain myv:Resource ;
  rdfs:range dcterms:MediaTypeOrExtent ;
  rdfs:label "形式" .


# === プロファイル管理画面で制約(SHACL) ===

# データセットプロファイル - 厳格な制約
:DatasetProfile
  a sh:NodeShape ;
  sh:targetClass myv:Dataset ;
  sh:property [
    sh:path myv:subject ;
    sh:class myv:NDCConcept ;    # skos:Concept のサブクラスに絞り込み
    sh:node [
      sh:property [
        sh:path skos:inScheme ;
        sh:hasValue <http://example.org/scheme/NDC>  # NDC分類のみ
      ]
    ] ;
    sh:minCount 1 ;              # 必須
    sh:maxCount 10
  ] ;
  sh:property [
    sh:path myv:creator ;
    sh:class foaf:Person ;       # foaf:Agent から Person に絞り込み
    sh:nodeKind sh:IRI ;
    sh:minCount 1                # 必須
  ] ;
  sh:property [
    sh:path myv:format ;
    sh:datatype xsd:string ;     # MediaTypeOrExtent を string に具体化
    sh:pattern "^[a-z]+/[a-z0-9+.-]+$" ;  # MIME type形式
    sh:minCount 1
  ] .

# 画像プロファイル - より柔軟な制約
:ImageProfile
  a sh:NodeShape ;
  sh:targetClass myv:Image ;
  sh:property [
    sh:path myv:subject ;
    sh:class skos:Concept ;      # range と同じ(自由な概念スキーム)
    sh:minCount 1
  ] ;
  sh:property [
    sh:path myv:creator ;
    sh:or (
      [ sh:class foaf:Person ]
      [ sh:class foaf:Organization ]  # 組織も許可
    ) ;
    sh:minCount 1
  ] ;
  sh:property [
    sh:path myv:format ;
    sh:in ( "image/jpeg" "image/png" "image/gif" ) ;  # 許可された値のリスト
    sh:minCount 1 ;
    sh:maxCount 1
  ] .

6. まとめ:設計指針

語彙設計(RDFS)のポイント

  1. できるだけ一般的に定義する(再利用性を高める)
  2. domain/range は柔軟に(将来の拡張を考慮)
  3. 意味的な関係を明示(推論に使える情報を提供)

プロファイル設計(SHACL)のポイント

  1. 用途に応じて具体的な制約を設定(データ品質を保証)
  2. RDFS range と同じか、より厳しい制約に(より緩くしない)
  3. 型カテゴリの整合性を保つ(クラス↔クラス、データ型↔データ型)
  4. 必須・任意、個数制限などを明確に(運用ルールを反映)

禁止事項

❌ RDFS がクラス(foaf:Person)なのに SHACL でデータ型(xsd:string)を指定
❌ RDFS がデータ型(xsd:string)なのに SHACL で別のデータ型(xsd:integer)を指定
❌ SHACL の制約を RDFS range より緩くする

推奨事項

✅ RDFS は汎用的に、SHACL は具体的に
✅ サブクラスやサブプロパティで絞り込む
✅ プロファイルごとに異なる制約を設定
✅ URI参照とリテラルは別プロパティで管理

7. さらに学ぶために

Discussion