takanakahiko’s blog

多分三日坊主で辞めます。

ヴァーチャルな人やものを検索できる LOD - Vlueprint の紹介と LOD の解説

Vlueprint というプラットフォームを作っています。 今回は、 Vlueprint に興味を持っていただきたく、その紹介していけたらと思います。 また Vlueprint を支える技術であるところの LOD についても解説していきます。

この記事は Linked Open Data Advent Calendar 2020 の 9日目の記事です。 大遅刻です、本当に申し訳ない。

adventar.org

LOD とは

正式名称は Linked Open Data のことです。 Web 上で取り扱いやすいようにデータを公開する技術のことを指します。 狭義の意味では RDF 形式でのデータの公開と、それを検索できる SPARQL エンドポイントの公開が当たると思います。

RDF とは、「主語 -> 述語 -> 目的語」(トリプル)によってデータを表現するフォーマットであり、いわゆる有向グラフで表すことができるものです。さらに「主語と述語はURIである」「目的語は実データかURIである」といった制約があります。

例を上げて「"takanakahiko" の "誕生日" は "2/5"」といった場合を考えてみましょう。

まずは有向グラフで示せることを確認してください。 また、RDFの制約である 「主語と述語はURIである」「目的語は実データかURIである」を満たすために主語と述語をURIにする必要があります。

f:id:takanakahiko:20201230074455j:plain

これを RDF のテキストフォーマットの一種である turtle で表すとこうなります。 URI< > で囲っているという点に注意してください。 また、URIを省略するための記法も用意されています。 @base@prefix という記述を行うことで URI を省略表記できます。

f:id:takanakahiko:20201230074610j:plain

ここに記述を足していくことで、情報を加えていくことが出来ます。 有向グラフとして表わすと以下のようになります。

f:id:takanakahiko:20201230074845j:plain

ここで、 ex-schema:love に着目してみてください。 このように URI 同士をつなぐことも可能となっています。

このような形で、URIへ情報を付与したり、URI同士を関係性でつないでいくことで情報を表現したものが RDF 及び LOD と呼ばれるものです。

これらの情報を検索するためのクエリランゲージを SPARQL と言い、 SPARQL を POST すると検索結果が帰ってくるエンドポイントを "SPARQL エンドポイント" と言います。

Vlueprint とは

私が作った、「ヴァーチャルな人やものを表現したRDF群」と「それらのRDFを検索できるエンドポイント」を提供するプラットフォームです。VTuber が中心となっていますが VTuber の定義は人それぞれですし、VTuber という明言をあえて避けている方もいるので、Vlueprint では VTuber という表現をあまり使わないようにしています。

Vlueprint のスキーマについて紹介する前に rdf:rdfs: について解説します。 これらは RDF の仕様で利用されるスキーマとなっていて、URIメタデータ等を表現するのに役立つものです。 例えば rdf:type は、URI がどういった "型" であるかを表すために利用されます。

それではまず、「おめがレイ」をサンプルとしてスキーマの一部を紹介します。 このサンプルでは、「所属」の概念を重点的に解説します。 「おめがレイ」が「おめがシスターズ」に所属していて、「おめがシスターズ」は「upd8」に所属していて、「upd8」は「Activ8」に所属していることがわかります。

f:id:takanakahiko:20201230075035j:plain

次に、より詳細な説明を行うために「月ノ美兎」をサンプルとしたスキーマの紹介もします。 下記図ではスペースの都合で省略をしていますので vpvlueprint に置き換えて読むようにしてください。

f:id:takanakahiko:20201230075613j:plain

実際の RDF は以下リンク内のそれぞれのファイルを参照してください。

github.com

SPARQL でデータを検索する

RDF に対して SPARQL というクエリランゲージを使って情報の検索をすることができます。

例えば、「月ノ美兎」の Youtube チャンネルの ID を調べたいとします。 そういった場合、以下のような手順で調べることが可能ですね。

  • redfs:label の述語が "月ノ美兎" になっている URI-A を調べる
  • その URI-A から伸びる述語 vlueprint:youtubeChannelId の目的語を調べる

それを踏まえ、 SPARQL を組み立てていきます。 SPARQL では変数という概念が存在します。 変数は「どのようなデータにでもなりうるもの」に名前をつけることができます。

例えば、上記の例で言うところの URI-A は実際に調べるまではどのような URI となるか定かではありません。 また、Youtube チャンネル ID も現時点では確定していません。

そういった変数を用いることで「条件(パターン)」を記述することができます。 SPARQL 内で変数を使うときは ?hoge のように ? から始めるように記述します。 実際パターンを書いていきましょう。

上記のような条件に当てはまるような「?YOUTUBE」を表示することで「月ノ美兎」の Youtube チャンネルの ID を調べることができそうです。 それを実際に SPARQL として記述したら以下のようになります。

f:id:takanakahiko:20201230080622j:plain

上記のクエリはこちらから実行することができます。 「Query」ボタンを押すことで、結果が表示されます。 無事に「月ノ美兎」の Youtube チャンネルの ID を調べることができるはずです。

また、SPARQL では、当てはまるものが複数ある場合でも調べることができます。

例えば VirtualBeing (いわゆる VTuber )の名前と Twitter アカウントの組み合わせを調べたいとします。 その場合は以下に当てはまるような「?LABEL」と「?TWITTER」を列挙すれば良さそうです。

  • 「?uri」-> 「rdf:type」-> 「vlueprint:VirtualBeing」
  • 「?uri」-> 「rdfs:label」-> 「?LABEL」
  • 「?uri」-> 「vlueprint:twitterAccount」-> 「?TWITTER

そういった場合以下のような SPARQL を記述されば検索が行なえます。

f:id:takanakahiko:20201230080626j:plain

上記のクエリはこちらから実行することができます。

同じように VirtualBeing の所属一覧を取得してみましょう。

f:id:takanakahiko:20201230080631j:plain

上記のクエリはこちらから実行することができます。

このように、 SPARQL を使うことで任意のデータを簡単に取得することができるのです。

プログラムから SPARQL を利用する

SPARQL は任意のプログラムからインターネット経由で叩くことが可能です。 そのためには SPARQL エンドポイントについて知っておく必要があります。

SPARQL エンドポイントとは、SPARQL をクエリとしてアクセスを行うことで結果を返すことのできる http サバとそのエンドポイントのことを指します。

例えば vlueprint の SPARQL は https://vlueprint.org/sparql/ です。 GET 及び POST でのアクセスに対応していますが、今回は GET のみの解説とします。 https://vlueprint.org/sparql/?query= の後ろに URI エンコードを行った SPARQL を付与することで結果を取得することが可能です。

例えば「月ノ美兎Youtube チャンネルの ID を調べる SPARQL を付与した場合は以下のようになります。 実際にアクセスすると検索結果が表示されるはずです。

https://vlueprint.org/sparql/?query=prefix+vlueprint%3A+%3Chttps%3A%2F%2Fvlueprint.org%2Fschema%2F%3E%0D%0Aprefix+rdfs%3A+%3Chttp%3A%2F%2Fwww.w3.org%2F2000%2F01%2Frdf-schema%23%3E%0D%0A%0D%0Aselect+%3FYOUTUBE+%7B%0D%0A++%3Furi+vlueprint%3AyoutubeChannelId+%3FYOUTUBE.%0D%0A++%3Furi+rdfs%3Alabel+%22%E6%9C%88%E3%83%8E%E7%BE%8E%E5%85%8E%22.%0D%0A%7D%0D%0A

また、クエリパラメータやヘッダーによってフォーマットの指定をすることが可能です。 CSVJSON による取得に対応をしています。 例えば先程の URL に &format=application%2Fsparql-results%2Bjson (application/sparql-results+json) を足してみましょう。 そうすることで JSON で結果を取得することが可能です。

https://vlueprint.org/sparql/?&query=prefix+vlueprint%3A+%3Chttps%3A%2F%2Fvlueprint.org%2Fschema%2F%3E%0D%0Aprefix+rdfs%3A+%3Chttp%3A%2F%2Fwww.w3.org%2F2000%2F01%2Frdf-schema%23%3E%0D%0A%0D%0Aselect+%3FYOUTUBE+%7B%0D%0A++%3Furi+vlueprint%3AyoutubeChannelId+%3FYOUTUBE.%0D%0A++%3Furi+rdfs%3Alabel+%22%E6%9C%88%E3%83%8E%E7%BE%8E%E5%85%8E%22.%0D%0A%7D%0D%0A&format=application%2Fsparql-results%2Bjson

これらの知識を知っていると、以下のようにプログラムを用いて結果を取得することが可能です。 例えば、以下のソースコードをブラウザのJavaScriptコンソールで実行してみてください。

(ブラウザのJavaScriptコンソールでプログラムを実行させることで個人情報の奪取を行うようなセキュリティ犯罪があります。基本的に提示されたプログラムはきちんと検証した上で実行するようにするべきです。今回はソースコードの下に実行結果を貼るので、実行しなくてもこの記事を読むことに差し支えはありません。)

const query = `
  prefix vlueprint: <https://vlueprint.org/schema/>
  prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>

  select ?id {
    ?uri vlueprint:youtubeChannelId ?id.
    ?uri rdfs:label "月ノ美兎".
  }
`;
const ret = await fetch(
  "https://vlueprint.org/sparql?query=" + encodeURIComponent(query),
  {
    headers: { Accept: "application/json" }
  }
);
const retJson = await ret.json();
const suddest = retJson.results.bindings[0]
  ? retJson.results.bindings[0].id.value
  : "";
console.log(suddest); // 月ノ美兎の Youtube チャンネルの ID が表示される

実行結果は以下のようになります。 無事に「月ノ美兎Youtube チャンネルの ID を調べることができました。

f:id:takanakahiko:20201230090238p:plain

貢献をする

今回紹介した Vlueprint はオープンな開発とデータの管理を行っています。 GitHub 上で行っているため、アカウントを持っている方であれば開発やデータのメンテナンスに参加することが可能です。

github.com

Vlueprint はまだまだ未整備のデータが多いのが現状です。 また、私個人では今日もなお増え続ける VirtualBeing (いわゆる VTuber ) に対応したデータをメンテナンスし続けることは現実的ではありません。

また、Issue 等による要望もお待ちしております。 VirtualBeing (いわゆる VTuber )とファンにより良い出会いが生まれるように、VirtualBeing に興味関心のある開発者の力になれるように、より良いプラットフォームにしていけたらと考えています。

みなさまの貢献をお待ちしております。 読んでいただきありがとうございました。