RDF数据查询语言SPARQL:初步

【转载】http://imarine.blog.163.com/blog/static/5138018320071119110889/

RDF数据查询语言SPARQL:初步

技术文档 2007-12-19 13:01:00 阅读3303 评论24  字号: 订阅

iMarine原创整理,引用请注明 http://iMarine.blog.163.com

说明:本文档实质上是阅读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

在 ARQ's downloadshttp://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:name vcard: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 { ?x  foaf:name  ?name1 } 
  OPTIONAL { ?x  vCard: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;

 

public class OntoQuery{

    public static void 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                                        |             
|====================================================================================================| 
|<http://www.owl-ontologies.com/IIPO.owl#Teacher_1> | <http://www.owl-ontologies.com/IIPO.owl#Std_1> | 
|----------------------------------------------------------------------------------------------------|

 

 

总结:并没能够很好的理解SPARQL,纯粹对Tutorial的翻译和rephrasing.

 

参考资料 (引自一篇文档http://www.ibm.com/developerworks/cn/java/j-sparql/,有删减)

 

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值