📚

SPARQLでWikidataからデータを取得する

2022/07/17に公開

はじめに

この記事は、Wikidataが提供しているチュートリアルとW3Cの仕様をもとに、基本的なSPARQLクエリの書き方を整理したものです。

Wikidataとは

WikidataはWikipediaの姉妹プロジェクトで、フリーで使用可能な知識データベースサイトです。Wikipediaと比較して構造化されたデータが取得しやすいので特定のデータのリストアップや辞書作成などに役立ちます。

Wikidataからデータを取得するにはブラウザから各概念のページにアクセスする以外に、SPARQLエンドポイントにクエリを投げて取得するという方法があります。今回は以下のチュートリアルを参考にしてアクセス方法を整理します。

参考:
https://www.wikidata.org/wiki/Wikidata:SPARQL_tutorial

SPARQLとは

SPARQLはRDF用の問合せ言語です。SQLに似た文法でクエリを記述しますが、WHERE の記述にRDF特有の表現があります。

参考:
https://www.w3.org/TR/sparql11-query/

Wikidataへのアクセス方法

Wikidataへのアクセスは、用意されている以下のエンドポイントの {SPARQL} の部分にクエリを指定してアクセスすればよい。

デフォルトでは結果がXMLで返却されるが、パラメータに format=json を指定すればJSONで返却される。

その他、エンドポイントへのアクセスはGUIのツールが用意されている。

https://query.wikidata.org/

このツールで実行可能であることが確認できたクエリは、各種言語のアクセス用コードに変換できる。クエリが成功した場合、画面の中段右部分に コード ボタンが出てくるのでこれで変換ができるようになる。

SPARQL

クエリの基本

基本的な構造はSQLと同様で、 SELECT にクエリの結果として得たい変数を指定し、WHERE に制約を指定する。WHERE はトリプル(Semantic triple)で記述し、この中で変数(?x)を定義することができる。

ここでいうトリプルとは Subject, Predicate, Objectの順で定義する三つ組みのデータのことで、この形式で書かれた定義は「Subject has Predicate Object」という文として読める。

これを踏まえてSPARQLのクエリを作成すると以下のようになる。

例:分類 (P31)ネコ (Q146) を持つ概念のリストを出力する

SELECT ?item
WHERE 
{
  ?item wdt:P31 wd:Q146.
}

ラベルや説明を付ける

WHERE で定義した変数を SELECT で指定すると、上で示した通り返却されるのは識別子だけになる。識別子をたどってページを確認すると、実際はその概念を示すラベルが各言語ごとに定義されていることがわかる。たとえば、貴志駅名誉永久駅長であるところのタマ駅長のページでは以下のようなラベルが定義されている。

概念のラベルを結果につけたい場合は、WHERESERVICE wikibase:label { bd:serviceParam wikibase:language "[AUTO_LANGUAGE],en". } を追加したうえで、SELECT?{変数名}Label を指定する。説明を付ける場合は、?{変数名}Description を指定すればよい。

SELECT ?item ?itemLabel
WHERE 
{
  ?item wdt:P31 wd:Q146.
  SERVICE wikibase:label { bd:serviceParam wikibase:language "[AUTO_LANGUAGE],en". }
}

ラベルの言語を変更したい場合は、[AUTO_LANGUAGE],en の部分で制御することになる。この例では、「使用言語を自動的に設定して問い合わせを行い、この言語が存在しない場合は en をフォールバックする」という指定になっている。もちろんフォールバック指定なしで ja のように単独の言語を指定することもできる。

ここで指定した言語で値が存在しない場合は、ラベルには識別子が埋められ、説明は空で表示される。

参考:
https://en.wikibooks.org/wiki/SPARQL/SERVICE_-_Label

別名を付ける

概念のラベルには代表的な表記がつけられ、それ以外の表記は別名(Also known as)として定義されている。

この別名を結果に含めたい場合は、通常のラベルと同様に SERVICE wikibase:label { bd:serviceParam wikibase:language "[AUTO_LANGUAGE]". } を定義したうえで、?{変数名}AltLabelSELECT に含める。

SELECT ?item ?itemLabel ?itemAltLabel
WHERE 
{
  ?item wdt:P31 wd:Q146.
  SERVICE wikibase:label { bd:serviceParam wikibase:language "[AUTO_LANGUAGE]". }
}

残念なことにWikidataの別名ラベルは精度が低い場合があり、同じラベルが重複して付与されていることも少なくない。Wikidataからの抽出時点で重複を除去したい場合は、以下の参考のようにリストをDISTINCTする方法で除去することもできる。

参考:
https://stackoverflow.com/questions/46850562/how-to-query-wikidata-for-also-known-as

概念が持つ属性を列に追加する

概念が持つ属性を一緒に表示したい場合は、WHERE の中で変数を定義して SELECT で指定する。

例:分類 (P31)ネコ (Q146) を持つ概念リストに 性別 (P21) を追加して出力する

SELECT ?item ?itemLabel ?itemAltLabel ?sex_and_genderLabel
WHERE 
{
  ?item wdt:P31 wd:Q146.
  ?item wdt:P21 ?sex_and_gender.
  SERVICE wikibase:label { bd:serviceParam wikibase:language "[AUTO_LANGUAGE]". }
}

上記の結果では 性別 (P21) を属性として持つ概念のみが出力されているが、持っていない概念も含めて出力する場合は、OPTIONAL で明示する必要がある。

SELECT ?item ?itemLabel ?itemAltLabel ?sex_and_genderLabel
WHERE 
{
  ?item wdt:P31 wd:Q146.
  OPTIONAL { ?item wdt:P21 ?sex_and_gender }
  SERVICE wikibase:label { bd:serviceParam wikibase:language "[AUTO_LANGUAGE]". }
}

AND条件を指定する

WHERE で複数の制約をAND条件で指定する場合は、単純に同じSubjectの定義を複数指定するだけで良い。このとき、同じSubjectは ; で区切った文にすると省略することができる。

例:分類 (P31)ネコ (Q146) を持ち 性別 (P21)雄 (Q44148) である概念のリストを出力する

SELECT ?item ?itemLabel ?itemAltLabel ?sex_and_genderLabel
WHERE 
{
  ?item wdt:P31 wd:Q146;
        wdt:P21 wd:Q44148.
  ?item wdt:P21 ?sex_and_gender.
  SERVICE wikibase:label { bd:serviceParam wikibase:language "[AUTO_LANGUAGE]". }
}

OR条件を指定する

WHERE で複数の制約をOR条件で指定する場合は、制約を UNION でつないで指定すればよい。

例:分類 (P31)ネコ (Q146) または イヌ (Q144) を持つ概念のリストを出力する

SELECT ?item ?itemLabel ?itemAltLabel ?categoryLabel
WHERE 
{
  {?item wdt:P31 wd:Q146.} UNION {?item wdt:P31 wd:Q144.}
  ?item wdt:P31 ?category.
  SERVICE wikibase:label { bd:serviceParam wikibase:language "[AUTO_LANGUAGE]". }
}

WikidataではSPARQL 1.1に含まれる VALUES という値をまとめる仕組みが利用できる。これを利用すると少し冗長な記述を減らすことができる。

SELECT ?item ?itemLabel ?itemAltLabel ?categoryLabel
WHERE 
{
  VALUES ?cat_and_dog {wd:Q146 wd:Q144}.
  ?item wdt:P31 ?cat_and_dog.
  ?item wdt:P31 ?category.
  SERVICE wikibase:label { bd:serviceParam wikibase:language "[AUTO_LANGUAGE]". }
}

Discussion