SPARQL/语句
在基础章节中,我们已经看到了约翰·塞巴斯蒂安·巴赫的所有孩子——更具体地说,所有拥有约翰·塞巴斯蒂安·巴赫作为父亲的项目。但是巴赫有两任妻子,所以这些项目有两个不同的母亲:如果我们只想看到约翰·塞巴斯蒂安·巴赫和他的第一任妻子玛丽亚·芭芭拉·巴赫 (Q57487)的孩子呢?尝试根据上面的查询编写那个查询。
做完了吗?好的,那么进入解决方案!最简单的方法是添加一个包含该限制的第二个三元组
SELECT ?child ?childLabel
WHERE
{
?child wdt:P22 wd:Q1339.
?child wdt:P25 wd:Q57487.
SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
用英语来说,这句话是
孩子有父亲约翰·塞巴斯蒂安·巴赫。孩子有母亲玛丽亚·芭芭拉·巴赫。
这听起来有点笨拙,不是吗?在自然语言中,我们会缩写成
孩子有父亲约翰·塞巴斯蒂安·巴赫和母亲玛丽亚·芭芭拉·巴赫。
事实上,在 SPARQL 中也可以表达相同的缩写:如果用分号 (;
) 而不是句号结束三元组,则可以添加另一个谓词-宾语对。这让我们能够将上面的查询缩写为
SELECT ?child ?childLabel
WHERE
{
?child wdt:P22 wd:Q1339;
wdt:P25 wd:Q57487.
SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
它具有相同的结果,但在查询中重复的次数更少。
现在假设,在这些结果中,我们只对那些也是作曲家和钢琴家的孩子感兴趣。相关的属性和项目是职业 (P106)、作曲家 (Q36834) 和 钢琴家 (Q486748)。尝试更新上面的查询以添加这些限制!
这是我的解决方案
SELECT ?child ?childLabel
WHERE
{
?child wdt:P22 wd:Q1339;
wdt:P25 wd:Q57487;
wdt:P106 wd:Q36834;
wdt:P106 wd:Q486748.
SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
这使用 ;
缩写两次来添加两个必需的职业。但是,你可能会注意到,仍然存在一些重复。这就像我们在说
孩子有职业作曲家和职业钢琴家。
我们通常会缩写成
孩子有职业作曲家和钢琴家。
SPARQL 也有一些语法可以实现这一点:就像 ;
允许你在三元组(重新使用主题)中添加谓词-宾语对一样,,
允许你在三元组(重新使用主题和谓词)中添加另一个宾语。有了这个,查询可以缩写为
SELECT ?child ?childLabel
WHERE
{
?child wdt:P22 wd:Q1339;
wdt:P25 wd:Q57487;
wdt:P106 wd:Q36834,
wd:Q486748.
SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
注意:缩进和其他空白实际上并不重要——我只是缩进了查询以使其更具可读性。你也可以这样写
SELECT ?child ?childLabel
WHERE
{
?child wdt:P22 wd:Q1339;
wdt:P25 wd:Q57487;
wdt:P106 wd:Q36834, wd:Q486748.
# both occupations in one line
SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
或者,更不具可读性的
SELECT ?child ?childLabel
WHERE
{
?child wdt:P22 wd:Q1339;
wdt:P25 wd:Q57487;
wdt:P106 wd:Q36834,
wd:Q486748.
# no indentation; makes it hard to distinguish between ; and ,
SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
幸运的是,WDQS 编辑器会自动缩进行,因此你通常不必担心这个问题。
好了,让我们在这里总结一下。我们已经看到查询的结构类似于文本。关于主题的每个三元组都以句号结束。关于同一主题的多个谓词由分号隔开,而同一主题和谓词的多个宾语可以列出并用逗号隔开。
SELECT ?s1 ?s2 ?s3
WHERE
{
?s1 p1 o1;
p2 o2;
p3 o31, o32, o33.
?s2 p4 o41, o42.
?s3 p5 o5;
p6 o6.
}
现在我想介绍 SPARQL 提供的另一种缩写。所以,如果你愿意,让我们再进行一个假设场景……
假设我们实际上对巴赫的孩子不感兴趣。(谁知道呢,也许对你来说确实如此!)但我们对他的孙子感兴趣。(假设)。这里有一个复杂之处:孙子可以通过母亲或父亲与巴赫相关联。那是两种不同的属性,这很不方便。相反,让我们反转关系:维基数据也拥有“孩子”属性,孩子 (P40),它从父母指向孩子,并且与性别无关。有了这些信息,你能编写一个返回巴赫孙子的查询吗?
这是我的解决方案
SELECT ?grandChild ?grandChildLabel
WHERE
{
wd:Q1339 wdt:P40 ?child.
?child wdt:P40 ?grandChild.
SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
用自然语言来说,这句话是
巴赫有一个孩子
?child
。?child
有一个孩子?grandChild
。
我再次建议我们缩写这个英语句子,然后我想向你展示 SPARQL 如何支持类似的缩写。注意,我们实际上并不关心孩子:我们不使用该变量,除了谈论孙子。因此,我们可以将句子缩写为
巴赫有一个孩子,这个孩子有一个孩子
?grandChild
。
我们没有说出巴赫的孩子是谁,只是说“某人”:我们并不关心是谁。但是我们可以参考他们,因为我们已经说了“某人谁”:这开始了关系从句,在这个关系从句中,我们可以说关于“某人”的事情(例如,他或她“有一个孩子 ?grandChild
”。在某种程度上,“某人”是一个变量,但它是一个特殊的变量,它只在关系从句中有效,并且我们没有明确引用它(我们说“某人是谁并做了什么”,而不是“某人是谁,某人做了什么”——那是两个不同的“某人”)。
在 SPARQL 中,可以写成
SELECT ?grandChild ?grandChildLabel
WHERE
{
wd:Q1339 wdt:P40 [ wdt:P40 ?grandChild ].
SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
你可以用一对括号 ([]
) 来代替变量,它充当匿名变量。在括号内,你可以指定谓词-宾语对,就像在正常三元组的 ;
之后一样;隐式主题在这种情况下是括号表示的匿名变量。(注意:就像在 ;
之后一样,你也可以使用更多分号添加更多谓词-宾语对,或者使用逗号添加相同谓词的更多宾语。)
这就是三元组模式!SPARQL 还有更多内容,但当我们即将离开与自然语言密切相关的部分时,
我想再次总结一下这种关系
自然语言 | 示例 | SPARQL | 示例 |
---|---|---|---|
句子 | 朱丽叶 爱 罗密欧. | 句号 | juliet loves romeo.
|
连词(从句) | 罗密欧 爱 朱丽叶 并且 杀死 自己. | 分号 | romeo loves juliet; kills romeo.
|
连词(名词) | 罗密欧 杀死 提伯尔特 并且 自己. | 逗号 | romeo kills tybalt, romeo.
|
关系从句 | 朱丽叶 爱 某人谁 杀死 提伯尔特. | 方括号 | juliet loves [ kills tybalt ].
|