1. 程式人生 > >RDF資料查詢語言SPARQL:初步

RDF資料查詢語言SPARQL:初步

說明:本文件實質上是閱讀Jena DocSPARQL部分學習使用SPARQL的學習筆記,主要想和大家分享學習過程,瞭解如何在Windows XP中開始使用SPARQL,在命令列(command line)和Jena環境中執行簡單SPARQL查詢。

可以從http://jena.sourceforge.net免費獲得Jena的最新版本,可以從ARQ主頁http://jena.hpl.hp.com/~afs/ARQ/index.html下載最新的ARQ 發行包,從而在執行SPARQL查詢。當然,在梯隊網站的個人主頁上,這些資源也是可得的。

SPARQLW3CRDF資料工作組設計的一種查詢語言和協議,用於

RDF資料的查詢。經過類似於JDK安裝時候的配置,可以在命令列執行SPARQL查詢,也可以在安裝了Jena API之後,在Java程式用使用SPARQL查詢。

在開始學習SPARQL之前,我的機器上已經安裝了JDK 5.0並在eclipse 3.2中可以使用Jena API。不知道SPARQL的命令列執行是不是需要Java環境,是不是需要Jena環境?當然,在Jena中使用SPARQL一定是需要Jena API的。我很想實驗一下,但是,解除安裝JDK還得裝,麻煩的狠,所以算了。如果誰沒有裝JDK,可以試一試,然後分享一下結論。

1.下載和配置SPARQL

http://jena.hpl.hp.com/~afs/ARQ/download.html

頁上找到最新的 ARQ 發行包,並解壓到某個目錄,我解壓到了D:/Jena-2.5/ARQ-2.1-beta,實際上,解壓到哪裡並沒有多大關係,不影響使用。

配置環境變數:滑鼠右鍵單擊【我的電腦】-【屬性】-【高階】-【環境變數】,在系統變數中找到CLASSPATH,將將解壓路徑中的lib資料夾路徑新增到CLASSPATH,對我的機器來說就是D:/Jena-2.5/ARQ-2.1-beta/lib;然後,在系統變數中找到PATH變數,將解壓路徑中的bat資料夾路徑新增到PATH變數,對我的機器來說就是D:/Jena-2.5/ARQ-2.1-beta/bat

第一個CLASSPATH設定保證機器可以使用開發包中的

API,第二個PATH設定使得可以在任意命令列路徑使用SPARQL查詢。如果不做PATH設定,那麼只能在D:/Jena-2.5/ARQ-2.1-beta/bat路徑下使用SPARQL查詢,那樣會很不方便。

在一般的設定建議中,會讓建一個ARQROOT變數,其值為D:/Jena-2.5/ARQ-2.1-beta,這樣在隨後的設定中用ARQROOT代替D:/Jena-2.5/ARQ-2.1-beta,使得環境變數的配置不至於很麻煩。我覺得這只是一個替換作用,在JDK的配置中也有類似的建議,我沒有做,只是照搬完整路徑。建立ROOT變數的好處在於,以後需要再配置環境變數時,直接JAVAROOT/../就可以了,不用再去找JDK到底安裝在什麼目錄下。

如果上面的設定成功,那麼在命令列下執行sparql命令,會返回

No query string or query file

指示沒有查詢語句和查詢資料檔案。如果執行sparql –h(或者sparql –hsparql –helpsparql –h)就會返回命令sparql的幫助資訊。

2.執行一個簡單的查詢

SPARQL查詢語句的執行格式是:

sparql --data=<file> --query=<query>

file是要查詢的資料來源,RDF檔案或者RDF圖檔案;query是查詢語句檔案,以.rq為檔案字尾。

2.1資料來源,一個RDF檔案,就是幫助文件中的vc-db-1.rdf,文件描述了一些簡單的人名資訊,下面是類似三元組形式的資料表示。

@prefix vCard:<http://www.w3.org/2001/vcard-rdf/3.0#> .
@prefix rdf:<http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix :<#> .
<http://somewhere/MattJones/>
vCard:FN"Matt Jones" ;
vCard:N[ vCard:Family
"Jones" ;
vCard:Given
"Matthew"
] .
<http://somewhere/RebeccaSmith/>
vCard:FN"Becky Smith" ;
vCard:N[ vCard:Family
"Smith" ;
vCard:Given
"Rebecca"
] .
<http://somewhere/JohnSmith/>
vCard:FN"John Smith" ;
vCard:N[ vCard:Family
"Smith" ;
vCard:Given
"John"
] .
<http://somewhere/SarahJones/>
vCard:FN"Sarah Jones" ;
vCard:N[ vCard:Family
"Jones" ;
vCard:Given
"Sarah"
] .

2.2查詢語句q1.rq,記事本建立一個檔案,內容如下,檔案儲存為q1.rq。注意檔案字尾是.rq,不是.txt

SELECT ?x
WHERE { ?x<http://www.w3.org/2001/vcard-rdf/3.0#FN>"John Smith" }

2.3那麼使用上面的查詢語句查詢vc-db-1.rdf檔案中的資料的命令列語句就是

sparql --data=vc-db-1.rdf --query=q1.rq

返回結果是:

---------------------------------
| x|
=================================
| <http://somewhere/JohnSmith/> |
---------------------------------

在執行上面的查詢時,要保證資料檔案和查詢檔案在當前目錄下,否則命令中應該包括完整路徑,即:

sparql --data=d:/sparql/vc-db-1.rdf --query=d:/sparql/q1.rq

2.4對查詢語句和查詢結果的理解

查詢語句包括查詢資訊的名稱以及名稱應該符合的條件。條件子句以三元組形式出現,按照<主語,謂語,賓語>的順序排列。查詢條件也成為一個模式(Pattern)。查詢的結果實際就是條件三元組與資料檔案(或RDF圖)中RDF三元組匹配的結果。

語句中的加一個字母表示該字母是一個變數,比如 ?x,在SELECT後面的變數會顯示在查詢結果中,作為列名稱出現。

實際上,做到這一步之後,所有的事情只是修改模式,給模式新增一些條件了,非常簡單。

3.名稱空間的簡寫替代

如果查詢所有具有名字的例項以及該例項的名字,那麼查詢語句如下

SELECT ?x ?fname
WHERE {?x<http://www.w3.org/2001/vcard-rdf/3.0#FN>?fname}

注意,“?x ?fname”之間是空格,不是逗號。如果有多個模式三元組,那麼三元組之間用點號“.”隔開,比如

SELECT ?givenName
WHERE 
{ ?y<http://www.w3.org/2001/vcard-rdf/3.0#Family>"Smith" .
?y<http://www.w3.org/2001/vcard-rdf/3.0#Given>?givenName .
}

這時候,模式中的謂詞的URI都帶一個長長的名稱空間字串,http://www.w3.org/2001/vcard-rdf/3.0#”,能用一個簡單的單詞代替它應該會比較簡單。實現簡寫URI的的語法是這樣的:

PREFIX vcard:http://www.w3.org/2001/vcard-rdf/3.0#
SELECT ?givenName
WHERE
 { ?y vcard:Family "Smith" .
?y vcard:Given?givenName .
 }

語句PREFIX vcard:http://www.w3.org/2001/vcard-rdf/3.0#定義了一個字首單詞vcard,在查詢語句中,它與後面的名稱空間等價。

4.過濾查詢結果

在查詢語句中新增過濾條件的語句是

FILTER regex(?x, "pattern" [, "flags"])

FILTER是宣告過濾, ?x是過濾模式作用的變數,後面的pattern是具體的限制條件,比如

PREFIX vcard: <http://www.w3.org/2001/vcard-rdf/3.0#>
SELECT ?g
WHERE
{ ?y vcard:Given ?g .
FILTER regex(?g, "r", "i") }

這是要查詢一些名字(Given Name),”r”表示,名字中必須出現的字母”r”或者”R””i”表示,對簽名的字母限制,對大小寫並不敏感。若是要對大小寫敏感,則去掉這個限制即可,即FILTER regex(?g, "r")

上面查詢的結果是

-------------
| g|
=============
| "Rebecca" |
| "Sarah"|
-------------

對數值限制的一個例子是:

PREFIX info <http://somewhere/peopleInfo#>
SELECT ?resource
WHERE { ?resource info:age ?age .
FILTER (?age >= 24)}

注意,在RDF檔案vc-db-1.rdf中並沒有包括年齡age資訊,這裡要查詢vc-db-2.rdf檔案,即

sparql --data=vc-db-2.rdf --query=q-f2.rq

查詢結果是:

---------------------------------
| resource|
=================================
| <http://somewhere/JohnSmith/> |
---------------------------------

5.可選的查詢資訊optional information

5.1 簡單的可選資訊

在一些查詢中,一些需要返回的資料可能不存在,而這些不存在的資料所在的資料元素中有其他需要返回的資訊,這時候就可以通過可選查詢資訊進行查詢,比如:

PREFIX info:<http://somewhere/peopleInfo#>
PREFIX vcard:<http://www.w3.org/2001/vcard-rdf/3.0#>
SELECT ?name ?age
WHERE {
?person vcard:FN?name .
OPTIONAL { ?person info:age ?age }
}

這是要查詢一些名字和年齡,但有些人沒有年齡資訊,也要返回名字。

於是,OPTIONAL表示,模式 { ?person info:age ?age }是可選的,不是必須滿足的。這個查詢的執行語句是

sparql --data=vc-db-2.rdf --query=q-opt1.rq

查詢結果是

------------------------
| name| age |
=======================
| "Becky Smith" | 23|
| "Sarah Jones" ||
| "John Smith"| 25|
| "Matt Jones"||
-----------------------

如果去點關鍵字OPTIONAL,那麼,查詢的結果就是

-----------------------
| name| age |
=======================
| "Becky Smith" | 23|
| "John Smith"| 25|
-----------------------

有些人沒有年齡資訊,那麼,這些人的名字也不會被作為查詢結果返回。

5.2 對可選模式新增過濾條件

PREFIX info:<http://somewhere/peopleInfo#>
PREFIX vcard:<http://www.w3.org/2001/vcard-rdf/3.0#>
SELECT ?name ?age
WHERE {
?person vcard:FN?name .
OPTIONAL { ?person info:age ?age . FILTER ( ?age > 24 ) }
}

這樣返回的資訊是

-----------------------
| name| age |
=======================
| "Becky Smith" ||
| "Sarah Jones" ||
| "John Smith"| 25|
| "Matt Jones"||
-----------------------

有些人沒有年齡資訊("Sarah Jones""Matt Jones" ),有些人的年齡小於24"Becky Smith"),他們的名字資訊也會出現在查詢結果中。下面的查詢要求,如果有年齡資訊,那麼年齡必須大於24,否則不是期望的查詢結果。

PREFIX info:<http://somewhere/peopleInfo#>
PREFIX vcard:<http://www.w3.org/2001/vcard-rdf/3.0#>
SELECT ?name ?age
WHERE {
?person vcard:FN?name .
OPTIONAL { ?person info:age ?age . }
FILTER ( !bound(?age) || ?age > 24 )
}

語句 !bound(?age) || ?age > 24的意思是,沒有(未繫結)age或者age大於24。如此,年齡小於24"Becky Smith"就不會出現在這個查詢的結果中了。

-----------------------
| name| age |
=======================
| "Sarah Jones" ||
| "John Smith"| 25|
| "Matt Jones"||
-----------------------

6.聯合查詢

vCard詞彙表和FOAF詞彙表都可以表示人的資訊,比如vCard中的 vCard:FN, FOAF中的 foaf:name.這一節介紹在一個RDF圖同時用vCard:FN foaf:name表示人的資訊時,如何查詢相關資料。

注:vCard是電子商務中卡的一種檔案格式標準,一般與郵件資訊關聯。FOAFhttp://xmlns.com/foaf/0.1/)是一種RDF的應用,所列網址有它的規範。

6.1 一個RDF圖檔案,vc-db-3.ttl,檔案的的內容為

@prefix foaf: <http://xmlns.com/foaf/0.1/> .
@prefix vcard: <http://www.w3.org/2001/vcard-rdf/3.0#> .
_:a foaf:name"Matt Jones" .
_:b foaf:name"Sarah Jones" .
_:c vcard:FN"Becky Smith" .
_:d vcard:FN"John Smith" .

它只是分別用foaf:namevcard:FN描述了四個人名,這一節的查詢將針對此檔案。

6.2 查詢人名資訊

PREFIX foaf: <http://xmlns.com/foaf/0.1/>
PREFIX vCard: <http://www.w3.org/2001/vcard-rdf/3.0#>
SELECT ?name
WHERE{
{ [] foaf:name ?name } UNION { [] vCard:FN ?name }
}

查詢結果是

-----------------
| name|
=================
| "Matt Jones"|
| "Sarah Jones" |
| "Becky Smith" |
| "John Smith"|
-----------------

一個等價的查詢語句是

PREFIX foaf: <http://xmlns.com/foaf/0.1/>
PREFIX vCard: <http://www.w3.org/2001/vcard-rdf/3.0#>
SELECT ?name
WHERE{
[] ?p ?name 
FILTER ( ?p = foaf:name || ?p = vCard:FN ) }

6.3 記錄結果的來源,查詢語句和結果分別是

PREFIX foaf: <http://xmlns.com/foaf/0.1/>
PREFIX vCard: <http://www.w3.org/2001/vcard-rdf/3.0#>
SELECT ?name1 ?name2
WHERE{
{ [] foaf:name ?name1 } UNION { [] vCard:FN ?name2 }
}
---------------------------------
| name1| name2|
=================================
| "Matt Jones"||
| "Sarah Jones" ||
|| "Becky Smith" |
|| "John Smith"|
---------------------------------

6.4 同時使用OPTIONALUNION

查詢語句是

PREFIX foaf: <http://xmlns.com/foaf/0.1/>
PREFIX vCard: <http://www.w3.org/2001/vcard-rdf/3.0#>
SELECT ?name1 ?name2
WHERE{
?x a foaf:Person
OPTIONAL { ?xfoaf:name?name1 } 
OPTIONAL { ?xvCard:FN?name2 }
}

查詢結果是:

---------------------------------
| name1| name2|
=================================
| "Matt Jones"||
| "Sarah Jones" ||
|| "Becky Smith" |
|| "John Smith"|
---------------------------------

7. 查詢命名的圖

圖是一個RDF資料集,不是一個完整的RDF檔案。現在有三個圖

Default graph (ds-dft.ttl):

@prefix dc: <http://purl.org/dc/elements/1.1/> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
<ds-ng-1.ttl> dc:date "2005-07-14T03:18:56+0100"^^xsd:dateTime .
<ds-ng-2.ttl> dc:date "2005-09-22T05:53:05+0100"^^xsd:dateTime .

Named graph (ds-ng-1.ttl):

@prefix dc: <http://purl.org/dc/elements/1.1/> .
[] dc:title "Harry Potter and the Philospher's Stone" .
[] dc:title "Harry Potter and the Chamber of Secrets" .

Named graph (ds-ng-2.ttl):

@prefix dc: <http://purl.org/dc/elements/1.1/> .
[] dc:title "Harry Potter and the Sorcerer's Stone" . 
[] dc:title "Harry Potter and the Chamber of Secrets" .

7.1 查詢語句是

PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
PREFIX dc: <http://purl.org/dc/elements/1.1/>
PREFIX : <.>
SELECT *{ ?s ?p ?o }

對圖的查詢是(PREFIX : <.>是為了格式化輸出???),

sparql --graph=ds-dft.ttl –namedgraph=ds-ng-1.ttl –namedgraph=ds-ng-2.ttl --query=q-ds-1.rq

查詢結果是

----------------------------------------------------------------------
| s| p| o|
======================================================================
| :ds-ng-2.ttl | dc:date | "2005-09-22T05:53:05+01:00"^^xsd:dateTime |
| :ds-ng-1.ttl | dc:date | "2005-07-14T03:18:56+01:00"^^xsd:dateTime |
|--------------------------------------------------------------------|

7.2 查詢指定圖

PREFIX dc: <http://purl.org/dc/elements/1.1/>
PREFIX : <.>
SELECT ?title{ 
GRAPH :ds-ng-2.ttl
{ ?b dc:title ?title }}

查詢結果

---------------------------------------------
| title|
=============================================
| "Harry Potter and the Sorcerer's Stone"|
| "Harry Potter and the Chamber of Secrets" |
--------------------------------------------

8. SPARQL查詢結果集

四種形式的結果

¨SELECT – 返回一個表(table),Tutorial裡介紹的主要是這種查詢

¨CONSTRUCT – 返回一個RDF

¨DESCRIBE – 返回一個RDF.

¨ASK – 布林查詢

結果調整

¨Projection 投影- keep only selected variables 只保持選擇的變數

¨OFFSET/LIMIT 偏移和限制 - chop the number solutions (best used with ORDER BY) 分解數字結果

¨ORDER BY 排序- sorted results(同資料型別類的結果???)

¨DISTINCT - yield only one row for one combination of variables and values.

9. Jena中使用SPARQL

在我的機器上,eclipse已經可以執行使用Jena APIJava程式。這樣就可以直接編寫SPARQL查詢程式。一個簡單查詢的全部程式碼如下:

import java.io.*;

import com.hp.hpl.jena.query.Query;

import com.hp.hpl.jena.ontology.OntModel;

import com.hp.hpl.jena.ontology.OntModelSpec;

import com.hp.hpl.jena.query.QueryExecution;

import com.hp.hpl.jena.query.QueryExecutionFactory;

import com.hp.hpl.jena.query.QueryFactory;

import com.hp.hpl.jena.query.ResultSet;

import com.hp.hpl.jena.query.ResultSetFormatter;

import com.hp.hpl.jena.rdf.model.ModelFactory;

publicclass OntoQuery{

publicstaticvoid main(String[] args) throws IOException{

//建立一個本體模型,這裡使用的是前一段時間設計的IIPO本體,附帶例項。

OntModel model = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM);

model.read("file:./IIPO.v1.1.with_individuals.owl");

//建立一個查詢語句

String queryString = "SELECT ?teacher ?student" +

" WHERE " +

"{ ?teacher <http://www.owl-ontologies.com/IIPO.owl#direct> ?student}";

//建立一個查詢

Query query = QueryFactory.create(queryString);

//執行查詢,獲得結果

QueryExecution qe = QueryExecutionFactory.create(query, model);

ResultSet results = qe.execSelect();

//向控制檯輸出結果s

ResultSetFormatter.out(System.out, results, query);

//釋放資源

qe.close();

} // the end of main.

} // the end.

返回的結果是:

------------------------------------------------------------------------------------------------------
| teacher| student|
|====================================================================================================|