目次


大規模なデータ統合

SPARQL を使用して RDF データに対してクエリーを実行する

セマンティック Web データ・セットから答えを引き出す

Comments

コンテンツシリーズ

このコンテンツは全#シリーズのパート#です: 大規模なデータ統合

このシリーズの続きに乞うご期待。

このコンテンツはシリーズの一部分です:大規模なデータ統合

このシリーズの続きに乞うご期待。

「大規模なデータ統合: RDF を使用してデータの Web を作成する」では、RDF (Resource Description Framework) について学びました。RDF は、グラフをベースとしたモデルを定義する W3C (World Wide Web Consortium) 標準です。このモデルを使用すると、事実上ありとあらゆるソースからのデータを完全かつ柔軟に移植できるようになります。規模を拡大してデータを関連付けられるのは強力な機能ですが、ある時点で、RDF データに問い合わせを行う必要も出てくるはずです。問い合わせを行うには、RDF グラフ構造とネットワーク・ベースの ID を理解する問い合わせ言語が必要です。

RDF モデルが出現してからずっと後になるまで、RDF データに対してクエリーを実行する標準化された方法はありませんでした。その間、片手で数えられるか、もう少し多くの独自仕様の問い合わせ言語が使われていましたが、いずれも独特の癖や不適合性がありました。各種の RDF ストレージ・システムに対して共通のクエリーを使用することができないというこの状況が、移植可能なデータという構想の実現を阻んでいましたが、幸いなことに W3C が再帰的な名前の SPARQL (SPARQL Protocol and RDF Query Language) を 2008年にリリースしました。ユーザーは SPARQL クライアントを使用することで、クエリーにデータを取り込んでローカルでクエリーを実行することや、クエリーをサーバーにプッシュして、SPARQL Protocol を通じてリモートからクエリーを実行することができます。SPARQL により、自分のデータに対しても他の誰かのデータに対しても、同じクエリー構文を使用できるようになったのです。

連載「大規模なデータ統合」の第 2 回となるこの記事では、SPARQL について紹介します。この SPARQL を基礎知識の 1 つとして、今後の記事では OSLC (Open Services for Lifecycle Collaboration) イニシアチブでのセマンティック Web テクノロジーの利用方法を詳しく探ります。この記事のサンプル・コードを入手するには、「ダウンロード」を参照してください。

基本的な SPARQL クエリー

SPARQL クエリーを実行できるクライアント・ライブラリーやアプリケーションは多数あります。そのうち、この記事では Apache Jena プロジェクトによる sparql コマンド・ライン・ツールを使用することにフォーカスします。このツールでローカル・ファイルに対してクエリーを実行するには、以下のコマンドを入力します。

sparql --query query.rq --data basic.nt

query.rq は、実行するクエリーが含まれるファイルです。.rq というファイル拡張子は慣例であり、必ずしもこの拡張子にしなければならないわけではありません。このデータ・ファイルの中身は、いずれかの標準フォーマットの RDF にすることができます。シリアライズ・フォーマットに適した標準サフィックスのいずれか (例えば、Turtle の場合は .ttl、RDF/XML の場合は .rdf、N-Triples の場合は .nt) を使用すると、sparql ツールはそのフォーマットを正しく構文解析します。Turtle ファイル名に .nt を付けたり、N-Triples ファイル名に .ttl を付けたりすると、ツールからエラーが出されます。

SPARQL クエリーの最も単純な形では、グラフの一部の突き合わせを試み、グラフ・パターンの中の重要な位置として表現される 1 つ以上の変数を選択します。この手法は SQL の SELECT クエリーおよび射影と同様です。異なる点は、クエリーがテーブルに対してではなく、グラフに対して行われることだけです。

SELECT variable-list
WHERE {
  graph pattern
}

グラフ・パターンはグラフ内での構造上の関係を表現し、ノードとこれらのノードをリンクするアークを参照します。RDF では、ノードは主語エンティティーを表現し、アークは、ノードをグラフ内の他のノードに接続するプロパティーを表現することを思い出してください。したがって、特定のノードについて問い合わせを行いたい場合は、それらのノードをパターンの主語の位置に指定します。特定のプロパティーの値を知りたい場合は、パターンの述語の位置にそのプロパティーを指定します。要素を未指定にする場合は、その要素を変数で表現します。その変数は、該当する位置に存在する有効な値にマッピングされることになります。パターンのいずれの部分も指定しなければ、それは実質的に、グラフ内のすべてのトリプルをフラットにして結果セットにするよう指定していることになります。結果セットのコンテンツは、選択する変数によって変わってきます。

例として、リスト 1 に記載する Turtle ファイル (basic.ttl) があるとします。

リスト 1. サンプル Turtle ファイル
<https://w3id.org/people/bsletten>
        a       <http://xmlns.com/foaf/0.1/Person> ;
        <http://xmlns.com/foaf/0.1/birthday> "05-26" ;
        <http://xmlns.com/foaf/0.1/name> "Brian Sletten" .
                
                
<https://w3id.org/people/mcarducci>
        a       <http://example.com/ns/Magician> ;
        <http://xmlns.com/foaf/0.1/homepage> <http://trulymagic.com> ;
        <http://xmlns.com/foaf/0.1/name> "Michael Carducci" .

上記の basic.ttl ファイルには、2 つの別個のエンティティーに関するわずかな数の事実が格納されています。現在、この 2 つのエンティティーのグラフは関連付けられていないため、basic.ttl の完全なデータ・セットには 2 つの別個のルート・ノードが含まれています。このファイルに格納されているすべての情報を要求したければ、グラフ・パターンの特定の部分を一切指定せずに、すべての変数を選択します。

SELECT ?s ?p ?o
WHERE {
  ?s ?p ?o
}

上記のクエリーを私のデータ・ファイルに対して実行すると、リスト 2 の結果になります。

リスト 2. basic.ttl 内のすべての情報を求めるクエリーを実行した結果
> sparql --query query.rq --data basic.ttl
  --------------------------------------------------------------------------------------------------------------------------------
  | s                                   | p                                                 | o                                  |
  ================================================================================================================================
  | <https://w3id.org/people/mcarducci> | <http://xmlns.com/foaf/0.1/name>                  | "Michael Carducci"                 |
  | <https://w3id.org/people/mcarducci> | <http://xmlns.com/foaf/0.1/homepage>              | <http://trulymagic.com>       |
  | <https://w3id.org/people/mcarducci> | <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> | <http://example.com/ns/Magician>   |
  | <https://w3id.org/people/bsletten>  | <http://xmlns.com/foaf/0.1/name>                  | "Brian Sletten"                    |
  | <https://w3id.org/people/bsletten>  | <http://xmlns.com/foaf/0.1/birthday>              | "05-26"                            |
  | <https://w3id.org/people/bsletten>  | <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> | <http://xmlns.com/foaf/0.1/Person> |
  --------------------------------------------------------------------------------------------------------------------------------

リスト 2 の SPARQL 結果セットには、選択された各変数に対して 1 つの列があり、条件を満たす各トリプルに対して 1 つの行があります。私が選択した変数は 3 つ (?s ?p ?o) なので、リスト 2 には 3 つの列があります。主語、述語、目的語のいずれに対しても値を指定しなかったため、グラフ内の事実のそれぞれに 1 つの行が割り当てられます。このデータ・セットには 2 つのグラフの 3 つのトリプルが含まれるため、結果セットは 6 行となっています。

基本的に、このクエリーは「すべてのことに関するすべての情報を提供してください」と SPARQL プロセッサーに対して要求しています。これは大規模なデータ・セットに対して実行するのにふさわしいクエリーではありません。LIMIT 節について学ぶと、(特に、SPARQL Protocol を使用して他の誰かのシステムに対して) 不愉快なクエリーを実行しないで済むようになります。

この結果セットからは定性的に、Michael Carducci というマジシャンの名前とホーム・ページ、そして Brian Sletten という人物の名前と誕生日がわかります。前回の記事から、皆さんはこれらの関係が何を意味するかを把握していますが、結果セットのエンティティーや関係がわからないとしたら、(エンティティーや関係は (理想的には) 解決可能な URI であるため) URI に対して GET リクエストを実行するだけで、これらが指している対象、あるいは意味していることがわかるようになります。

同じクエリーを異なるデータ・セットに対して実行すると、どの主語が対象となっているかに関係なく、その主語に対して何が記述されているかにも関係なく、すべてのトリプルがフラットな構造になります。

同じクエリーを異なるデータ・セットに対して実行すると、どの主語が対象となっているかにも、主語に対して何が記述されているかにも関係なく、すべてのトリプルがフラットな構造になります。これは重要な点です。RDF は移植可能なデータを提供します。それに対し、SPARQL は移植可能なクエリーを提供することができます (必ず提供しているというわけではありません)。データを取り込んで、そのデータに関する問い合わせを行う上で、ドメイン固有の関係やタイプを理解している必要はありません。

すべての主語またはすべての関係を検索する

すべての情報を要求するのではなく、もっと有用な問い合わせを行うとしたら、どのような問い合わせになるでしょう?例えば、データ・セットの中で扱われている主語を調べるというのはどうでしょう?この場合、関係や値は無視して、あらゆるグラフで主語の役割を持つノードの包括的なリストを取得することになります。グラフ・パターンは変わりませんが (同じグラフ・パターンで主語としての役割を果たすすべてのデータについて調べたいことに変わりはないからです)、主語の変数だけを選択して、グラフの値が結果セットに射影されるようにします。このクエリーは以下のようになります。

SELECT ?s
WHERE {
  ?s ?p ?o
}

上記のクエリーを実行すると、(おそらく予想に反して) リスト 3 の結果が生成されます。

リスト 3. 主語の変数だけを選択した場合の結果セット
> sparql --query subjects.rq --data basic.ttl
---------------------------------------
| s                                   |
=======================================
| <https://w3id.org/people/mcarducci> |
| <https://w3id.org/people/mcarducci> |
| <https://w3id.org/people/mcarducci> |
| <https://w3id.org/people/bsletten>  |
| <https://w3id.org/people/bsletten>  |
| <https://w3id.org/people/bsletten>  |
---------------------------------------

データには 2 つの主語しか含まれていませんが、リスト 3 の結果には、条件を満たす各グラフ・パターンに対して 1 つの主語がコピーされています。それぞれの主語に関して 3 つの異なることがわかっていることから、結果には主語ごとに 3 つの参照が返されています。このような冗長性は、DISTINCT キーワードを使用して、結果セットの行ごとに他とは異なるただ 1 つの値を要求することで、回避することができます。単一の変数のみを要求すれば、グラフ内のそれぞれ固有の主語への参照が 1 つだけ返されます。その場合のクエリーは以下のようになります。

SELECT DISTINCT ?s
WHERE {
  ?s ?p ?o
}

(期待どおり) 以下の結果が生成されます。

> sparql --query distinct-subjects.rq --data basic.ttl 
---------------------------------------
| s                                   |
=======================================
| <https://w3id.org/people/mcarducci> |
| <https://w3id.org/people/bsletten>  |
---------------------------------------

主語よりも、グラフで表現されている関係の本質に興味があるとしたら、別の変数 (この場合、?p 変数) を選択するだけのことです。 ?p は、グラフで主語 (?s) を目的語 (?o) に結び付ける役割を持つことから、?p はグラフ内の述語関係のすべてを表します。以下のクエリーでも、他とは異なる値だけが返されるよう、前もって結果を制限しています。

SELECT DISTINCT ?p 
WHERE 
{ 
  ?s ?p ?o 
}

クエリーの実行結果には、グラフで使用されているプロパティーが示されます。

> sparql --query predicates.rq --data basic.ttl 
-----------------------------------------------------
| p                                                 |
=====================================================
| <http://xmlns.com/foaf/0.1/name>                  |
| <http://xmlns.com/foaf/0.1/homepage>              |
| <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> |
| <http://xmlns.com/foaf/0.1/birthday>              |
-----------------------------------------------------

当然のことながら、これらの結果から、データが FOAFnamehomepage、および birthday プロパティーと RDF の type プロパティーを使用していることが明らかにわかります。また、グラフ内のすべてのトリプルに関して、そこに含まれる個々の値を調べるために、他とは異なる目的語を選択することもできます。そのようなクエリーを作成して結果を調べるのは、皆さんの宿題としておきます。

グラフ・パターンの主語を指定する

例えば、データに対して主語のクエリーを実行して、記述されているエンティティーの ID がわかったとします。特定の主語に関する情報を要求するには、グラフ・パターンにその ID 値を指定し、その主語に関連付けられている述語オブジェクトのすべてを選択します。つまり、「特定のリソースに関するすべての情報を提供してください」と要求します。リソース Michael Carducci に関してさらなる情報を調べる場合は、以下のようなクエリーを実行します。

SELECT ?p ?o 
WHERE 
{ 
  <https://w3id.org/people/mcarducci> ?p ?o 
}

このクエリーの実行結果は以下のとおりです。

> sparql --query carducci.rq --data basic.ttl 
----------------------------------------------------------------------------------------
| p                                                 | o                                |
========================================================================================
| <http://xmlns.com/foaf/0.1/name>                  | "Michael Carducci"               |
| <http://xmlns.com/foaf/0.1/homepage>              | <http://trulymagic.com>          |
| <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> | <http://example.com/ns/Magician> |
----------------------------------------------------------------------------------------

特定のリソースに関する情報を要求するというアイデアは非常に役立つため、代替手段を提供する、DESCRIBE という別の SPARQL クエリー・フォームもあるほどです。

DESCRIBE <https://w3id.org/people/mcarducci>

DESCRIBE が生成するのは、SELECT クエリーによって生成されるような結果セット・テーブルではありません。DESCRIBE は、リスト 4 に記載されているような新しいグラフを生成します。

リスト 4. DESCRIBE によって生成されたグラフ
> sparql --query describe.rq --data basic.ttl 
<https://w3id.org/people/mcarducci>
        a       <http://example.com/ns/Magician> ;
        <http://xmlns.com/foaf/0.1/homepage>
                <http://trulymagic.com> ;
        <http://xmlns.com/foaf/0.1/name>
                "Michael Carducci" .

主語 ID を調べる

今度は、データ・セットに多数の人物に関する情報が含まれていて、すべての ID のリストでどれが Michael の主語 ID であるかわからない場合のことを考えてください。その場合、クエリーに変更を加えることで Michael の主語 ID を調べることができます。便宜上この機会に、PREFIX を使ってグラフ・パターンの表現を簡素化する方法も紹介します。PREFIX キーワードを使用して foaf: プレフィックスが http://xmlns.com/foaf/0.1/ 名前空間を指すことを指定すると、それからは foaf:name または foaf:Person: という簡素化された形で参照することができます。

PREFIX foaf: <http://xmlns.com/foaf/0.1/>
SELECT ?s
WHERE 
{ 
  ?s foaf:name "Michael Carducci" 
}

結果は、期待どおりのはずです。使用する ID がわかった後は、前のクエリーを実行して Michael に関する情報を取得することができます。あるいは、この 2 つのステップを組み合わせるために、以下のより複雑なクエリーを実行することもできます。

PREFIX foaf: <http://xmlns.com/foaf/0.1/>
SELECT ?p ?o
WHERE 
{ 
  ?s foaf:name "Michael Carducci";
    ?p ?o .
}

上記クエリーでは、「Michael Carducci という名前のすべての人物に関するすべての情報を提供してください」と要求しています。Michael Carducci という名前の人物に関するリソースが複数ある場合、そのすべてのリソースに関する結果が返されます。名前は一意の ID ではないため、この時点では、リソースが同じ人物を参照しているかどうかは必ずしもわかるわけではありません。

上記のクエリーでは主語を選択していませんが、おそらくその必要はありません。Michael Carducci という名前の人物についての情報を知りたいだけであれば、リソース ID は役に立たないかもしれません。ID も取得したいのであれば、?s 変数を SELECT 節に追加するだけのことです。ただし、ID を選択しないとしても、?s にはグラフ・パターンで主語としての役割を果たさせる必要があります。主語は、foaf:name プロパティーで検索対象の名前に関連付けなければなりません。それによって、該当する主語に関連付けられているこのプロパティーの値と目的語の値を取得することができます。

より間接的なクエリーでも DESCRIBE の形を使用できることを期待しているとしたら、そのとおりです。以下のクエリーでは、ex:Magician という任意のリソースに関する情報を要求しています。

PREFIX ex: <http://example.com/ns/>

DESCRIBE ?s
WHERE {
  ?s a ex:Magician
}

この最後の例では、構文糖を利用した別の有用なトリックを導入して、RDF の type プロパティーをそっくりそのまま指定する必要をなくしています。この例がそれ以外に優れている点は、ドメインの知識を利用して、「Engineer である人物を検索してください」、「この名前を持つ Person を検索してください」、「ヒューストンに住んでいる Magician を検索してください」などといった、ターゲットを指定した問い合わせをデータに対して実行できることです。

使用されているドメインのタイプが不明な場合は、別のクエリーを実行するだけで、該当するタイプがわかります。では、すべてのタイプのリストを要求するにはどうすればよいでしょう? (ヒント: そのための基本的なクエリーは、「何かしらのタイプとなっている、すべてのタイプを表示してください」というものです。つまり、主語や目的語ではなく、述語を指定 (または、構文糖のショートカットを使用) するということです。

複数のデータ・セットに対してクエリーを実行する

何らかのつまらない理由で basic.ttl ファイルを変更することができないとしても、このファイルに含まれる事実を拡張することは可能です。それには、事実を別のファイルに格納し、そのファイルをコマンド・ラインに追加します。一例として、「私は Michael を知っています」という事実を取り込むとします。その場合、別のファイル (knows.ttl) に以下の内容を含めます。

PREFIX foaf: <http://xmlns.com/foaf/0.1/>

<https://w3id.org/people/bsletten>
  foaf:knows <https://w3id.org/people/mcarducci> .

両方のファイルで使用している ID は同じなので、このファイルのデータと今まで使用してきたデータを混ぜ合わせても、グラフが連結されるだけのことです。元のファイルは変更されません。クエリーに使用されているモデルに追加された、このもう 1 つのトリプルが、foaf:knows 関係によって Brian のノードを Michae のノードに接続することになります。これで、リスト 5 のようなもっと面白いクエリーを実行できるようになります。

リスト 5. リンクされたグラフ・パターンに対するクエリー
PREFIX ex: <http://example.com/ns/>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>

SELECT ?magician ?name
WHERE {
  ?s foaf:name "Brian Sletten" ;
     foaf:knows ?magician .

  ?magician a ex:Magician ;
     foaf:name ?name .
}

リスト 5 では、2 つの異なるグラフ・パターンが magician 変数でリンクされています。このクエリーでは、「ex:Magician クラスのインスタンスである誰か (?magician) を知っている、Brian Sletten という名前の人物 (?s) についての情報を提供し、そのもう一人の人物の名前も取得してください」と要求しています。knows.ttl ファイルのトリプルがなければ、このクエリーは結果を返しません。ただし、このクエリーをランタイム・モデルに組み込むと、魔法が行われます。

> sparql --query complex.rq --data basic.ttl --data knows.ttl
------------------------------------------------------------
| magician                            | name               |
============================================================
| <https://w3id.org/people/mcarducci> | "Michael Carducci" |
------------------------------------------------------------

リモート・データに対してクエリーを実行する

前のセクションで説明した、各種ファイルからデータを収集するメリットは Web でアドレス指定可能なリソースにも当てはまりますが、ここで皆さんに応用問題を出します。前回の記事で、私が W3ID コミュニティーの ID を使用して自分自身を参照したことを覚えていますか?リスト 6 に記載するように、そのリソースを要求したとしたら実際には何が起こるでしょう?

リスト 6. W3ID のリソースを要求するクエリー
> http get https://w3id.org/people/bsletten
HTTP/1.1 303 See Other
Access-Control-Allow-Origin: *
Content-Length: 314
Content-Type: text/html; charset=iso-8859-1
Date: Tue, 31 Mar 2015 22:33:15 GMT
Location: http://bosatsu.net/foaf/brian.rdf
Server: Apache/2.4.7 (Ubuntu)

...

リスト 6 では、HTML のヘッダーだけを示しており、HTML の本体は省略しています。「303 See Other」レスポンスに含まれている Location ヘッダーは、私に関する情報が格納されたファイルを指しています。私をシリアライズすることはできませんが、その文書をシリアライズすることは可能です。その文書を要求すると (リスト 7 を参照)、興味深いことがわかります。

リスト 7. W3ID のリソースを要求するクエリー
> http get http://bosatsu.net/foaf/brian.rdf

HTTP/1.1 200 OK
Accept-Ranges: bytes
Access-Control-Allow-Origin: *
Content-Length: 8507
Content-Type: application/rdf+xml
Date: Tue, 31 Mar 2015 22:40:04 GMT
ETag: "402ab-213b-508583ad90a40"
Last-Modified: Fri, 21 Nov 2014 06:05:21 GMT
Server: Apache/2.2.16 (Debian)

<?xml version="1.0" ?>
<rdf:RDF xmlns:cert="http://www.w3.org/ns/auth/cert#" 
   xmlns:contact="http://www.w3.org/2000/10/swap/pim/contact#"
   xmlns:dc="http://purl.org/dc/elements/1.1/"
   xmlns:foaf="http://xmlns.com/foaf/0.1/" 
   xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#"
   xmlns:loc="http://simile.mit.edu/2005/05/ontologies/location#"
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" 
   xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#" 
   xmlns:wot="http://xmlns.com/wot/0.1/">

  <foaf:Person rdf:about="https://w3id.org/people/bsletten">
    ...
  </foaf:Person>
  ...
</rdf:RDF>

リスト 7 では、HTTP レスポンス・ヘッダー、RDF 文書の先頭、そしてすべての名前空間プレフィックスの後で、https://w3id.org/people/bsletten というリソースを foaf:Person クラスのインスタンスとして識別しています。(これが、主要なタイプに対する rdf:type の関係を表現する RDF/XML の方法です。) それに続くのは、この人物 (私) に関するさまざまな詳細情報です。これには、私が通った学校、私の知り合い、私が興味を持っていることなどの情報が含まれます。

ただし忘れてはならないのは、この一連の考え方を取り巻く大枠のコンテキストです。私が自分用に指定した不変の ID は、303 リダイレクトにより (同じ ID を使用して)、私について記述している文書にリダイレクトします。Web リダイレクトを理解する SPARQL クライアント (大抵の SPARQL クライアントは理解します) はこのことを完全に把握するため、コマンド・ラインで私への参照を追加すると、私が自分自身について一般に公開しているすべての情報も (リダイレクトが行われた末に) 追加されるというわけです。このことから、3 つの異なるデータ・セットを関連付けて、「Michael Carducci という名前のマジシャンを知っている人物の関心事を教えてください」と問い合わせることが可能になります。これらの関心事は、この新しいリダイレクト先 RDF ファイルから提供されます。リスト 8 に、この新しいクエリーを記載します。

リスト 8. 3 つのリソースを関連付けるクエリー
PREFIX ex: <http://example.com/ns/>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>

SELECT ?interest WHERE {
  ?s foaf:interest ?interest ;
     foaf:knows ?magician .
   
  ?magician a ex:Magician ;
     foaf:name "Michael Carducci" .
}

リスト 9 に、クエリーの実行結果を記載します。

リスト 9. リスト 8 のクエリーの実行結果
> sparql --query interests.rq --data basic.ttl --data knows.ttl --data https://w3id.org/people/bsletten
-----------------------------------------------
| interest                                    |
===============================================
| <http://dbpedia.org/page/Fish_%28singer%29> |
| <http://dbpedia.org/resource/Sushi>         |
| <http://dbpedia.org/resource/Phish>         |
| <http://www.w3.org/2000/01/sw/>             |
| <http://www.w3.org/Metadata/>               |
| <http://www.w3.org/RDF/>                    |
-----------------------------------------------

どこまで複雑なクエリーを実行できるかは、利用可能なデータの複雑さに直接関係します。

この新しいクエリーでは、かなりのことが行われています。まず、basic.ttl に含まれるトリプルが、Michael と私に関するいくつかの単純な事実を立証しました。knows.ttl ファイルに格納された単一の事実により、私が Michael を知っているという事実が取り込まれ、(このことがなければ関連付けられていない) basic.ttl ファイルの 2 つのグラフが関連付けられます。最後に、私の W3ID による ID をサポートする FOAF ファイルに公開したデータが、私に関する情報のなかでも、私の関心事の一部を表現しています。リスト 8 のクエリーが機能するのは、これら 3 つすべてのリソースから提供されたリンクのおかげです。どこまで複雑なクエリーを実行できるかは、利用可能なデータの複雑さに直接関係します。データを取り込んでから、そのデータが伝える情報、関連するプロパティーなどについてのクエリーを実行できることを頭に置いといてください。

SPARQL Protocol

SPARQL クライアントがクエリーを解析して実行するときには、最初に HTTP を介してデータを取得し、そのデータをエンジンに取り込みます。この仕組みは優れており、ソースから常に最新のデータがプルされます。したがって、ソース・データに変更が加えられた場合には、次にクエリーを実行すると、更新後のデータが取得されます。しかし大規模なデータ・セットの場合、クエリーを実行するたびに受け入れられないほどの量の情報がプルされることになります。これは、最終的なグラフのほんのわずかな部分だけが必要な場合に、特に言えることです。この問題に対処できるようにする上で SPARQL Protocol を使用すると、わずかな慣例をサポートするリモート・サーバーに対してクエリーを実行できるようになります。ここでは、それらの慣例の 1 つのみにフォーカスします。

サーバーが GET モードでの SPARQL クエリーの実行をサポートしている場合、そのサーバーは、パラメーターとして渡される URL エンコードされた形式のクエリーを受け入れます。これは、リソース指向パターンに関する私の著書で「Named Query Pattern (名前付きクエリー・パターン)」と呼んでいるパターンの一例です。(名前付きりリソースを公開するサーバーとは対照的に) クライアント自らが関心のある情報を反映する情報リソースを作成するには、単純にその情報を要求します。それには以下のクエリーを使用します。

PREFIX ex: <http://example.com/ns/>

DESCRIBE ?s
WHERE {
  ?s a ex:Magician
}

上記のクエリーは、http://example.com/sparql?query=PREFIX%20ex%3A%20%26lt%3Bhttp%3A%2F%2Fexample.com%2Fns%2F%26gt%3B%0A%0ADESCRIBE%20%3Fs%0AWHERE%20%7B%0A%20%20%3Fs%20a%20ex%3AMagician%0A%7D に対するリクエストに変換され、この URL に対して、GET リクエストを発行することができます。結果セットは通常、SPARQL 結果セットのフォーマットの XML 表現、JSON 表現、または CSV 表現としてシリアライズされます。ただし、クエリーは情報リソースであることに変わりはないため、共有したり、ブックマークを付けたり、場合によっては (例えば、キャッシュ・コントロールを利用してクエリーをキャッシュに入れることができると、サーバーが示している場合など)、キャッシュに入れたりすることも可能です。

ここで実際に何が行われているのかを考えて見ましょう。私はデータをプルするのではなく、データが存在するサーバーにクエリーをプッシュしています。大規模なデータ・セットの場合、この機能は相当な帯域幅の節約になることがあります。ただし、トレードオフに懸念がないわけではありません。皆さんが管理しているサーバー上で実行される任意のクエリーを、任意のクライアントがプッシュできるようにするのは、あまりにもリスキーです。幸い、クライアントによって駆動されるこれらのリソースは、単なる情報リソースに過ぎないため、何らかの認証および承認システムを配置することで保護することができます。(現在、SPARQL Protocol を使用する場合とほとんど同じ結果を得られる、軽量のクエリーをクライアントが実行できるようにする標準を定義するべく、「Linked Data Fragments」というイニシアチブが取り組んでいます。)

それでもやはり、プロトコルのサポートを SPARQL の SELECT クエリーに組み合わせると、強力です。この強力さは、プロトコルで CONSTRUCT の形式を使用すると、より具体的に明らかになるかもしれません。CONSTRUCT を使用した場合、既存のグラフから新しいグラフを作成することができます。新しく作成するグラフは、サブグラフや (DESCRIBE クエリーと同様に) 特定のリソースに関するグラフにすることも、任意の形のグラフにすることもできます。

最後の例として、最小限の作業で前例がないほどの強力さが発揮される方法を紹介します。リソース ID やプロパティー、クラスなどに関して、私が使っている用語と、皆さんが使っている用語が異なるとします。その場合、私は皆さんのデータを要求し、そのデータを皆さんの SPARQL Protocol エンドポイントにプッシュするだけで、私が使っている用語を使用して皆さんのデータのサブグラフを作成することができます。合意に至ろうとして実りのない、エンドレスなミーティングを重ねる必要はありません。皆さんが、作成者を示す ex:author として、ある情報を参照している一方で、私はより広範に使われている Dublin Core の http://purl.org/dc/terms/creator を使用したい場合には、単に以下のようなクエリーを使用するだけのことです。

PREFIX ex: <http://example.com/ns/>
PREFIX dct: <http://purl.org/dc/terms/>

CONSTRUCT {
  ?x dct:creator ?y .
} WHERE {
  ?x ex:author ?y .
}

私がこのクエリーを皆さんのサーバーにプッシュするには、http://example.com/sparql?query=PREFIX%20ex%3A%20%3Chttp%3A%2F%2Fexample.com%2Fns%2F%3E%0APREFIX%20dct%3A%20%3Chttp%3A%2F%2Fpurl.org%2Fdc%2Fterms%2F%3E%0A%0ACONSTRUCT%20%7B%0A%20%20%3Fx%20dct%3Acreator%20%3Fy%20.%0A%7D%20WHERE%20%7B%0A%20%20%3Fx%20ex%3Aauthor%20%3Fy%20.%0A%7D を使用します。注意する点として、CONSTRUCT クエリーは結果セットではなく (DESCRIBE クエリーのように) RDF グラフを生成します。したがって私は、クライアント上で直接 SPARQL Protocol リソースに対してクエリーを実行することができます (リスト 10 を参照)。

リスト 10. クライアントから直接 SPARQL Protocol リソースに対してクエリーを実行する
PREFIX dct: <http://purl.org/dc/terms/>

SELECT ?creator
FROM <http://example.com/sparql?query=PREFIX%20ex%3A%20%3Chttp%3A%2F%2Fexample.com%2Fns%2F%3E%0APREFIX%20dct%3A%20%3Chttp%3A%2F%2Fpurl.org%2Fdc%2Fterms%2F%3E%0A%0ACONSTRUCT%20%7B%0A%20%20%3Fx%20dct%3Acreator%20%3Fy%20.%0A%7D%20WHERE%20%7B%0A%20%20%3Fx%20ex%3Aauthor%20%3Fy%20.%0A%7D>
FROM some local file or data
WHERE {
  ?x dct:creator ?creator .
}

私はこのクエリーで、ネットワークを介して動的に皆さんのデータを取得し、私が望む方法で表示されるような形にしていますが、そのデータが最終的にどのように生成され、保管されるか (RDBMS に格納することも可能です) について、特別な洞察をすることもありません。また、皆さんのデータを私のデータと関連付けていますが、(おそらく皆さんの SPARQL Protocol エンドポイントへのアクセス権を取得すること以外は) 必ずしも皆さんと調整する必要はありません。

次回の記事で Linked Data を取り上げるときに、SPARQL Protocol を使用した面白い例を紹介します。

まとめ

この連載ではこれまで、最小限の作業で、新しい事実を学んで簡単に新しいデータ・ソースを統合することを常に可能にする、柔軟な標準データ・モデルについて説明しました。また、基礎となる実装の詳細とは関係なく、標準的な ID、標準的なモデル、標準的な問い合わせ言語を使って Web の任意のドメインに関する任意の問い合わせをすることで、データ・ソースに対するクエリーの実行を開始する方法についても説明しました。次回の記事では、これらの概念を基に、Linked Data と Linked Data Platform について詳しく探ります。


ダウンロード可能なリソース


関連トピック

  • SPARQL: SPARQL 関連の仕様を読んでください。
  • 「Learn SPARQL」: いくつかの SPARQL チュートリアルを行ってください。
  • Learning SPARQL, 2nd Edition」(Bob DuCharme 著、O'Reilly Media、2013年): SPARQL に関する優れた書籍を読んでください。
  • 「Linked Data Fragments」: クライアントがリモートから情報にクエリーを実行できるようにする、煩わしくない方法について読んでください。
  • Stardog: Stardog は、セマンティック Web の標準や、SPARQL クエリー、SPARQL Protocol をサポートするグラフ・データベースです。
  • Virtuoso: Virtuoso は、セマンティック Web の標準や、SPARQL クエリー、SPARQL Protocol をサポートするハイブリッド・データベースです。
  • AllegroGraph: AllegroGraph は、セマンティック Web の標準や、SPARQL クエリー、SPARQL Protocol をサポートするグラフ・データベースです。

コメント

コメントを登録するにはサインインあるいは登録してください。

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Web development, XML
ArticleID=1009233
ArticleTitle=大規模なデータ統合: SPARQL を使用して RDF データに対してクエリーを実行する
publish-date=07022015