見出し画像

【実践ドリル】作って学ぶSPARQL基礎:Wikidata Query Serviceを使いこなそう

この記事について

想定読者:SPARQLやWikidata Query Serviceの初学者
目的:例を参考に自身の力で練習問題を解けるようになること
使用サイト:Wikidata Query Service(https://query.wikidata.org/


はじめに

こんにちは!今回は、セマンティック・ウェブの標準クエリ言語である「SPARQL」の基礎を、Wikidata Query Serviceを実際に叩きながら身につけるドリルを作成しました。

「座学だけではピンとこない」という方も、まずは例題を見て、その後の練習問題で実際にクエリを書いて実行することで、グラフデータベースの扱い方が体感できるはずです。ぜひ最後まで挑戦してみてください!

前提条件のおさらい:SPARQLとRDFの基本

SPARQLを学ぶ前に、クエリの対象となるRDFを簡単に理解しておきましょう。

普段よく使うリレーショナルデータベース(RDB)は表でデータを管理しますが、Wikidataなどのグラフデータベースは「RDF:Resource Description Framework」という形式でデータを管理します。

RDFの基本は、データを「主語(Subject)」「述語(Predicate)」「目的語(Object)」の3つの組み合わせ(Triple)で表現することです。

  • 主語 (Subject): 検索したい対象(例:日本)

  • 述語 (Predicate): 対象の属性や関係性(例:首都は)

  • 目的語 (Object): 属性の値や関係する対象(例:東京)

SPARQLは、この「主語・述語・目的語」のパズルを解くようにクエリを書いていきます。


SPARQLのコア構文1:SELECT と WHERE(基本グラフパターン)

もっとも基本となる構文が SELECT と WHERE です。

  • SELECT: 最終的に画面に表示したい変数を、変数の前に?をつけて指定します。

  • WHERE: 検索したいトリプルの条件を { } の中に記述します。

前提知識:Wikidataでは、エンティティ(主語や目的語)には wd:Qxxx、プロパティ(述語)には wdt:Pxxx という固有のIDが割り当てられています。

例)

  • wd:Q6256 = 国

  • wd:Q50337 = 日本の都道府県

  • wdt:P31 = 〜の一例である(instance of)

これらの固有IDはWikidata(https://www.wikidata.org/?uselang=ja)というサイトから得ることができますが、今回のドリルで用いるIDは事前に用意させていただいております。

【クエリの例1】

「世界の国」の一覧を取得する場合、以下のように書きます。

前提知識:wd:Q6256 = 国、wdt:P31 = 〜の一例である

「?country(主語)は、wdt:P31(分類が)、wd:Q6256(国)である」という条件になります。末尾のピリオド(.)は文の終わりを示します。

これを実行すると以下のようなIDの一覧を取得することがD系ます。

試しにQ16にアクセスしてみるとCanadaのデータにアクセスすることができます。2026年5月29日時点では215件の国IDを取得することができました。

練習問題1

Wikidata Query Serviceを使って、「日本の都道府県(のQID)」の一覧を取得するクエリを書いてください。

※出力する変数は ?pref としてください。
wd:Q50337 = 日本の都道府県、wdt:P31 = 〜の一例である

解答1

SELECT ?pref WHERE {
  ?pref wdt:P31 wd:Q50337 .
}

これを実行すると126個のデータが得られました。(47都道府県なので、今の行政区分にない県データも得られているのだと思います。)


SPARQLのコア構文2:ラベルの自動取得(SERVICE構文)

コア構文1の問題のクエリを実行すると、必要でないデータも混じっていることに気がつきました。どれが間違えているかを確認したいのですが、先ほどのクエリではただのQIDがずらりと並び、人間にはどれがどのデータか分かりづらい状態になります。

そこで、Wikidata特有の便利な機能である SERVICE wikibase:label を使います。これを入れることで、指定した言語(今回は日本語 "ja")のラベルを自動的に取得してくれます。

変数 ?xxx を指定した場合、自動的に ?xxxLabel という変数に名称が格納されます。

【クエリの例2】

先ほどの「世界の国」のクエリに、日本語のラベルを追加して表示する場合は以下のように書きます。

SELECT ?country ?countryLabel WHERE {
  ?country wdt:P31 wd:Q6256 .
  SERVICE wikibase:label { bd:serviceParam wikibase:language "ja" . }
}

練習問題2

練習問題1のクエリにラベル取得のサービスを追加し、日本の都道府県の「QID」と「日本語の名称」を並べて表示するクエリを書いてください。

※SELECT に表示したい変数を2つ並べる必要があります。

解答2

SELECT ?pref ?prefLabel WHERE {
  ?pref wdt:P31 wd:Q50337 .
  SERVICE wikibase:label { bd:serviceParam wikibase:language "ja" . }
}

尼崎県など、不必要なデータが含まれていることが確認できました。

SPARQLのコア構文3:データの結合と並び替え(ORDER BY / LIMIT)

次に、さらに別のデータも組み合わせる構文を学びましょう。

トリプル条件を増やすときは、セミコロン(;)を使うと、同じ主語に対して複数の述語と目的語を続けて書くことができます。

  • wdt:P1082 = 人口(population)

また、取得した結果を並び替えるときは ORDER BY、取得件数を制限するときは LIMIT を使います。降順にする場合は ORDER BY DESC(?変数) と囲みます。

【クエリの例3】

「世界の国」を人口が多い順にトップ5つ取得する場合は以下のように書きます。

SELECT ?country ?countryLabel ?population WHERE {
  ?country wdt:P31 wd:Q6256 ;
           wdt:P1082 ?population .
  SERVICE wikibase:label { bd:serviceParam wikibase:language "ja" . }
}
ORDER BY DESC(?population)
LIMIT 5

?country wdt:P31 wd:Q6256 ; の後ろをセミコロンで繋ぎ、人口の条件を追加しています。

練習問題3

日本の都道府県について、「人口が多い順にトップ48」を、都道府県のQID、日本語名称、人口の3つの情報とともに取得するクエリを書いてください。

※人口の変数は ?population としてください。

解答3

SELECT ?pref ?prefLabel ?population WHERE {
  ?pref wdt:P31 wd:Q50337 ;
        wdt:P1082 ?population .
  SERVICE wikibase:label { bd:serviceParam wikibase:language "ja" . }
}
ORDER BY DESC(?population)
LIMIT 48


いつか品川県が鳥取県の人口を追い越した場合はこのランキングも機能しなくなってしまうのかもしれませんね。

SPARQLのコア構文4:OPTIONAL(データの欠損を許容する)

グラフデータベースを扱う上で、最も重要と言っても過言ではないのがこの OPTIONAL です。 RDB(リレーショナルデータベース)と違い、RDFには「空欄(Null)」という概念がありません。データが存在しない場合、通常の WHERE で条件を指定すると、その行自体が検索結果から消滅してしまいます。

「データがあれば取得するが、なくても主語のデータは残す」という場合に OPTIONAL { } で条件を囲みます。

【クエリの例4】

「世界の国(Q6256)」とその「公式なウェブサイト(P856)」を取得します。ウェブサイトが登録されていない国も一覧から消さないようにします。

SELECT ?country ?countryLabel ?website WHERE {
  ?country wdt:P31 wd:Q6256 .
  OPTIONAL { ?country wdt:P856 ?website . }
  SERVICE wikibase:label { bd:serviceParam wikibase:language "ja" . }
}
LIMIT 5


練習問題4

Wikidataには、医療や創薬のデータも豊富にあります。「感染症」(QID: Q18123741)の一覧を取得し、もし「治療に用いられる薬・治療法」(PID: P2176)のデータが登録されていれば、それも一緒に表示するクエリを書いてください。 ※変数は ?infectiousDisease と ?treatment としてください。

解答4

SELECT ?infectiousDisease ?infectiousDiseaseLabel ?treatment ?treatmentLabel WHERE {
  ?infectiousDisease wdt:P31 wd:Q18123741 .
  OPTIONAL { ?ntd wdt:P2176 ?treatment . }
  SERVICE wikibase:label { bd:serviceParam wikibase:language "ja" . }
}

【解説】 OPTIONAL を使わない場合、まだ治療薬が登録されていない(あるいは開発されていない)疾患は結果からごっそり抜け落ちてしまいます。未発見の領域を調査するようなリサーチにおいては、この構文が必須になります。


SPARQLのコア構文5:プロパティパス(階層の再帰的な探索)

Wikidataは「AはBのサブクラス(下位分類)である」というツリー構造を持っています。 例えば、「ランダムフォレスト」は「アンサンブル学習」のサブクラスであり、「アンサンブル学習」は「機械学習」のサブクラスといった階層です。

プロパティの後ろに *(0回以上の繰り返し)や /(パスの連結)をつけることで、この階層を自動的に一番下まで辿って検索することができます。

  • wdt:P279 = 〜のサブクラスである(subclass of)

【クエリの例5】

「動物(Q729)」のサブクラス(哺乳類や鳥類など、さらにその下の階層すべて)に該当するものを抽出します。

コード スニペット

SELECT ?animal ?animalLabel WHERE {
  ?animal wdt:P279* wd:Q729 .
  SERVICE wikibase:label { bd:serviceParam wikibase:language "ja" . }
}
LIMIT 20

練習問題5

「機械学習」(QID: Q2539)のサブクラスに属するあらゆるアルゴリズムやモデルをすべて抽出するクエリを書いてください。 ※変数は ?ml_model としてください。

解答5

コード スニペット

SELECT ?ml_model ?ml_modelLabel WHERE {
  ?ml_model wdt:P279* wd:Q2539 .
  SERVICE wikibase:label { bd:serviceParam wikibase:language "ja" . }
}
LIMIT 50

【解説】 wdt:P279* とアスタリスクをつけることで、「直接のサブクラス」だけでなく「孫クラス」「ひ孫クラス」まで再帰的に探索してくれます。これはグラフデータベースならではの非常に強力な機能です。


SPARQLのコア構文6:UNION(複数の条件をまとめる)

「条件A、または条件B」のどちらかに当てはまるものを取得したい場合は、UNION を使ってブロックを繋ぎます。

【クエリの例6】

「美術館(Q207694)」または「博物館(Q33506)」のいずれかに該当するものを取得します。

コード スニペット

SELECT ?place ?placeLabel WHERE {
  { ?place wdt:P31 wd:Q207694 . }
  UNION
  { ?place wdt:P31 wd:Q33506 . }
  SERVICE wikibase:label { bd:serviceParam wikibase:language "ja" . }
}
LIMIT 10

練習問題6

イタリア料理について調べます。分類が「ピザ」(QID: Q177)または「パスタ」(QID: Q178)のいずれかである食べ物を取得するクエリを書いてください。 ※変数は ?food としてください。

解答6

コード スニペット

SELECT ?food ?foodLabel WHERE {
  { ?food wdt:P31 wd:Q177 . }
  UNION
  { ?food wdt:P31 wd:Q178 . }
  SERVICE wikibase:label { bd:serviceParam wikibase:language "ja" . }
}
LIMIT 20

【解説】 それぞれの条件を { } で囲み、その間に UNION を配置します。変数名(?food)を両方のブロックで統一しておくことがポイントです。


SPARQLのコア構文7:GROUP BY と COUNT(データを集計する)

最後に、取得したデータを俯瞰するための集計構文です。 SQLと同じように、GROUP BY で特定の変数をグループ化し、COUNT でその数を数えることができます。

【クエリの例7】

国(P17)ごとに、登録されている世界遺産(Q9259)の数をカウントし、多い順に表示します。 ※少し複雑ですが、SELECT の中で (COUNT(?heritage) AS ?count) のように書くのがルールです。

コード スニペット

SELECT ?countryLabel (COUNT(?heritage) AS ?count) WHERE {
  ?heritage wdt:P31 wd:Q9259 ;
            wdt:P17 ?country .
  SERVICE wikibase:label { bd:serviceParam wikibase:language "ja" . }
}
GROUP BY ?countryLabel
ORDER BY DESC(?count)
LIMIT 5


練習問題7

練習問題4の応用です。感染症(Q18123741)ごとに、登録されている「治療薬(P2176)」の数をカウントし、治療薬の種類が多い順に並べるクエリを書いてください。 ※変数は ?ntdLabel とし、カウント結果は ?drug_count としてください。(OPTIONAL を使うか使わないかで結果が変わりますが、今回は治療薬が存在するもののみをカウント対象とします)。

解答7

SELECT ?infectiousDiseaseLabel (COUNT(?treatment) AS ?drug_count) WHERE {
  ?ntd wdt:P31 wd:Q18123741 ;
       wdt:P2176 ?treatment .
  SERVICE wikibase:label { bd:serviceParam wikibase:language "ja" . }
}
GROUP BY ?infectiousDiseaseLabel
ORDER BY DESC(?drug_count)

【解説】 疾患ごとにグループ化(GROUP BY ?ntdLabel)し、そこに紐づく治療薬を数え上げています。創薬ターゲットを絞り込む際など、「どの領域にどれくらい既存のアプローチが存在するか」を定量的に把握するのに役立ちます。


ラップアップ

ここまで、全7つのコア構文を学習しました。

  1. SELECT / WHERE: 基本のマッチング

  2. SERVICE: ラベルの取得

  3. ORDER BY / LIMIT: 並び替えと制限

  4. OPTIONAL: 欠損データの許容

  5. プロパティパス: 階層の深堀り

  6. UNION: 複数条件の結合

  7. GROUP BY / COUNT: データの集計

これらをブロックのように組み合わせることで、「〇〇という性質を持ち、かつ△△のサブクラスであるデータのうち、条件に合致するものを集計する」といった、高度なデータマイニングが可能になります。

SPARQLは、散在するオープンデータを統合し、新しい知見を見つけ出すための強力な検索言語です。最近ではAIの推論なんかにも使われているそうなのでこれからもっと使われていくかもしれませんね。

いいなと思ったら応援しよう!