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)のポイント
- できるだけ一般的に定義する(再利用性を高める)
- domain/range は柔軟に(将来の拡張を考慮)
- 意味的な関係を明示(推論に使える情報を提供)
プロファイル設計(SHACL)のポイント
- 用途に応じて具体的な制約を設定(データ品質を保証)
- RDFS range と同じか、より厳しい制約に(より緩くしない)
- 型カテゴリの整合性を保つ(クラス↔クラス、データ型↔データ型)
- 必須・任意、個数制限などを明確に(運用ルールを反映)
禁止事項
❌ RDFS がクラス(foaf:Person)なのに SHACL でデータ型(xsd:string)を指定
❌ RDFS がデータ型(xsd:string)なのに SHACL で別のデータ型(xsd:integer)を指定
❌ SHACL の制約を RDFS range より緩くする
推奨事項
✅ RDFS は汎用的に、SHACL は具体的に
✅ サブクラスやサブプロパティで絞り込む
✅ プロファイルごとに異なる制約を設定
✅ URI参照とリテラルは別プロパティで管理
7. さらに学ぶために
- RDF 1.1 Primer
- RDF Schema 1.1
- SHACL - Shapes Constraint Language
- SHACL Playground - SHACL制約を試せるオンラインツール
Discussion