今日は「RAP(RDF API for PHP)」を使って,オントロジーにSPARQLクエリを投下中.
ただクエリのFILTER句でうまく動作せず困ったので,例を挙げながらまとめておく.
- -
動作確認に用いるオントロジー例とその可視化例を示す.
簡単に言えば,BobとTomの誕生日情報を,xsd:date型とxsd:dateTime型で定義した感じ.
<?xml version="1.0"?> <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:xsd="http://www.w3.org/2001/XMLSchema#" xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#" xmlns:owl="http://www.w3.org/2002/07/owl#" xmlns="http://www.owl-ontologies.com/Ontology1000000000.owl#" xml:base="http://www.owl-ontologies.com/Ontology1000000000.owl"> <owl:Class rdf:ID="People"/> <owl:DatatypeProperty rdf:ID="birthdayIs_date"> <rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#date"/> <rdfs:domain rdf:resource="#People"/> </owl:DatatypeProperty> <owl:DatatypeProperty rdf:ID="birthdayIs_dateTime"> <rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#dateTime"/> <rdfs:domain rdf:resource="#People"/> </owl:DatatypeProperty> <People rdf:ID="Bob"> <birthdayIs_dateTime rdf:datatype="http://www.w3.org/2001/XMLSchema#dateTime" >2002-10-01T16:30:30</birthdayIs_dateTime> <birthdayIs_date rdf:datatype="http://www.w3.org/2001/XMLSchema#date" >2002-10-01</birthdayIs_date> </People> <People rdf:ID="Tom"> <birthdayIs_dateTime rdf:datatype="http://www.w3.org/2001/XMLSchema#dateTime" >2008-10-01T16:30:30</birthdayIs_dateTime> <birthdayIs_date rdf:datatype="http://www.w3.org/2001/XMLSchema#date" >2008-10-01</birthdayIs_date> </People> </rdf:RDF>
- -
まず「Protege」を用いて上のオントロジーにクエリを投げてみる.
クエリ_1 : 全員の誕生日(xsd:date型/xsd:dateTime型)を推論する
PREFIX ex: <http://www.owl-ontologies.com/Ontology1000000000.owl#> SELECT ?name ?b_dT ?b_d WHERE { ?name rdf:type ex:People . ?name ex:birthdayIs_dateTime ?b_dT . ?name ex:birthdayIs_date ?b_d }
?name ?b_dT ?b_d Bob 2002-10-01T16:30:30 2002-10-01 Tom 2008-10-01T16:30:30 2008-10-01
I made it!!!
クエリ_2 : FILTERを使って,誕生日(xsd:dateTime型)が「2007-01-01T12:00:00」以降の人を推論する
PREFIX ex: <http://www.owl-ontologies.com/Ontology1000000000.owl#> PREFIX xsd: <http://www.w3.org/2001/XMLSchema#> SELECT ?name ?b_dT ?b_d WHERE { ?name rdf:type ex:People . ?name ex:birthdayIs_dateTime ?b_dT . ?name ex:birthdayIs_date ?b_d FILTER(xsd:dateTime(?b_dT) > "2007-01-01T12:00:00"^^xsd:dateTime) } ※ FILTER(xsd:dateTime(?b_dT) > xsd:dateTime("2007-01-01T12:00:00")) でもOK.
?name ?b_dT ?b_d Tom 2008-10-01T16:30:30 2008-10-01
I made it!!!
クエリ_3 : FILTERを使って,誕生日(xsd:date型)が「2007-01-01」以降の人を推論する
PREFIX ex: <http://www.owl-ontologies.com/Ontology1000000000.owl#> PREFIX xsd: <http://www.w3.org/2001/XMLSchema#> SELECT ?name ?b_dT ?b_d WHERE { ?name rdf:type ex:People . ?name ex:birthdayIs_dateTime ?b_dT . ?name ex:birthdayIs_date ?b_d FILTER(xsd:date(?b_d) > "2007-01-01"^^xsd:date) } ※ FILTER(xsd:date(?b_d) > xsd:date("2007-01-01")) でもOK.
?name ?b_dT ?b_d Tom 2008-10-01T16:30:30 2008-10-01
I made it!!!
どのクエリも,しっかりとFILTERで限定された結果が返ってきている.
- -
そこで,上記のクエリをRAPを用いてPHP上で投げてみることにする.
RAPの実装を超簡略化するとこんな感じになる.
<?php define("RDFAPI_INCLUDE_DIR", "./../rap/api/"); include(RDFAPI_INCLUDE_DIR . "RDFAPI.php"); // 読み込むオントロジーファイル $base = ""; $model = ModelFactory::getDefaultModel(); $model->load($base); // 投げるSPARQLクエリ $querystring = ''; // クエリの投下 $result = $model->sparqlQuery($querystring); // クエリ結果をHTMLのテーブルで表示 echo $model->sparqlQuery($querystring,'HTML'); ?>
- -
クエリ_1(RAP利用) : 全員の誕生日(xsd:date型/xsd:dateTime型)を推論する
<?php $querystring = ' PREFIX ex: <http://www.owl-ontologies.com/Ontology1000000000.owl#> PREFIX xsd: <http://www.w3.org/2001/XMLSchema#> SELECT ?name ?b_dT ?b_d WHERE { ?name rdf:type ex:People . ?name ex:birthdayIs_dateTime ?b_dT . ?name ex:birthdayIs_date ?b_d }';
クエリ_2(RAP利用) : FILTERを使って,誕生日(xsd:dateTime型)が「2007-01-01T12:00:00」以降の人を推論する
<?php $querystring = ' PREFIX ex: <http://www.owl-ontologies.com/Ontology1000000000.owl#> PREFIX xsd: <http://www.w3.org/2001/XMLSchema#> SELECT ?name ?b_dT ?b_d WHERE { ?name rdf:type ex:People . ?name ex:birthdayIs_dateTime ?b_dT . ?name ex:birthdayIs_date ?b_d FILTER( ?b_dT > xsd:dateTime("2007-01-01T12:00:00")) }';
ちなみにRAPで以下の形式だと動作しなかった.
FILTER(xsd:dateTime(?b_dT) > "2007-01-01T12:00:00"^^xsd:dateTime)
ただ,
rap/api/sparql/SparqlEngine.php[943-951行目(改行は省略)]
を見ると
<?php // replace xsd:date expressions $pattern = "/\"(.[^\"]*)\"\^\^".$xsd."dateTime/"; preg_match_all($pattern,$evalString,$hits); foreach($hits[1] as $dummy) $evalString = preg_replace("/\".[^\"]*\"\^\^".$xsd."dateTime/",strtotime($dummy),$evalString,1); $evalString = preg_replace("/(\'\<".$xsd."dateTime\()(.[^\)]*\))\>\'/","dateTime($2",$evalString);
こういう記述があるので,「"2007-01-01T12:00:00"^^xsd:dateTime」のような形式でも使えるような気がするのだが.
ちなみに,コメントの「// replace xsd:date expressions」は「// replace xsd:dateTime expressions」の間違いかな?
クエリ_3(RAP利用) : FILTERを使って,誕生日(xsd:date型)が「2007-01-01」以降の人を推論する
<?php $querystring = ' PREFIX ex: <http://www.owl-ontologies.com/Ontology1000000000.owl#> PREFIX xsd: <http://www.w3.org/2001/XMLSchema#> SELECT ?name ?b_dT ?b_d WHERE { ?name rdf:type ex:People . ?name ex:birthdayIs_dateTime ?b_dT . ?name ex:birthdayIs_date ?b_d FILTER( ?b_d > xsd:date("2007-01-01")) }';
No result rows.
Oh No!
RAPだと,FILTERでxsd:date型での比較が実装されてないのかも?
rap/api/sparql/SparqlEngine.php[883-898行目(改行は省略)]
<?php if($res[$var] instanceof Literal){ if($res[$var]->getDatatype()!= null){ if($res[$var]->getDatatype() == XML_SCHEMA.'boolean') $replacement = $res[$var]->getLabel(); if($res[$var]->getDatatype() == XML_SCHEMA.'double') $replacement = $res[$var]->getLabel(); if($res[$var]->getDatatype() == XML_SCHEMA.'integer') $replacement = $res[$var]->getLabel(); if($res[$var]->getDatatype() == XML_SCHEMA.'dateTime') $replacement = strtotime($res[$var]->getLabel()); }else{ if($res[$var]->getLabel()=="") $replacement = 'false'; else $replacement = "'str_".$res[$var]->getLabel()."'"; }
こんなコードを発見したので,やっぱり「boolean」「double」「integer」「dateTime」だけの実装で,「date」は使えないのかも.
rap/test/unit/Sparql/filterCases.php
を見てもFILTERでdate型を使ったクエリ例が書かれていないし.
- -
まとめ
RAPを使う場合,FILTERで指定するデータ型によっては,動作しない場合がある.
なので,その場合はアプリケーション側で対応する(面倒だけど).
出来るならRAPのソースを拡張するのがベストなんだけど,把握できるような量じゃないので,V0.9.6以降にアップデートされることを期待します.