sparql查询学习 2

说明:本文档实质上是阅读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/,有删减)

  •  “Jena 简介,这篇文章的作者也是 Philip McCarthy developerWorks2004  6 月),文中提供了Jena 语义 Web 工具包的概述,包括 RDQL 查询语言的一些细节。
  • 最新版的 SPARQL specification 提供了 SPARQL 查询语法和功能的确切描述。
  • Jena SourceForge project 上有大量 Jena 语义 Web 工具包的文档和下载。
  • Andy Seaborne  ARQ home page 上有关于从 CVS 获得 ARQ 的指导。最新的 ARQ 发行包可以在 ARQ's downloads页上找到。
  • SPARQLer  Jena  SPARQL 查询语言引擎的一个在线演示。可以用它来体验 SPARQL 查询。
  • FOAF Project 是用机器可读的 RDF 词汇来描述一些人及他们之间关系的一个实验。FOAF Vocabulary Specification 定义了本文使用的 FOAF 术语。
  • SPARQL 的图形模式是以 Turtle -- Terse RDF Triple Language 的语法为基础。
  • iMarine  http://iMarine.blog.163.com

 

你可能感兴趣的:(sparql查询学习 2)