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