sparql查询学习

SPARQL 提供了四种不同形式的查询:SELECT、ASK、DESCRIBE 和 CONSTRUCT。我将通过几个查询来说明每种查询类型的不同形式、各种语法技巧、变化形式和查询的用途。这些查询有很多共性。在大多数情况下,我都使用 SELECT 形式来介绍,因为这可能是最常用的查询类型。

SELECT 查询形式用于标准查询。以标准 SPARQL XML 结果格式返回查询结果。本节中多数查询都要用到 SELECT 查询。ASK 的结果是 yes/no,没有具体内容,后面的 清单 33 将会展示。DESCRIBE 用于提取本体和实例数据的一部分。CONSTRUCT 根据查询图的结果生成 RDF,在 下载 部分的代码中可以找到一些例子。

为了节约空间,本教程中的例子将只保留前两个结果,除非必须看到全部内容。多数查询返回的结果都多于两个。如果您痛恨那些罗罗嗦嗦的手册和书籍,我和您一样。本教程会尽量避免这种情况。本教程中重复的一个地方是查询的前缀。查询应该能够立即使用,因此它们必须是自成体系的。您可以直接将其拖到查询表单中执行。

分解查询

清单 22 中的查询获取所有的注释并按照时间先后返回。这一节我们看看典型的 SPARQL 查询语法。下一节 将讨论三元组库用于查找和查询匹配的三元组的算法。


清单 22. 按日期顺序返回注释的查询
                    
PREFIX : <http://aabs.purl.org/ont/journal#>

SELECT ?notes
WHERE
 {
 ?e a :JournalEntry .
 ?e :notes ?notes .
 ?e :date ?date .
 }
ORDER BY ?date

每个 SPARQL SELECT 查询都包括一组按顺序排列的部分。第一部分是序言,包括可选的 BASE 定义和一些前缀定义。其后的 SELECT 部分以 SELECT 开始,描述搜索哪个图的可选的数据集部分,后面用 WHERE 子句表达描述目标结果的图模式。WHERE 子句之后是一些结果修饰符:Order 子句、Limit 子句或者 Offset 子句。这些修饰符将在后面介绍。

结果如清单 23 所示。


清单 23. 清单 22 的查询结果
                    
notes

"Today I wrote some more content for the great new SPARQL tutorial ...

"Today I learnt about insane asylums"

要使返回结果按倒序排列,可通过选择顺序修饰符 ASC()DESC() 实现。下面的命令可以使结果按相反的顺序出现:ORDER BY DESC(?date)

如果还想在日期排序中根据其他变量排序,可以在 ORDER BY 子句中添加其他变量:ORDER BY DESC(?date) ASC(?notes)

如果需要把结果限制到前 5 个,可使用 LIMIT 运算符(如清单 24 所示)。


清单 24. 限制返回的结果数量
                    
SELECT ?notes
WHERE
 {
 ?e a :JournalEntry .
 ?e :notes ?notes .
 ?e :date ?date .
 }
ORDER BY ?date
LIMIT 5

如果准备跳过某些结果,可使用 OFFSET 修饰符(如清单 25 所示)。


清单 25. 跳过部分结果
                    
SELECT ?notes
WHERE
 {
 ?e a :JournalEntry .
 ?e :notes ?notes .
 ?e :date ?date .
 }
ORDER BY ?date
LIMIT 5
OFFSET 150

如果进行过 SQL 开发,应该很熟悉这些修饰符。

搜索三元组库

使用图模式获取结果的过程非常简单。多数三元组库都在内存或者数据库中保存三元组,可按照主语、谓语和宾语查询。SPARQL 在查询图模式中用一组三元组表示。首先假设图模式中只有一个三元组。查询可能提供具体的主语 URI。这样的话,三元组库可以忽略没有该主语的所有三元组。然后再筛选掉与图模式提供 的谓语不匹配的所有三元组。最后,如果 SPARQL 提供了具体的宾语,还可进一步排除不匹配的三元组。

如果查询的主语、谓语或宾语中使用了变量,则不排除那些不匹配的三元组,三元组库将其全部保留,因为可能和变量匹配。上例中第一个三元组是 ?e a :JournalEntry .a 是 rdfs:type 的简写,因此三元组库可以忽略所有谓语不是 rdfs:type 的三元组。然后再筛选掉宾语不是 :JournalEntry 的三元组。余下的就是可以作为 ?e 结果的三元组。

上述查询的图模式包含多个三元组,因此三元组库在完成之前还需要对其他三元组做同样的处理。如果一个变量出现在多个位置,则可以使用所有那些值相同的三元组的交集。上例中所有匹配的三元组必须有一个匹配的主语。如果不符合,则丢弃,结果中只保留剩下的三元组。变量匹配可能有多种方式,所以会有多个结果。三元组库的最后一步是根据结果集需要的变量创建结果集。

在搜索的最后,三元组库将得到包含 ?e?notes?date 的结果集,这些都是查询中定义的变量。如果 SELECT 查询的形式为 “SELECT ?date ?notes”,则不返回 ?e,虽然在查询中很重要。

上述过程是实际过程的简化形式。有多种方法可以加快这个过程(比如一次进行多项匹配)。完成的任务将是一样的。

按照日期顺序取得所有预约列表

清单 22 中的查询可以创建一个简单的微型博客,按照日期顺序显示注释。和 twitter 差不多。这个查询采用相同的形式,按照日期顺序返回所有的预订列表。如果准备组织新的项目团队,这样的查询是必需的,以便筛掉已经预定的雇员。

在清单 26 中,必须连接多个类的数据:EmployeeBookingCustomer 和 User。SQL 表示连接表的语法非常笨拙。所幸的是 SPARQL 不会这样。它根本就是为这类查询而设计的,因此非常简单。您需要定义一个图匹配模式,定义需要返回的每个类的属性。在三元组世界中,连接的结果是另一个三元组。清单 26 展示了这个查询。


清单 26. 按日期返回所有的预约信息
                    
PREFIX u: <http://aabs.purl.org/ont/users#>
PREFIX j: <http://aabs.purl.org/ont/journal#>
PREFIX b: <http://aabs.purl.org/ont/avail#>

SELECT ?dn ?custName ?startDate ?endDate 
WHERE
{
?booking a b:EmployeeBooking ;
 b:startDate ?startDate ;
 b:endDate ?endDate ;
 b:employee ?dl ;
 b:with ?cust .
?cust a b:Customer ;
 b:name ?custName .
?emp a u:User ;
 u:domainLogin ?dl ;
 u:displayName ?dn .
}
ORDER BY ?startDate

首先定义了三个名称空间前缀:uj 和 b,分别用于用户、日志和预约。然后告诉 Joseki 您需要和变量 ?dn?custName?startDate 以及 ?endDate 的匹配。?dn 仅仅是 “display name” 的简写形式,也是查询运行后包含的内容。

在基本的图模式中定义了预约(称为 ?booking)及其起始和结束日期(?startDate 和 ?endDate)。意思是说在 b:EmployeeBooking类型的图中定义了一些实例。只要发现 b:Employeebooking 类型的匹配,就一定有 b:startDate 和 b:endDate 类型的属性。与这些属性匹配的内容可以放在变量 ?startDate 和 ?endDate 中。

查询结果定义规定必须取得雇员的 u:displayName 和与其联系的客户的 b:name。查询必须定义谁以及这些属性是什么,以便获得正确的匹配。因此定义 ?emp 和 ?cust 实例及其属性。查询只需要将其链接起来,以引入将预约、用户和客户类的实例链接到一起的三元组。EmployeeBooking 的对象属性 b:employee 链接一个特定的用户实例。它的 b:with 属性则链接到 Customer 类。

添加 'b:with ?cust' 三元组(主语仍然是 ?booking),这可以告诉 SPARQL 只需要返回和 ?booking 返回结果匹配的 ?cust(如表 1 所示)。这就是 SPARQL 中的连接。:User 类也是如此。


表 1. 与 ?booking 匹配的 ?cust 的连接结果
dn custName startDate endDate
"Andrew Matthews" "IBM" "2008-03-01T09:00:00" ^^xsdt:dateTime "2008-03-08T09:00:00" ^^xsdt:dateTime
"John Connor" "IBM" "2008-03-01T09:00:00" ^^xsdt:dateTime "2008-03-08T09:00:00" ^^xsdt:dateTime

连接很简单吧?只需要声明两个类的实例之间存在关系,SPARQL 只返回存在这种关系的匹配。

获取所有用户(雇员)

这个查询和前面的查询非常相似。清单 27 中的查询使用了默认前缀,因为它只处理一个本体中的 URI。因为可以假定该类和对象属性的 URI,因此可以使用分号(:)作为前缀。


清单 27. 使用默认前缀的查询
                    
PREFIX : <http://aabs.purl.org/ont/users#>

SELECT DISTINCT ?dl ?dn
WHERE {
 ?u a :User ;
 :domainLogin ?dl ;
 :displayName ?dn .
}
ORDER BY ?dn

表 2 显示了 清单 27 中查询的结果。


表 2. 默认前缀查询的结果
dl dn
"someDomain/andrew.matthews" "Andrew Matthews"
"someDomain/john.connor" "John Connor"
"someDomain/john.doe" "John Doe"
"someDomain/sarah.connor" "Sarah Connor"

获取通过关键字筛选的所有日志条目的注释

作为对公司内其他雇员的一项服务,可以按照作者附加到日志条目上的标签进行聚合。从而为 RDF 或者 Java 开发提供专门的流。希望了解和 RDF 有关的工作的用户可以订阅这样的流,从而得到量身定做的提要。

这个查询很有意思,因为它引入了 FILTER 关键字。允许用表达式来定义匹配变量的属性。该查询假设您只对那些包含关键字 SPARQL 的注释感兴趣。

清单 28 中的查询仅仅取得所有日志条目的注释部分 — 不想看到大量的文本。这是使用 FILTER 关键字的第一个查询。筛选提供了一种非图形化的方法来定义匹配结果特性。下面的例子使用正则表达式匹配包含单词 SPARQL 的条目。


清单 28. 检索注释中包含单词 “today” 的所有日志条目
                    
PREFIX : <http://aabs.purl.org/ont/journal#>

SELECT ?notes
WHERE
 {
 ?e a :JournalEntry .
 ?e :notes ?notes .
 FILTER regex(?notes, "today")
 }
ORDER BY ?date

该查询使用了默认名称空间前缀分号(:)。该查询仅指一个本体中定义的实体,因此谓语和类型没有歧义。FILTER 表达式使用正则表达式说明需要包含单词 SPARQL 的日志条目。结果有两个,如清单 29 所示。


清单 29. 结果
                    
notes

"Went to work on the SPARQL tutorial today. I seem to have a terminator
fixation."

"Today I wrote some more content for the great new SPARQL tutorial that
I've been preparing. I used some Turtle, and I defined a simple
ontology for defining journal entries. This is an example of one of
those entries!"

正则表达式是可用的函数和运算符之一。它来自 XPath 和 XQuery 系统。FILTER 表达式支持中缀和前缀运算符以及括号的一般语法,因此清单 30 也是有效的。


清单 30. 使用 FILTER 限制图匹配的更多例子 
                    
  FILTER (?t = "RDF" || ?t = "OWL" || ?t = "cash")

 FILTER (
 (?start > "2008-03-05T09:00:00"^^xsdt:dateTime && 
 ?start < "2008-03-07T09:00:00"^^xsdt:dateTime)||
 (?start < "2008-03-05T09:00:00"^^xsdt:dateTime && 
 ?end > "2008-03-05T09:00:00"^^xsdt:dateTime)
 )
 

运算符、函数的完整列表以及类型匹配请参阅 SPARQL 文档。

获取具备所需技能的所有用户

如果需要组建一个团队(这也是本教程中的例子),需要一份具备将要使用的技术知识的人员清单。要找到这些人,需要提供要寻找的所有技能或技术,看看谁和这些技能匹配。这个查询的意义在于它使用了 UNION 运算符。UNION 可以合并单独查询的结果。可以用它将每种技术的查询结果合并起来。

这个例子获取编写的日志条目中标记有 RDF、OWL 或 SPARQL 的所有用户的显示名称。UNION 运算符允许合并可替换的图模式的结果。

一般来说,返回结果前必须匹配所有的图模式。但是 UNION 只需要满足任何一个子图模式即可。在清单 31 所示查询中,任何能够匹配 {?e j:tag "RDF".}{?e j:tag "OWL".} 或 {?e j:tag "SPARQL".} 的结果都是可接受的。它相当于 OR 运算符,后面将看到 || 运算符也能实现同样的效果。


清单 31. 获取具备匹配技能的用户
                    
PREFIX u: <http://aabs.purl.org/ont/users#>
PREFIX j: <http://aabs.purl.org/ont/journal#>

SELECT DISTINCT ?dn
WHERE
{
?u a u:User;
 u:displayName ?dn .
?e a j:JournalEntry;
 j:user ?u .
 {
 {?e j:tag "RDF".} UNION 
 {?e j:tag "OWL".} UNION 
 {?e j:tag "SPARQL".}
 }
}

通常,定义所处理的本体的名称空间以及感兴趣的变量。然后定义希望用户匹配的属性。这里定义了希望连接的两个实例(?u 表示用户,?e 表示日志条目)。为了建立连接,在日志条目中描述 j:user 属性。实例及其之间的关系被定义之后,另一个图模式根据附加到日志条目的标记将匹配项合并到一起(如表 3 所示)。


表 3. 连接日志实例和用户类的实例
dn
"Andrew Matthews"
"John Doe"

表示该查询的另一种方法是使用 FILTER。

清单 31 中的简单查询将日志实例和用户类实例连接起来。该查询(清单 32)引入了一个字符串文字作为三元组模式 <?e j:tag "RDF"> 的宾语。它的意思很清楚,但是如果没有读过本教程开始部分关于 RDF 和 RDF 的介绍,现在最好读一读。


清单 32. 该查询使用 FILTER 实现和清单 31 中的 UNION 同样的结果
                    
PREFIX u: <http://aabs.purl.org/ont/users#>
PREFIX j: <http://aabs.purl.org/ont/journal#>

SELECT DISTINCT ?dn
WHERE
{
?u a u:User;
 u:displayName ?dn .
?e a j:JournalEntry;
 j:user ?u ;
 j:tag ?t .
 FILTER (?t = "RDF" || ?t = "OWL" || ?t = "SPARQL")
}

筛选器的逻辑意义和前面的基于 UNION 的查询一样,但如果不熟悉多图模式的话可能更容易理解。

给定日期哪位雇员开始为客户服务

很多查询可能需要对数据进行概括,或者得到许多问题(比如 “Do we have someone working at X this week?”)的是或者否的简要答案。SPARQL 可使用 ASK 查询类型解决这类问题。

清单 33 中的查询是否有人在 3月 18 日开始在 IBM 工作。不需要关心是谁,只想知道有没有。


清单 33. 询问是否有人在 3 月 18 日开始在 IBM 工作
                    
PREFIX b: <http://aabs.purl.org/ont/avail#>
PREFIX u: <http://aabs.purl.org/ont/users#7>
PREFIX xsdt: <http://www.w3.org/2001/XMLSchema#>
 
ASK
{
 ?x a u:User;
 u:displayName ?dn;
 u:domainLogin ?dl.
 ?c a b:Customer;
 b:name "IBM".
 ?b a b:EmployeeBooking;
 b:with ?c;
 b:employee ?dl;
 b:startDate "2008-03-18T09:00:00"^^xsdt:dateTime.
}

ASK 查询只需要返回是否找到了结果,返回结果基本上不需要占用带宽。该查询的格式类似于 SELECT。但是没有定义返回变量,因为不需要返回变量。相反,它返回 true 或者 false 表示查询(如果使用 SELECT)有没有返回数据(如清单 34 所示)。


清单 34. ASK 查询返回 true
                    
ASK => true

通过上面这些查询示例,您应该对 SPARQL 有一定的了解了。本文未进行详细讨论,可以通过 下载 部分的示例代码了解从这个日志示例导出数据的各种方法。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值