LODとSPARQL入門(1)

この記事は1年以上前に書かれました。
内容が古くなっている可能性がありますのでご注意下さい。


ビジュアライゼーション(1)で使用したオープンデータはExcel形式のファイルだったため、CSV形式に変換する必要がありました。
CSVファイルはプログラムによる処理に便利ですが、それ以上にデータの利活用を向上させる技術として期待されているのがリンクト・オープン・データ(LOD:Linked Open Data)です。

ExcelやCSVでは、データは表形式で表現されます。一方LODでは、RDF(Resource Description Framework)グラフと呼ばれる、主語(subject)と目的語(object)を述語(predicate)でリンクしたトリプル(triple)で表現します。

夏目漱石 → 作品 → 吾輩は猫である

「夏目漱石」が主語、「作品」が述語、「吾輩は猫である」が目的語です。
作品の発行年のデータでは、

吾輩は猫である → 発行 → 1905

というようなグラフができます。
1つめのグラフでは、作品名は目的語でしたが、2つめのグラフでは主語になっています。そこで、

夏目漱石 → 作品 → 吾輩は猫である → 発行 → 1905

というように、RDFグラフをリンクさせることができます。

LODのデータ取得には、SPARQL(スパークル)というクエリ言語を使用します。
一見するとSQLに似たような構文ですが、SPARQLの対象はグラフモデルですので、
関係モデルを対象とするSQLとは似て非なるものと考えた方が良さそうです。

SPARQLクエリを受け付けるURIを、SPARQLエンドポイントと呼びます。
SPARQLエンドポイントによっては、SPARQLクエリを入力するフォームが用意されていることがあります。Wikipediaから抽出した情報をLODとして公開しているDBpedia Japaneseでは、
http://ja.dbpedia.org/sparql
の入力フォームからSPARQLクエリを発行することができます。

それでは、DBpediaのフォームを使ってSPARQLクエリを試してみましょう。
以下のクエリ

SELECT DISTINCT *
WHERE {
  ?s ?p ?o .
}
LIMIT 10

は、すべてのトリプルから、データを10件だけ取得します。

SELECT DISTINCT *

は、重複しないすべての結果を返します。次の

WHERE {
  ?s ?p ?o .
}

WHERE節には、データを取得する際の条件を記述します。「?s」「?p」「?o」は、それぞれ主語、述語、目的語を表す変数です。主語、述語、目的語のすべてが変数になっていますので、すべてのトリプルがヒットします。
そこで、

LIMIT 10

で取得するデータを10件に制限しています(そうしないと、大変なことになってしまいます)。

SELECT DISTINCT ?s
WHERE {
  ?s ?p ?o .
}
LIMIT 10

とすると、主語だけを10件取得することができます。

次に、主語が「フクジュソウ」のすべてのトリプルを取得してみましょう。
WikipediaのリソースのURIは、DBpediaでは

<http://ja.dbpedia.org/resource/リソース名>

になりますので、フクジュソウは

<http://ja.dbpedia.org/resource/フクジュソウ>

です。
最初のクエリで変数「?s」になっていた箇所をこのURIに変えて、

SELECT DISTINCT *
WHERE {
  <http://ja.dbpedia.org/resource/フクジュソウ> ?p ?o .
}

とします。今回は、件数を制限しなくても大丈夫です。

フクジュソウを主語とするトリプルの、重複しないすべての述語と目的語のペアを取得できました。

上の画像では表示されていませんが、

http://dbpedia.org/ontology/family http://ja.dbpedia.org/resource/キンポウゲ科

というデータがあり、フクジュソウがキンポウゲ科の植物であることが分かります。
そこで、この述語と目的語を使用して、Wikipediaに掲載されているキンポウゲ科のすべての植物を調べてみることにします。
今度は、主語だけが変数となります。

SELECT DISTINCT ?s
WHERE {
  ?s <http://dbpedia.org/ontology/family> <http://ja.dbpedia.org/resource/キンポウゲ科> .
}

クエリを実行すると、以下のような結果が得られます。

少し残念なことに、植物名だけではなく「キンポウゲ科」や「オダマキ属」などの分類名まで取得してしまいました。

先ほどの

SELECT DISTINCT *
WHERE {
  <http://ja.dbpedia.org/resource/フクジュソウ> ?p ?o .
}

の結果には、

http://ja.dbpedia.org/property/種 “フクジュソウ A. ramosa”@ja

という述語と目的語のペアがあります。そこで、

http://ja.dbpedia.org/property/種

を述語とするトリプルを持っていることを条件に加えれば良さそうです。

SELECT DISTINCT ?s
WHERE {
  ?s <http://dbpedia.org/ontology/family> <http://ja.dbpedia.org/resource/キンポウゲ科> .
  ?s <http://ja.dbpedia.org/property/種> ?o .
}

クエリを実行すると、

今度は、キンポウゲ科の植物名のみを取得することができました。

PREFIX句を用いると、URIの接頭辞をあらかじめ宣言しておくことにより、クエリの本体を簡潔に記述することができます。

PREFIX dbp:<http://ja.dbpedia.org/resource/>
PREFIX dbp-owl:<http://dbpedia.org/ontology/>
PREFIX prop:<http://ja.dbpedia.org/property/>
SELECT DISTINCT ?s
WHERE {
  ?s dbp-owl:family dbp:キンポウゲ科 .
  ?s prop:種 ?o .
}

WHERE節で同じ主語が続くときは、行末をピリオドではなくセミコロンにすることで、次の行の主語を省略することができます。

PREFIX dbp:<http://ja.dbpedia.org/resource/>
PREFIX dbp-owl:<http://dbpedia.org/ontology/>
PREFIX prop:<http://ja.dbpedia.org/property/>
SELECT DISTINCT ?s
WHERE {
  ?s dbp-owl:family dbp:キンポウゲ科 ;
  prop:種 ?o .
}

WHERE節が読みやすくなったと思います。

LODとSPARQL入門 1234