跳转到内容

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 ].

参考文献

[编辑 | 编辑源代码]


华夏公益教科书