官方文档:SPARQL 1.1 Query Language
SPARQL语言主要是面向RDF/OWL的查询语言。从图论的角度来看,查询的过程可以看做子图匹配。相应的案例采用python实现。在python中,操作本体的库是rdflib,这个库非常好用,rdflib的官方教程也非常容易看懂和上手。
数据的准备就是把Data文件复制到记事本里面,然后将txt文件的后缀名修改成为.ttl或者.rdf就可以了。
数据准备:
@prefix dc: .
@prefix owl: .
@prefix rdf: .
@prefix rdfs: .
@prefix xml: .
@prefix xsd: .
dc:a dc:name "Johnny Lee Outlaw" .
dc:a dc:mbox .
dc:b dc:name "Peter Goodguy" .
dc:b dc:mbox .
dc:c dc:mbox .
dc:a dc:age "42"^^xsd:integer .
dc:b dc:age "25"^^xsd:integer .
dc:c dc:age "36"^^xsd:integer .
dc:a dc:has "cat"@en .
_:a dc:name "Alice" .
_:b dc:name "Bob" .
查询代码:
from rdflib import Graph
g = Graph()
g.parse("data 1-1.ttl", format = 'ttl')
q = '''SELECT ?name {dc:a dc:name ?name .}'''
rows = g.query(q)
使用rdflib来操作本体并采用SPARQL查询的程序框架如上所示。在这段程序中,我们首先新建了一个图g
,然后从数据文件中将本体数据导入这个图中。q
是SPARQL查询语句,通过g.query(q)
获取查询结果。
SELECT{}
是最常用的SPARQL查询语句。?x
定义了一个变量,变量可以用?
或者$
开头,?x
和$x
指代同一个变量。{}
给这个变量限制了一些条件。上面这段查询语句的意思就是查询a的姓名,返回结果就是Johnny Lee Outlaw
。SPARQL匹配到的结果又被称为解决方案(Solutions)。
我们可以一次查询多个变量,或者设置多个限制条件——
q = '''SELECT ?name ?mail{
?x dc:name ?name .
?x dc:mbox ?mail .
}
'''
rows = g.query(q)
for row in rows:
print("%s has mail %s" %row)
查询结果:
Johnny Lee Outlaw has mail mailto:[email protected]
Peter Goodguy has mail mailto:[email protected]
上面这个案例就是同时查找人的名字及其邮箱。需要注意的是,当出现多个限制条件是,除了最后一个限制条件,其余的每个限制条件都要以.
结尾。为了避免语法错误,建议每个条件的结尾都加上.
。在SPARQL中,可以出现很多个中间变量(如上例中的?x
),来帮助完成不同指定变量(?name
,?mail
)之间的逻辑构建,这些中间变量如果不SELECT
出来,是不会出现在查询结果中的。
SPARQL也可以用于空白节点(Blank Node)的查询。
print('-'*15)
q = '''SELECT ?x ?name{
?x dc:name ?name .
}
'''
rows = g.query(q)
for row in rows:
print("%s 's name is %s" %row)
查询结果:
f3e668e8003a54a8eb9636271b8e3046ab2 's name is Bob
f3e668e8003a54a8eb9636271b8e3046ab1 's name is Alice
http://www.semanticweb.org/mayn/ontologies/2020/09/test#a 's name is Johnny Lee Outlaw
http://www.semanticweb.org/mayn/ontologies/2020/09/test#b 's name is Peter Goodguy
对于空白节点,会随机分配地址。
可以看到,
Data(1-2)
:
@prefix dt: .
@prefix ns: .
@prefix : .
@prefix xsd: .
:x ns:p "cat"@en .
:y ns:p "42"^^xsd:integer .
:z ns:p "abc"^^dt:specialDatatype .
_:a ns:name "Alice" .
_:b ns:name "Bob" .
对于指明数据类型的变量查找
在RDF文件中,我们可以看到有些属性被赋予了数据类型,比如:x ns:p "cat"@en .
说明x是词典中的单词"cat",语言是英文;:y ns:p "42"^^xsd:integer .
表明y的某个属性数值是42,类型是整型;:z ns:p "abc"^^dt:specialDatatype .
说明z的属性是abc,类型是规定的特殊类型。
对于这种指明了数据的RDF文件,在查询时同样需要指明数据类型:
SELECT ?v WHERE {
?v ?p "cat"@en .
}
如果查询语句是SELECT ?v WHERE { ?v ?p "cat" }
的话,将无法得到正确的结果。
对于数值型的变量查找
如果是对于数值型的变量查找,可以有两种表述方式:
SELECT ?v WHERE { ?v ?p "42"^^xsd:integer . }
SELECT ?v WHERE { ?v ?p 42 . }
总的来说,SPARQL中有以下几种LIiteral描述方式:
类型 | 描述案例 |
---|---|
字符串型 | “chat” |
词典型(lexical) | 'chat'@fr 该例子表明词典的语言是法语 |
自定义数据类型 | "xyz"^^ |
时间 | "abc"^^appNS:appDataType |
引号套用——如果字符串中包括双引号,则用三引号描述。 | '''The librarian said, "Perhaps you would enjoy 'War and Peace'." ''' |
整型 | 1 或者 "1"^^xsd:integer |
一位小数 | 1.3 或者 "1.3"^^xsd:decimal |
多位小数 | 1.300 或者 "1.300"^^xsd:decimal |
科学计数法 | 1.0e6 或者 "1.0e6"^^xsd:double |
布尔值(真) | true 或者 "true"^^xsd:boolean |
布尔值 (假) | false 或者 "false"^^xsd:boolean |
SPARQL通过构建一系列的三元组来进行匹配。SPARQL中的三元组的基本语法和ttl或者rdf文件中的一致。在构建这些三元组时,SPARQL有一些特殊的语法技巧:
;
隔开。比如下面这两个语句是等价的。?x foaf:name ?name ;
foaf:mbox ?mbox .
?x foaf:name ?name .
?x foaf:mbox ?mbox .
,
将宾语合并,形成一个三元组。下表中对应的两组三元组是等价的:三元组1 | 三元组2 |
---|---|
?x foaf:nick “Alice” , “Alice_” . | ?x foaf:nick “Alice” . ?x foaf:nick “Alice_” . |
?x foaf:name ?name ; foaf:nick “Alice” , “Alice_” . |
?x foaf:name ?name . ?x foaf:nick “Alice” . ?x foaf:nick “Alice_” . |
RDF Collections
如果要检索RDF Collections三元组,则可以用(element1 element2 ...)
的格式。这种格式还可以嵌套使用。官方文档给了2个案例来帮助理解。
rdf:type
在SPARQL中,可以用谓语a
来代替谓语rdf:type
。比如?x a :Class1 .
和?x rdf:type :Class1 .
是一个意思。
SPARQL是基于图形模式来匹配的,第二章主要介绍以下几种不同的匹配模式。
匹配模式 | 匹配逻辑 | 关键字 |
---|---|---|
Basic Graph Patterns | 匹配所有满足条件的变量 | SELECT |
Group Graph Patterns | 匹配所有满足WHERE条件及FILTER条件的变量(类似于逻辑语言中的AND) | SELECT WHERE FILTER |
Optional Graph patterns | 提供可选择的匹配条件,如果满足OPTIONAL条件,则返回OPTIONAL相关的结果;OPTIONAL中的条件不影响其他变量的匹配。 | OPTIONAL |
Alternative Graph Pattern | 匹配UNION条件中的任意一个,即可得到结果,类似于逻辑语言中的OR;如果UNION所有的条件均不满足,则无法匹配。 | UNION |
Negation | 主要是对匹配结果的筛选 | FILTER NOT EXISTS / FILTER EXISTS / MINUS |
Patterns on Named Graphs | 匹配指定命名空间中的三元组 | FROM |
@prefix dc: .
@prefix owl: .
@prefix rdf: .
@prefix rdfs: .
@prefix xml: .
@prefix xsd: .
dc:a dc:name "Johnny Lee Outlaw" .
dc:a dc:mbox .
dc:b dc:name "Peter Goodguy" .
dc:b dc:mbox .
dc:c dc:mbox .
dc:a dc:age "42"^^xsd:integer .
dc:b dc:age "25"^^xsd:integer .
dc:c dc:age "36"^^xsd:integer .
比如,我们要获取本体中的所有三元组,可以使用下面这条查询语句:
SELECT * {?s ?p ?o .}
关于SELECT WHERE{}
的案例在第一章中已经有很多,在此不做赘述。
Group Graph Patterns在Basic Graph Patterns的基础上增加了对结果的过滤条件。比如,我们想要知道本体中年龄大于30的人,可以用下面这条查询语句,过滤条件用FILTER ()
来实现:
SELECT ?x WHERE{
?x dc:age ?age .
FILTER (?age >30)
}
匹配结果:
http://www.semanticweb.org/mayn/ontologies/2020/09/test#c
http://www.semanticweb.org/mayn/ontologies/2020/09/test#a
如果要过滤包含字符串的结果,则用FILTER regex (element1, element2)
来实现:
SELECT ?x WHERE{
?x dc:name ?name .
FILTER regex(?name, "Lee")
}
匹配结果:
http://www.semanticweb.org/mayn/ontologies/2020/09/test#a
Optional matching provides this facility: if the optional part does not match, it creates no bindings but does not eliminate the solution.
OPTIONAL
用于指定可选的匹配条件。比如下面这组匹配模式,?x dc:mbox ?mail .
是必须满足的条件,?x dc:name ?name .
是选择满足的条件。运行下面的匹配模式,可以得到三个结果。而如果不添加OPTIONAL条件,则只能得到两个结果。
SELECT ?x ?name ?mail WHERE{
?x dc:mbox ?mail .
OPTIONAL{?x dc:name ?name .}
}
匹配结果:
http://www.semanticweb.org/mayn/ontologies/2020/09/test#b Peter Goodguy mailto:[email protected]
http://www.semanticweb.org/mayn/ontologies/2020/09/test#a Johnny Lee Outlaw mailto:[email protected]
http://www.semanticweb.org/mayn/ontologies/2020/09/test#c None mailto:[email protected]
SELECT ?x ?name ?mail WHERE{
?x dc:mbox ?mail .
?x dc:name ?name .
}
匹配结果:
http://www.semanticweb.org/mayn/ontologies/2020/09/test#b Peter Goodguy mailto:[email protected]
http://www.semanticweb.org/mayn/ontologies/2020/09/test#a Johnny Lee Outlaw mailto:[email protected]
同时,也可以在OPTIONAL
条件中添加限制条件:
SELECT ?x ?name ?age WHERE{
?x dc:name ?name .
OPTIONAL{
?x dc:age ?age .
FILTER(?age > 30)
}
}
匹配结果:
http://www.semanticweb.org/mayn/ontologies/2020/09/test#a Johnny Lee Outlaw 42
http://www.semanticweb.org/mayn/ontologies/2020/09/test#b Peter Goodguy None
当然,可以有多个OPTIONAL
条件:
SELECT ?x ?name ?mail ?age WHERE{
?x dc:mbox ?mail .
OPTIONAL{?x dc:name ?name .}
OPTIONAL{?x dc:age ?age .}
}
匹配结果:
http://www.semanticweb.org/mayn/ontologies/2020/09/test#a Johnny Lee Outlaw mailto:[email protected] 42
http://www.semanticweb.org/mayn/ontologies/2020/09/test#b Peter Goodguy mailto:[email protected] 25
http://www.semanticweb.org/mayn/ontologies/2020/09/test#c None mailto:[email protected] 36
需要注意的是,OPTIONAL
是left-associative的。我的理解就是它只限制它对的前一个三元组所匹配得到的结果,并不是对整个查询模式的匹配。
Alternative Graph Pattern通过UNION
来实现。
数据准备:
@prefix dc10: .
@prefix dc11: .
_:a dc10:title "SPARQL Query Language Tutorial" .
_:a dc10:creator "Alice" .
_:b dc11:title "SPARQL Protocol Tutorial" .
_:b dc11:creator "Bob" .
_:c dc10:title "SPARQL" .
_:c dc11:title "SPARQL (updated)" .
查询代码:
SELECT ?title WHERE {
{ ?book dc10:title ?title } UNION { ?book dc11:title ?title }
}
匹配结果:
SPARQL Query Language Tutorial
SPARQL
SPARQL Protocol Tutorial
SPARQL (updated)
可以使用多个UNION
来联合不同的条件:
SELECT ?x ?y ?z WHERE{
{ ?book dc10:title ?x } UNION { ?book dc11:title ?y } UNION {?book dc10:creator ?z}
}
匹配结果:
SPARQL Query Language Tutorial None None
SPARQL None None
None SPARQL Protocol Tutorial None
None SPARQL (updated) None
None None Alice
SELECT ?title ?author WHERE {
{ ?book dc10:title ?title . ?book dc10:creator ?author }
UNION
{ ?book dc11:title ?title . ?book dc11:creator ?author }
}
匹配结果:
SPARQL Query Language Tutorial Alice
SPARQL Protocol Tutorial Bob
Negation主要是对匹配结果的筛选。首先。FILTER NOT EXISTS
筛选出不符合相关条件的变量。比如下面这组模式,匹配的是有邮箱但是没有名字的变量,匹配结果是http://www.semanticweb.org/mayn/ontologies/2020/09/test#c
。在实际的应用中,FILTER NOT EXISTS
在本体或者知识图谱的查漏这方面有比较大的发挥空间。
SELECT ?x WHERE{
?x dc:mbox ?mail .
FILTER NOT EXISTS {?x dc:name ?name .}
}
匹配结果:
http://www.semanticweb.org/mayn/ontologies/2020/09/test#c
我们也可以通过FILTER EXISTS
来找到那些既有邮箱,又有姓名的人。
SELECT ?x WHERE{
?x dc:mbox ?mail .
FILTER EXISTS {?x dc:name ?name .}
}
匹配结果:
http://www.semanticweb.org/mayn/ontologies/2020/09/test#a
http://www.semanticweb.org/mayn/ontologies/2020/09/test#b
使用FILTER
实际上是对整个匹配模型进行了筛选。SPARQL同样提供了left-associative的关键字——MINUS
。
SELECT ?x WHERE{
?x dc:mbox ?mail .
MINUS {?x dc:name "Johnny Lee Outlaw" .}
}
匹配结果:
http://www.semanticweb.org/mayn/ontologies/2020/09/test#c
http://www.semanticweb.org/mayn/ontologies/2020/09/test#b
FILTER和MINUS是两种不同的删减思路,他们主要的区别在官网中有比较清晰的描述。主要从以下三个方面来理解:
匹配模式 | 匹配结果 |
---|---|
对于FILTER NOT EXISTS
来说,虽然其条件中的变量?x ?y ?z
和外层的?s ?p ?o
不一样,但是他们的匹配模式是相同的,所以筛选出不符合{?x ?y ?z}
的结果,返回没有匹配。而MINUS
条件中的变量名和外层的条件中没有匹配,所以删减的是变量名为{?x ?y ?z}
的模式,结果就是啥都没有删减。
用一句话来概括就是,MINUS
内外参数共享,而FILTER NOT EXISTS
内外参数不共享。如果能理解这个,后面两个就能很好地理解了。
匹配模式 | 匹配结果 |
---|---|
匹配模式 | 匹配结果 |
---|---|
属性路径提供了更加灵活的匹配模式。属性路径(Property Path)是图中两个节点之间的关系集合。SPARQL中关于属性路径的语法如下表所示,其中iri
表示前缀(命名空间的全称或者缩写),elt
表示路径元素。计算优先级从高到低,1表示最高;同一级的运算按照从左至右进行。
Property Path 类型 | 语法格式 | 匹配逻辑 | 计算优先级 |
---|---|---|---|
PredicatePath | iri |
An IRI. A path of length one. | 1 |
NegatedPropertySet | !iri 或者!(iri1| ...|irin) |
路径中不包含相关的匹配。需要注意的是,!iri 和!(iri) 并不等价。 |
2 |
NegatedPropertySet | !^iri 或者!(^iri1| ...|^irin) |
反向路径中不包含相关的匹配。!^iri 和!(^iri) 并不等价。 |
2 |
NegatedPropertySet | !(iri1| ...|irij|^irij+1| ...|^irin) |
前面两种否定形式的结合。 | 2 |
组合路径 Groups | (elt) |
路径组合 | 3 |
ZeroOrMorePath | elt* |
匹配0个以上路径元素elt |
4 |
OneOrMorePath | elt+ |
匹配1个以上路径元素elt |
4 |
ZeroOrOnePath | elt? |
匹配0个或1个路径元素elt |
4 |
InversePath | ^elt |
表示路径的反方向 | 5 |
SequencePath | elt1 / elt2 |
匹配路径序列(elt1 → elt2 ) |
6 |
AlternativePath | elt1 | elt2 |
匹配路径中的任意一个(elt1 or elt2 ) |
7 |
数据准备:
@prefix dc: .
@prefix : .
@prefix ns: .
:book1 dc:title "SPARQL Tutorial" .
:book1 ns:price 42 .
:book1 ns:discount 0.2 .
:book2 dc:title "The Semantic Web" .
:book2 ns:price 23 .
:book2 ns:discount 0.25 .
BIND——给变量赋值
SELECT ?title ?price{
?x ns:price ?p .
?x ns:discount ?discount
BIND (?p*(1-?discount) AS ?price)
?x dc:title ?title .
}
匹配结果:
The Semantic Web, 17.25
SPARQL Tutorial, 33.6
我们可以看到,利用关键字BIND
可以将运算结果重新赋予变量?price
。
VALUES——限制变量的取值范围
SELECT ?book ?title ?price{
VALUES ?book { :book1 :book3 }
?book dc:title ?title ;
ns:price ?price .
}
匹配结果:
http://example.org/book/book1, SPARQL Tutorial 42
这组匹配模式的意思是匹配变量?book
,该变量的取值范围是{ :book1 :book3 }
,并输出其书名和价格。因为数据里面没有:book3
,所以返回的结果只匹配了:book1
。
下面是另一个例子。
SELECT ?book ?title ?price
{
?book dc:title ?title ;
ns:price ?price .
VALUES (?book ?title)
{ (UNDEF "SPARQL Tutorial")
(:book2 UNDEF)
}
}
匹配结果:
http://example.org/book/book1, SPARQL Tutorial 42
http://example.org/book/book2, The Semantic Web 23
这里,关键字UNDEF
表示对变量没有限制条件。这组匹配模式匹配的是书名为"SPARQL Tutorial"
和书:book2
的书名和价格。
Aggregates用于对匹配结果的整合。一般来说,匹配结果默认会放在一起。如果我们希望能够得到分组结果,可以使用分组关键字GROUP BY
和HAVING
。同时,可以使用COUNT
, SUM
, MIN
, MAX
, AVG
, GROUP_CONCAT
和SAMPLE
等关键字对结果进行整合。、
数据准备:
@prefix : .
:org1 :affiliates :auth1, :auth2 .
:auth1 :writesBook :book1, :book2 .
:book1 :price 9 .
:book2 :price 5 .
:auth2 :writesBook :book3 .
:book3 :price 7 .
:org2 :affiliates :auth3 .
:auth3 :writesBook :book4 .
:book4 :price 7 .
查询代码:
SELECT ?org (SUM(?lprice) AS ?totalPrice)
WHERE{
?org :affiliates ?auth .
?auth :writesBook ?book .
?book :price ?lprice .
}
GROUP BY ?org
匹配结果:
http://books.example/org1 21
http://books.example/org2 7
可以看到,这组匹配模式匹配的是书的价格总和,并且按照机构?org
来分组。在SELECT
条件中,虽然出现了?lprice
变量,但是通过(SUM(?lprice) AS ?totalPrice)
将?lprice
变量的结果整合到了?totalPrice
中,所以匹配结果中只有?org
和?totalPrice
两个变量。
关键字HAVING
相当于对组合结果的过滤(FILTER)。
SELECT ?org (SUM(?lprice) AS ?totalPrice)
WHERE{
?org :affiliates ?auth .
?auth :writesBook ?book .
?book :price ?lprice .
}
GROUP BY ?org
HAVING (SUM(?lprice) > 10)
匹配结果:
http://books.example/org1 21
SPARQL查询语句SELECT
是可以嵌套使用的。
数据准备:
@prefix : .
:alice :name "Alice", "Alice Foo", "A. Foo" .
:alice :knows :bob, :carol .
:bob :name "Bob", "Bob Bar", "B. Bar" .
:carol :name "Carol", "Carol Baz", "C. Baz" .
查询代码:
SELECT ?y ?minName
WHERE{
:alice :knows ?y .
{
SELECT ?y (MIN(?name) AS ?minName)
WHERE{
?y :name ?name .
}
GROUP BY ?y
}
}
匹配结果:
http://people.example/bob B. Bar
http://people.example/carol C. Baz
在上面这个匹配模式中,首先先执行内层的匹配模式SELECT ?y (MIN(?name) AS ?minName) WHERE{ ?y :name ?name . } GROUP BY ?y
,得到以下三个结果(?y
和?minName
):
http://people.example/bob B. Bar
http://people.example/carol C. Baz
http://people.example/alice A. Foo
然后在这个结果的基础上,执行外层的匹配模式SELECT ?y ?minName WHERE {:alice :knows ?y . }
。
The default graph is defined as the union of all named graphs.
参考资料:SPARQL datasets and named graphs
参考资料:13 RDF Dataset
前面我们使用的SPARQL语句都是针对Default Graph的,如果我们要针对某一命名空间中的三元组(Named Graph)进行匹配,SPARQL查询可以通过使用FROM
子句和FROM NAMED
子句来指定用于匹配的数据集。
匹配模式 | 关键字 | 匹配逻辑 |
---|---|---|
Order | ORDER BY | 对匹配结果进行排序 |
Projection | 选择特定的变量,即得到结果的子集。如果是SELECT * ,那么返回的结果中会包含所有限制条件中出现的变量;如果是SELECT ?x ,那么即使限制条件中出现了?y 、?z ,最后的结果只会返回变量?x 的匹配结果。这个过程就叫做Projection。 |
|
Duplicate Solutions | DISTINCT / REDUCED | 确保返回的结果中没有重复的选项 |
Offset | OFFSET | 返回从关键字OFFSET 后指定的数字开始的匹配结果 |
Limit | LIMIT | 限制返回的匹配结果的数量。如果把匹配结果看成是一个list,那么OFFSET num_1 LIMIT num_2 相当于list[num1: num1 + num2]。 |
数据准备:
@prefix dc: .
@prefix owl: .
@prefix rdf: .
@prefix rdfs: .
@prefix xml: .
@prefix xsd: .
dc:a dc:name "Johnny Lee Outlaw" .
dc:a dc:mbox .
dc:b dc:name "Peter Goodguy" .
dc:b dc:mbox .
dc:c dc:mbox .
dc:a dc:age "25"^^xsd:integer .
dc:b dc:age "25"^^xsd:integer .
dc:c dc:age "36"^^xsd:integer .
dc:c dc:name "Carol" .
ORDER BY
后面的语句是排序的依据。
例子 | 排序逻辑 | 匹配结果 |
---|---|---|
SELECT ?name WHERE{ ?x dc:name ?name . } ORDER BY ?name |
对匹配结果根据人名来排序。 | Carol Johnny Lee Outlaw Peter Goodguy |
SELECT ?name WHERE{ ?x dc:name ?name . ?x dc:age ?age . } ORDER BY ASC(?age) |
关键字DESC 表示降序,ASC 表示升序。这组匹配模式的匹配结果将根据年龄从低到高输出人名。 |
Peter Goodguy Johnny Lee Outlaw Carol |
SELECT ?name WHERE{ ?x dc:name ?name . ?x dc:age ?age . } ORDER BY ?age DESC(?name) |
这里有两个限制条件,首先,先按照年龄排序,对于相同年龄的人,按照姓名进行逆序排列。 | Peter Goodguy Johnny Lee Outlaw Carol |
对于不同的数据类型,SPARQL也规定了比较方法:numerics(数值型 数据8.2 确保匹配结果不重复——DISTINCT / REDUCED
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
_:x foaf:name "Alice" .
_:x foaf:mbox <mailto:alice@example.com> .
_:y foaf:name "Alice" .
_:y foaf:mbox <mailto:asmith@example.com> .
_:z foaf:name "Alice" .
_:z foaf:mbox <mailto:alice.smith@example.com> .
匹配模式
匹配结果
9. SPARQL的查询形式(Query Forms)
Query Forms
应用场景
SELECT
Returns all, or a subset of, the variables bound in a query pattern match.
CONSTRUCT
Returns an RDF graph constructed by substituting variables in a set of triple templates. 类似于SWRL中的(?x p1 ?y)→ (?x p2 ?y)
ASK
Returns a boolean indicating whether a query pattern matches or not. 可用于判断某个/类三元组是否存在,对于知识图谱的查漏比较有用。
DESCRIBE
Returns an RDF graph that describes the resources found.