最近学习了一点是指图谱相关的内容,其中对RDF数据的查询最常用的就是SPARQL了,简单的学习了一下它的语言,和SQL语句类似。
Data:
@prefix foaf: .
_:a foaf:name ”Johnny Lee Outlaw“.
_:a foaf:mbox "".
_:b foaf:name ”Peter Googguy“.
_:a foaf:mbox "".
_:c foaf:mbox "".
Query:
PREFIX foaf:
SELECT ?name ?mbox
WHERE
{?x foaf:name ?name .
?x foaf:mbox ?mbox}
Query Result
name | mbox |
---|---|
“Johnny Lee Outlaw” | “mailto:[email protected]” |
“Peter Googguy” | mailto:[email protected] |
Data:
@prefix dt: .
@prefix ns:
@prefix :
@prefix xsd: .
:x ns:p "cat"@en.
:y ns:p "42"^^xsd:integer .
:z ns:p "abc"^^dt:specialDatatype
其中"cat"是RDF数据内容,@en是该内容的一个类型标记;
同理下面的整形 和specialDatatype为一个带有数据类型http://example.org/datatype#specialDatatype的类型化文字。
在具有数据标记的RDF数据中如果不带类型是查询不到的,例如:
SELECT ?v WHERE{?v ?p "cat"}
正确的查询方法为:
SELECT ?v WHERE {?v ?p "cat"@en}
v |
---|
http://example.org//ns#x |
SELECT ?v WHERE {?v ?p 42}
v |
---|
http://example.org/ns#y |
SELECT ?v WHERE {?v ?p "abc"^^
v |
---|
http://example.org/ns#z |
查询结果可以包含空白节点,本文档中示例结果集中的空白节点“_:”形式编写,后跟空白节点标签。
Data:
@prefix foaf: .
_:a foaf:name "Alcie"
_:b foaf:name "Bob"
Tips:注意这里的空白节点和前面的空白前缀不同
Query:
PREFIX foaf:
SELECT ?x ?name
WHERE {?x foaf:name ?name}
Query Result:
x | name |
---|---|
_:c | “Alice” |
_:d | “Bob” |
Data:
@prefix foaf:
_:a foaf:givenName "John" .
_:a foaf:surname "Doe" .
Query:
PREFIX foaf:
SELECT ?name
WHERE {
?P foaf:givenName ?G ;
foaf:surname ?S
BIND(CONCAT(?G," ",?S) AS ?name)
}
Query Result:
name |
---|
“John Doe” |
Data:
@prefix dc: .
@prefix : .
@prefic ns: .
:book1 dc:title "SPARQL Tutorial" .
:book1 ns:price 42 .
:book2 dc:title "The Semantic Web" .
:book2 ns:price 23 .
Query:
PREFIX dc:
SELECT ?title
WHERE {
?x dc:title ?title
FILTER regex(?title,"SPARQL")
}
Query Result:
title |
---|
“SPARQL Tutorial” |
其中FILTER regex内的为正则表达式。
Data:
@prefix dc: .
@prefix : .
@prefic ns: .
:book1 dc:title "SPARQL Tutorial" .
:book1 ns:price 42 .
:book2 dc:title "The Semantic Web" .
:book2 ns:price 23 .
Query:
PREFIX dc:
PREFIX ns:
SELECT ?title ?price
WHERE {
?x ns:price ?price .
FILTER (?price < 30.5)
?x dc:title ?title .
}
Query Result:
title | price |
---|---|
“The Semantic Web” | 23 |
Tips:通过约束变量,只有第二本书与之匹配。达到过滤的要求,其实FILTER可以放在?title . 的下面.
如果SPARQL中三元组查询模式共享一个宾语,那么可以用 逗号“,”来进行表示
?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_" .
在SPARQL查询字符串中,组图模式使用大括号进行分隔:{}。 例如,此查询的查询模式是一个基本图形模式的组图模式。
PREFIX foaf:
SELECT ?name ?mbox
WHERE {
?x foaf:name ?name .
?x foaf:mbox ?mbox .
}
从将三重模式分组为两个基本图形模式的查询中可以获得相同的解决方案。 例如,下面的查询具有不同的结构,但会产生与上一个查询相同的解决方案:
PREFIX foaf:
SELECT ?name ?mbox
WHERE {{?x foaf:name ?name .}
{?x foaf:mbox ?mbox .}
}
OPTIONAL为考虑的限制关系,用于加入一个即使没有绑定任何关系,也不会过滤掉该元素。有点类似关系里的或。
Data:
@prefix foaf: .
@prefix rdf: .
_:a rdf:type foaf:Person .
_:a foaf:name "Alice" .
_:a foaf:mbox .
_:a foaf:mbox .
_:b rdf:type foaf:Person .
_:b foaf:name "Bob" .
Query:
PREFIX foaf:
SELECT ?name ?mbox
WHERE {
?x foaf:name ?name .
OPTIONAL {?x foaf:mbox ?mbox}
}
Query Result:
name | |
---|---|
“Alice” | mailto:[email protected] |
“Alice” | mailto:[email protected] |
“Bob” |
即使OPTIONAL中限制得由mbox的值的元素,在Bob中没有mbox,那么也会输出该数据。
Data:
@prefix dc: .
@prefix : .
@prefic ns: .
:book1 dc:title "SPARQL Tutorial" .
:book1 ns:price 42 .
:book2 dc:title "The Semantic Web" .
:book2 ns:price 23 .
Query:
PREFIX dc:
PREFIX ns:
SELECT ?title ?price
WHERE {
?x dc:title ?title .
OPTIONAL{ ?x ns:price ?price . FILTER (?price < 30)}
}
Query Result:
title | price |
---|---|
“SPARQL Tutorial” | |
“The Semantic Web” | 23 |
Tip:由查询结果我们可以发现,通过option对price的值进行限制,如果不满足那么在该列输出空内容,但保留内容为空的该元素的其他内容。
下面的例子将阐述有两个OPTION内容这样会输出多个可选模型的查询内容:
Data:
@prefix foaf: .
_:a foaf:name "Alice"
_:a foaf:homepage .
_:b foaf:name "Bob" .
_:b foaf:mbox .
Query:
PREFIX foaf: .
SELECT ?name ?mbox ?hpage
WHERE {
?x foaf:name ?name .
OPTIONAL {?x foaf:mbox ?mbox} .
OPTIONAL {?x foaf:homepage ?hpage}
}
Query Result:
name | mbox | hpage |
---|---|---|
“Alice” | http://work.example.org/alice/ | |
“Bob” | mailto:[email protected] |
SPARQL上采用UNION关键字来实现多种图形模式的组合 如果只输出一列的化,它会将两个模式串联排列起来。
Data:
@prefix dc10: .
@prefix dc11: .
_:a dc10:title "SPARQL Query Language Tutorial" .
_:a dc10:creator "Alice" .
_:b dcll:title "SPARQL Protocol Tutorial" .
_:b dc11:creator "Bob" .
_:c dc10:title "SPARQL" .
_:c dc11:title "SPARQL (updated)" .
Query:
PREFIX dc10: .
PREFIX dc11: .
SELECT ?title
WHERE {
{?book dc10:title ?title} UNION { ?book dc11:title ?title }
}
Query Result:
title |
---|
“SPARQL Protocol Tutorial” |
“SPARQL” |
“SPARQL (updated)” |
“SPARQL Query Language Tutorial” |
当将查询结果两列显示的话则会正常显示:
PREFIX dc10: .
PREFIX dc11: .
SELECT ?x ?y
WHERE {
{ ?book dc10:title ?x } UNION { ?book dc11:title ?y }
}
Query Result:
x | y |
---|---|
“SPARQL (updated)” | |
“SPARQL Protocol Tutorial” | |
“SPARQL” | |
“SPARQL Query Language Tutorial” |
在SPARQL中FILTER过滤器中采用(NOT EXISTS和EXISTS)来实现全面的过滤效果
NOT EXISTS 表示筛选出查找得目标与数据集不匹配的项,并且给出查询的数据值,例如:
Data:
@prefix : .
@prefix rdf: .
@prefix foaf: .
:alice rdf:type foaf:Person .
:alice foaf:name "Alice" .
:bob rdf:type foaf:Person .
Query:
PREFIX rdf:
PREFIX foaf:
SELECT ?person
WHERE
{
?person rdf:type foaf:Person .
FILTER NOT EXISTS {?person foaf:name ?name}
}
Query Result:
person |
---|
http://example/bob |
这里就输出匹配不上的项,bob在RDF图中没有相关name数据,相反EXISTS就会输出 匹配到的项。
Query:
PREFIX rdf:
PREFIX foaf:
SELECT ?person
WHERE
{
?person rdf:type foaf:Person .
FILTER EXISTS {?person foaf:name ?name}
}
Query Result:
person |
---|
http://example/alice |
这时EXISTS就会找出匹配到的项。
SPARQL中另一种否定过滤筛选是另一种否定类型“MINUS”关键字,它对两个参数进行评估,删选出不满足与目标相匹配相的结果。例如:
Data:
@prefix : .
@prefix foaf: .
:alice foaf:givenName "Alice" ;
foaf:familyName "Smith" .
:bob foaf:givenName "Bob" ;
foaf:familyName "Jones" .
:carol foaf:givenName "Carol" ;
foaf:familyName "Smith" .
Query:
PREFIX :
PREFIX foaf:
SELECT DISTINCT ?s
WHERE {
?s ?p ?o .
MINUS {
?s foaf:givenName "Bob" .
}
}
Query Result:
s |
---|
http://example/carol |
http://example/alice |
由查询结果可以看出,我们删选出不是BOB名的目标,distinct的目的是使重复的两个数据也只输出一个数据。
MINUS不会在自己语句中去与外界变量进行匹配,但NOT EXISTS会自行将语句中的变量与语句外的变量进行匹配操作。
例如对于一个DATA集里的空标识数据:
Data:
@prefix : .
:a :b :c .
Query:
SELECT *
{
?s ?p ?o
FILTER NOT EXISTS { ?x ?y ?z}
}
在查询语句中NOT EXISTS会将?x与?s进行匹配,这样查询的逻辑为查询其不存在的东西,逻辑上是矛盾的,所以查询结果为空。
而MINUS则不会进行匹配,所以MINUS内的变量不指代数据集中的变量,所以MINUS内的变量存不存在对查询结果无影响。
Query:
SELECT *
{
?s ?p ?o
MINUS
{ ?x ?y ?z }
}
Query Result:
s | p | o |
---|---|---|
http://example/a | http://example/b | http://example/c |
另外在MINUS与NOT EXISTS,关于这个变量的作用域的还有个明显的区别。我们通过以下这个例子来看:
Data:
@prefix : .
:a :p 1 .
:a :q 1 .
:a :q 2 .
:b :p 3.0 .
:b :q 4.0 .
:b :q 5.0 .
以上是我们例子中的数据集,由两个主语a和b。现在我们用NOT EXISTS来进行过滤:
Query:
PREFIX :
SELECT * WHERE {
?x :p ?n
FILTER NOT EXISTS {
?x :q ?m .
FILTER(?n = ?m)
}
}
Queru Result:
x | n |
---|---|
http://example.com/b | 3.0 |
查询结果很明显的现实,NOT EXISTS中?n作用域明显与FILETER上一行的?n对应,所以能正确过滤出q与p值不一样的数据。
Data:
PREFIX :
SELECT * WHERE {
?x :p ?n
MINUS {
?x :q ?m .
FILTER( ?n = ?m )
}
}
Query Result:
x | n |
---|---|
http://example.com/b | 3.0 |
http://example.com/a | 1 |
而在MINUS里面其?n并未绑定,在这里面MINUS与MINUS上一行的?n并不一样,所以在此MINUS里 ?m是与一个随机的数进行的匹配。
所以最后过滤的思路是,输出与?n不相同的主语;而由于?n是随机的,所以a 和b都不与之相等。
在SPARQL里提供了循环查询方式 通过 “/”来实现的循环操作:
Query:
{
?x foaf:mbox .
?x foaf:knows/foaf:knows/foaf:name ?name .
}
等同于
SELECT ?x ?name
{
?x foaf:mbox .
?x foaf:knows [ foaf:knows [ foaf:name ?name ]].
}
再换成我们看的懂的查询语句就是:
SELECT ?x ?name
{
?x foaf:mbox .
?x foaf:knows ?a1 .
?a1 foaf:knows ?a2 .
?a2 foaf:knows ?name /
}
我们来举个例子说明一下这个循环查询,原始数据为:
Data:
@prefix : .
:order :item :z1 .
:order :item :z2 .
:z1 :name "Small" .
:z1 :price 5 .
:z2 :name "Large" .
:z2 :price 5 .
我们用/来实现的循环查询操作:
Query:
PREFIX :
SELECT *
{ ?s :item/:price ?x .}
Query Result:
s | x |
---|---|
http://example/order | 5 |
http://example/order | 5 |
这样的查询语句类似于:
PREFIX :
SELECT *
{ ?s :item ?a .
?a :price ?x .}
s | _a | x |
---|---|---|
http://example/order | http://example/z1 | 5 |
http://example/order | http://example/z2 | 5 |
现查询主语的标签,再根据标签去查询对应的价格最后输出。
这样的循环操作 有这样一个例子可以来展示其循环效果,就是查询到有标签和价格同时存在的价格之和:
Query:
PREFIX :
SELECT (sum(?x) AS ?total)
{
:order :item/:price ?x
}
Query Result:
total |
---|
10 |
用BIND,可以将查询语句内的变量在BIND中进行数学运算并将运算的结果分配给变量,但是这样新引入的变量不能重新作为查询变量来用,不过可以作为限制条件来采用。
Data:
@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 .
Query:
PREFIX dc:
PREFIX ns:
SELECT ?title ?price
{
{
?x ns:price ?p .
?x ns:discount ?discount .
BIND (?p*(1-?discount) AS ?price)
}
{?x dc:title ?title . }
FILTER(?price <20)
}
Query Result:
title | price |
---|---|
The Semantic Web" | 17.25 |
该语句的目的即为通过BIND方式来实现利润运算,通过收入减去支持百分百得到的利润price。
GROUP BY可以通过根据一个或多个表达式对查询的解决方案进行分组;
HAVING必须要配套GOURP BY来使用(在与GROUP BY中类似FILETER的作用)进行过滤。
下面一个例子将展示有若干本书,每本书都有作者,链接域名,和每本书的价格。我们通过GROUP BY以域名的方式进行分组,并计算每组下面的总价格:
Data:
@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 .
Query:
PREFIX :
SELECT (SUM(?lprice) AS ?totalPrice)
WHERE {
?org :affiliates ?auth .
?auth :writesBook ?book .
?book :price ?lprice .
}
GROUP BY ?org
HAVING (SUM(?lprice) > 10)
Query Result:
totalPrice |
---|
21 |
再举一个例子如果想对数据集中( {?x→2, ?y→3}, {?x→2, ?y→5}, {?x→6, ?y→7} )我们对x相同值得进行分组,并求出每组得y的平均值,我们可以采用以下方式:
Query:
SELECT (AVG(?y) AS ?avg)
WHERE {
?a :x ?x ;
:y ?y .
}
GROUP BY ?x
子查询是在其他查询中内嵌SPARQL查询的一种方式,通常用于实现无法实现的结果,例如在限制的查询结果中查询出某些子图的信息。例如:
Query:
PREFIX :
SELECT ?y ?minName
WHERE {
:alice :knows ?y .
{
SELECT ?y (MIN(?name) AS ?minName)
WHERE {
?y :name ?name .
} GROUP BY ?y
}
}
Query Result:
y | minName |
---|---|
:bob | “B.Bar” |
:carol | “C.Baz” |