(5)クラスも検索できる
ここまで、SPARQLでインディビデュアルを検索してきた。それは一般的な使い方だろう。オントロジーとはいえ、実際には設計したスキーマを利用して、そのクラス(普遍者)の外延、つまり実例となるインディビデュアル(個物)を蓄積する、データベースとして活用するのだ。
ただ、SPARQLでは、インディビデュアルに対して、そのクラスを調べることができるのだ。もしくはスキーマそのものを確認できる、という言い方もできる。
まずは、次の例を見てみよう。ファイル名をt07.rqとする。
# cookpad_moritosh.ttlに含まれるすべてのインディビデュアル
# sparql --data=cookpad_moritosh.ttl --query=t06.rq
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX fmat: <http://www.onto.org/life/food/material#>
PREFIX recp: <http://www.onto.org/life/food/recipe#>
PREFIX mtsh: <http://www.onto.org/life/food/cookpad_moritosh/>
PREFIX owl: <http://www.w3.org/2002/07/owl#>
SELECT ?a ?class
WHERE
{
?a a ?class.
}
?a a ?classにおいて、述語のaはis_aであり、?aは?classのインスタンスであることを意味する。つまり、aはrdf:typeなのだ。おそらくはis_aを省略したものと考えられる。しかし、オブジェクト指向やそもそも知識工学ではis_aは継承関係(subclass of)なので、ちょっと感覚が異なる。
老婆心ながら、
This pen is an instance of a pen. インスタンス、例、実体のこと
A ball-point pen is a subclass of a pen. 一種類であること、継承のこと
の違いで、どちらも、~is a pen.であり、実はのところ例化も継承もis_a関係といえるのかもしれない。ただ、継承関係であるとする工学書が多いだろう。すくなくともオブジェクト指向でis_a関係は継承だ。
t07.rqの検索結果は1700件を超える。以下の通り、個物とクラスの関係がとれている。
------------------------------------------------------------------------------------------------------
| a | class |
======================================================================================================
| mtsh:たらこドレッシングのサラダうどん_たらこドレッシング | recp:材料グループ |
| mtsh:パスタ麺の皿うどん_スープ | recp:材料グループ |
| mtsh:カレーうどん_カレー | recp:材料グループ |
| mtsh:パスタ麺のちゃんぽん_具 | recp:材料グループ |
| mtsh:スモークサーモンのクラッカー載せ_タルタルソース | recp:材料グループ |
| mtsh:パスタ麺のちゃんぽん_スープ | recp:材料グループ |
~
| mtsh:手打ちうどん_ステップ10 | recp:ステップ |
| mtsh:ビーフシチュー_ステップ7 | recp:ステップ |
------------------------------------------------------------------------------------------------------
そこで、cookpad_moritosh.ttlの中で利用されているクラスを問い合わによって確認してみよう。以下の問い合わせとなる。ファイル名はt07.rqである。
# cookpad_moritosh.ttlに含まれるすべてのインディビデュアル
# sparql --data=cookpad_moritosh.ttl --query=t08.rq
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX fmat: <http://www.onto.org/life/food/material#>
PREFIX recp: <http://www.onto.org/life/food/recipe#>
PREFIX mtsh: <http://www.onto.org/life/food/cookpad_moritosh/>
PREFIX owl: <http://www.w3.org/2002/07/owl#>
SELECT DISTINCT ?class
WHERE
{
?a a ?class.
}
結果は次を得た。
-----------------------
| class |
=======================
| recp:材料グループ |
| recp:材料項目 |
| owl:NamedIndividual |
| recp:レシピ |
| recp:作り方(全体) |
| owl:Ontology |
| recp:材料一覧 |
| recp:ステップ |
-----------------------
なお、owl:NamedIndividualはインディビデュアルであることを意味するOWL言語のクラスを意味し、すべてのインディビデュアルはこのクラスの例である。ここでの検索対象としては無視してよい。
記事「食材を使った料理レシピの検索(料理レシピSPARQL検索3)」で、材料一覧が持つ(recp:has)の対象は材料項目と材料グループがあることを、スキーマのデータを用いて確認することを考えよう。次のような問い合わせ(t09.rq)とに検索結果となる。
# 材料一覧がrecp:has(持つ)関係を持つクラス
# sparql --data=cookpad_moritosh.ttl --query=t09.rq
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX fmat: <http://www.onto.org/life/food/material#>
PREFIX recp: <http://www.onto.org/life/food/recipe#>
PREFIX mtsh: <http://www.onto.org/life/food/cookpad_moritosh/>
PREFIX owl: <http://www.w3.org/2002/07/owl#>
SELECT DISTINCT ?class
WHERE
{
{
?v recp:has ?u.
?v rdf:type recp:レシピ.
?u rdf:type recp:材料一覧.
?u recp:has ?r.
?r a ?class.
}
UNION
{
?v recp:has ?u.
?v rdf:type recp:レシピ.
?u rdf:type recp:材料一覧.
?u recp:has ?t.
?s rdf:type recp:材料グループ.
?t rdf:type recp:材料グループ.
?t recp:has* ?s.
?s recp:has ?r.
?r a ?class.
}
}
ORDER BY ?v
-----------------------
| class |
=======================
| recp:材料項目 |
| owl:NamedIndividual |
| recp:材料グループ |
-----------------------
これにより、材料一覧の以下あるインディビデュアルは材料項目か材料グループであることが確認できた。もし材料項目だけを取り出したいなら?classをrecp:材料項目と記述すればよいことも分かる。
次に、スキーマの関係を検索する例を示そう。
まずは、料理レシピオントロジーのスキーマを記述しているcooking_recipe.rdfファイルからクラスを取り出してみよう。クラスは次のトリプルとして記述される。
recp:[クラス名] rdf:type owl:Class .
次のように問い合わせればよい。ファイル名はt10.rqとする。
# スキーマからクラスを取り出す
# sparql --data=cooking_recipe.rdf --query=t10.rq
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX fmat: <http://www.onto.org/life/food/material#>
PREFIX recp: <http://www.onto.org/life/food/recipe#>
PREFIX mtsh: <http://www.onto.org/life/food/cookpad_moritosh/>
PREFIX owl: <http://www.w3.org/2002/07/owl#>
SELECT ?c1
WHERE
{
?c1 rdf:type owl:Class.
}
ORDER BY ?c1
cooking_recipe.rdfはnoteの記事にある。
結果は次のようになる。
----------------
| c1 |
================
| fmat:食材 |
| recp:コツ |
| recp:ステップ |
| recp:ヒント |
| recp:レシピ |
| recp:作り方(全体) |
| recp:材料グループ |
| recp:材料一覧 |
| recp:材料項目 |
----------------
次にクラスとプロパティの関係を取り出してみよう。
まずクラスの定義の記述を確認してみよう。cooking_recipe.ttl(タートル形式)のレシピクラスを以下に示す。
:レシピ rdf:type owl:Class ;
owl:equivalentClass [ rdf:type owl:Restriction ;
owl:onProperty :has ;
owl:qualifiedCardinality "1"^^xsd:nonNegativeInteger ;
owl:onClass :作り方(全体)
] ,
[ rdf:type owl:Restriction ;
owl:onProperty :has ;
owl:qualifiedCardinality "1"^^xsd:nonNegativeInteger ;
owl:onClass :材料一覧
] ,
[ rdf:type owl:Restriction ;
owl:onProperty :title ;
owl:someValuesFrom xsd:string
] ,
[ rdf:type owl:Restriction ;
owl:onProperty :コツ ;
owl:qualifiedCardinality "1"^^xsd:nonNegativeInteger ;
owl:onDataRange xsd:string
] ,
[ rdf:type owl:Restriction ;
owl:onProperty :レシピID ;
owl:qualifiedCardinality "1"^^xsd:nonNegativeInteger ;
owl:onDataRange xsd:string
] ,
[ rdf:type owl:Restriction ;
owl:onProperty :作者 ;
owl:qualifiedCardinality "1"^^xsd:nonNegativeInteger ;
owl:onDataRange xsd:string
] ,
[ rdf:type owl:Restriction ;
owl:onProperty :写真 ;
owl:qualifiedCardinality "1"^^xsd:nonNegativeInteger ;
owl:onDataRange xsd:string
] ,
[ rdf:type owl:Restriction ;
owl:onProperty :紹介 ;
owl:qualifiedCardinality "1"^^xsd:nonNegativeInteger ;
owl:onDataRange xsd:string
] .
述語owl:equivalentClassの後に、鍵括弧 [ ] で、また次の述語が列挙されている。これは無名(匿名)のクラスが内部的にあることを意味する。セマンティック・ウェブの文脈、つまりトリプルとして空ノード(blank node)と呼ぶと、次のような関係があることである。
$\textit{recp:レシピ}$ $\textit{owl:equivalentClass}$ $\textit{blank node}$,
$\textit{blank node}$ $\textit{owl:onProperty}$ $\textit{recp:has}$.
プロパティはowl:onPropertyの目的語である。プロパティの目的語としてはコドメイン(値域)となるのだが、その記述はコドメインが個物ならばowl:onClassで、属性値(データ型のある値)ならばowl:onDataRange、またはowl:someValuesFromである。他にowl:allValuesFrom、owl:hasValueもあるが、このファイルには内容だ。
クラス、空ノード、プロパティ、ドメインの組を取得する問い合わせは次となる。ファイル名はt10.rqとする。
# クラスとそのプロパティの一覧を取る
# sparql --data=cooking_recipe.rdf --query=t11.rq
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX fmat: <http://www.onto.org/life/food/material#>
PREFIX recp: <http://www.onto.org/life/food/recipe#>
PREFIX mtsh: <http://www.onto.org/life/food/cookpad_moritosh/>
PREFIX owl: <http://www.w3.org/2002/07/owl#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
SELECT ?c1 ?ec ?prop ?o
WHERE
{
?c1 rdf:type owl:Class.
?c1 owl:equivalentClass ?ec.
?ec owl:onProperty ?prop.
{
?ec owl:onDataRange ?o.
}
UNION
{
?ec owl:someValuesFrom ?o.
}
UNION
{
?ec owl:onClass ?o.
}
}
ORDER BY ?c1
結果は次の通りである。
-----------------------------------------------------------
| c1 | ec | prop | o |
===========================================================
| recp:コツ | _:b0 | recp:text | xsd:string |
| recp:ステップ | _:b1 | recp:title | xsd:string |
| recp:ステップ | _:b2 | recp:has | recp:コツ |
| recp:ステップ | _:b3 | recp:写真 | xsd:string |
| recp:ステップ | _:b4 | recp:next_sibling | recp:ステップ |
| recp:ステップ | _:b5 | recp:text | xsd:string |
| recp:ステップ | _:b6 | recp:has | recp:ヒント |
| recp:ステップ | _:b7 | recp:first_child | recp:ステップ |
| recp:ヒント | _:b8 | recp:text | xsd:string |
| recp:レシピ | _:b9 | recp:コツ | xsd:string |
| recp:レシピ | _:b10 | recp:has | recp:作り方(全体) |
| recp:レシピ | _:b11 | recp:紹介 | xsd:string |
| recp:レシピ | _:b12 | recp:写真 | xsd:string |
| recp:レシピ | _:b13 | recp:has | recp:材料一覧 |
| recp:レシピ | _:b14 | recp:作者 | xsd:string |
| recp:レシピ | _:b15 | recp:レシピID | xsd:string |
| recp:レシピ | _:b16 | recp:title | xsd:string |
| recp:作り方(全体) | _:b17 | recp:head | recp:ステップ |
| recp:材料グループ | _:b18 | recp:has | recp:材料項目 |
| recp:材料グループ | _:b19 | recp:name | xsd:string |
| recp:材料グループ | _:b20 | recp:has | recp:材料グループ |
| recp:材料一覧 | _:b21 | recp:has | recp:材料項目 |
| recp:材料一覧 | _:b22 | recp:分量 | xsd:string |
| recp:材料一覧 | _:b23 | recp:has | recp:材料グループ |
| recp:材料項目 | _:b24 | recp:ref_mat | fmat:食材 |
| recp:材料項目 | _:b25 | recp:数量 | xsd:string |
| recp:材料項目 | _:b26 | recp:単位 | xsd:string |
| recp:材料項目 | _:b27 | recp:補足 | xsd:string |
-----------------------------------------------------------
SPARQLの検索対象はインディビデュアルでもクラスでもよいのだ。つまりOWLオントロジー言語で、トリプルとして記述されているものが検索対象なのであった。