跳轉到內容

SPARQL/屬性路徑

來自華夏公益教科書

屬性路徑

[編輯 | 編輯原始碼]

三元組儲存中的語句在三元組中具有特定的屬性。在SPARQL查詢中,您也可以在三元組中寫下屬性路徑。

屬性路徑是用來描述兩個專案之間屬性路徑的簡寫。最簡單的路徑只是一個單獨的屬性,它形成一個普通的三元組。

?item wdt:P31 ?class.

您可以使用正斜槓(/)新增路徑元素。

?item wdt:P31/wdt:P279/wdt:P279 ?class.

這等效於以下任一內容

?item wdt:P31 ?temp1.
?temp1 wdt:P279 ?temp2.
?temp2 wdt:P279 ?class.
?item wdt:P31 [ wdt:P279 [ wdt:P279 ?class ] ].

練習:(重新)編寫“巴赫的孫子”查詢以使用此語法。

路徑元素後面的星號(*)表示“零個或多個此元素”。

?item wdt:P31/wdt:P279* ?class.
# means:
?item wdt:P31 ?class
# or
?item wdt:P31/wdt:P279 ?class
# or
?item wdt:P31/wdt:P279/wdt:P279 ?class
# or
?item wdt:P31/wdt:P279/wdt:P279/wdt:P279 ?class
# or ...

如果路徑中沒有其他元素,則?a something* ?b表示?b也可能只是?a,它們之間根本沒有路徑元素。

加號(+)類似於星號,但表示“一個或多個此元素”。以下查詢找到巴赫的所有後代

SELECT ?descendant ?descendantLabel
WHERE
{
  wd:Q1339 wdt:P40+ ?descendant.
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}

試試看!

如果我們在這裡使用星號而不是加號,查詢結果將包括巴赫本人。

問號(?)類似於星號或加號,但表示“零個或一個此元素”。

您可以使用豎線(|)而不是正斜槓來分隔路徑元素;這意味著“或”:路徑可能使用這兩個屬性中的任何一個。(但不是兩者都使用 - “或”路徑段始終匹配長度為一的路徑。)

您也可以使用括號(())將路徑元素分組,並自由組合所有這些語法元素(/|*+?)。這意味著,找到巴赫所有後代的另一種方法是

SELECT ?descendant ?descendantLabel
WHERE
{
  ?descendant (wdt:P22|wdt:P25)+ wd:Q1339.
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}

試試看!

我們不是使用“孩子”屬性從巴赫到他的後代,而是使用“父親”和“母親”屬性從後代到巴赫。路徑可能包括兩個母親和一個父親,或者四個父親,或者父親-母親-母親-父親,或者任何其他組合。(當然,巴赫不可能是某人的母親,所以最後一個元素總是父親。)

路徑元素後面的程式碼總結

程式碼 含義
? (問號) 零個或一個此元素
* (星號) 零個或多個此元素
+ (加號) 一個或多個此元素
[編輯 | 編輯原始碼]

除了正常的三元組“主體、謂語、賓語”之外,還可以將其寫成逆向連結“賓語、謂語、主體”。這可以透過在謂語前面新增^來實現。對於普通三元組來說,這並不是很有用,但對於屬性路徑來說,它可以避免使用虛擬變數。

例如,此查詢透過查詢具有相同父親的兄弟姐妹來找到約翰·塞巴斯蒂安·巴赫的兄弟姐妹。

SELECT ?sibling ?siblingLabel
WHERE
{
  # Bach   father/has father sibling
  wd:Q1339 wdt:P22/^wdt:P22 ?sibling. # ^ = Inverse link
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}

試試看!

使用虛擬變數,可以寫成

SELECT ?sibling ?siblingLabel
WHERE
{
  # Bach   father/has father sibling
  wd:Q1339 wdt:P22 ?dummy.
  ?dummy ^wdt:P22 ?sibling. # ^ = Inverse link
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}

試試看!

或者沒有逆向連結

SELECT ?sibling ?siblingLabel
WHERE
{
  # Bach   father/has father sibling
  wd:Q1339 wdt:P22 ?dummy.
  ?sibling wdt:P22 ?dummy.
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}

試試看!

程式碼 含義
^ (插入符) 逆向連結

例項和類

[編輯 | 編輯原始碼]

大多數維基資料屬性是“有”關係:孩子,父親,職業。但有時(實際上,經常),您還需要談論某事物是什麼。但實際上,那裡存在兩種關係

  • 《亂世佳人》一部電影。
  • 一部電影一件藝術作品。

《亂世佳人》是一部特定的電影。它有一個特定的導演(維克多·弗萊明),一個特定的時長(238分鐘),一個演員名單(克拉克·蓋博、費雯·麗……),等等。

電影是一個普遍的概念。電影可以有導演、時長和演員陣容,但“電影”本身並沒有特定的導演、時長或演員陣容。雖然電影一件藝術作品,藝術作品通常有創作者,但“電影”本身沒有創作者——只有這個概念的特定例項有。

這種差異就是維基資料中存在兩個“是”屬性的原因:P31P279《亂世佳人》是“電影”類的一個特定例項;“電影”類是更一般類“藝術作品”的子類(更具體的類;專門化)。

那麼,當我們編寫SPARQL查詢時,這意味著什麼呢?當我們要搜尋“所有藝術作品”時,僅僅搜尋所有直接屬於“藝術作品”的專案是不夠的

SELECT ?work ?workLabel
WHERE
{
  ?work wdt:P31 wd:Q838948. # instance of work of art
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}

試試看!

當我寫這篇文章的時候,這個查詢只返回了2815個結果——很明顯,藝術作品不止這些!問題是,這錯過了像《亂世佳人》這樣的專案,它僅僅是“電影”的例項,而不是“藝術作品”的例項。“電影”是“藝術作品”的子類,但我們需要告訴SPARQL在搜尋時要考慮到這一點。

對此的一個可能的解決方案是我們討論過的[]語法:《亂世佳人》是“藝術作品”的某個子類的例項。(作為練習,嘗試編寫這個查詢!)但這仍然存在問題

  1. 我們不再包含直接屬於藝術作品的專案。
  2. 我們仍然錯過了“藝術作品”的某個子類的某個其他子類的例項——例如,《白雪公主和七個小矮人》是一部動畫電影,動畫電影是一部電影,電影是一件藝術作品。在這種情況下,我們需要遵循兩個“子類”語句——但它也可能是三個、四個、五個,實際上可能是任何數量。

解決方案:?item wdt:P31/wdt:P279* ?class。這意味著,在專案和類之間有一個“例項”和任何數量的“子類”語句。

SELECT ?work ?workLabel
WHERE
{
  ?work wdt:P31/wdt:P279* wd:Q838948. # instance of any subclass of work of art
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
LIMIT 1000

試試看!

我不建議對所有藝術作品執行這個查詢。WDQS 可以處理它(勉強),但您的瀏覽器在嘗試顯示結果時可能會崩潰,因為結果太多了。出於這個原因,插入了LIMIT 1000

現在您知道如何搜尋所有藝術作品、所有建築或所有人類住區:神奇咒語wdt:P31/wdt:P279*,以及相應的類。這使用了更多我尚未解釋過的SPARQL功能,但坦率地說,這幾乎是這些功能的唯一相關用途,因此您不需要瞭解它是如何工作的,就可以有效地使用WDQS。

參考文獻

[編輯 | 編輯原始碼]


華夏公益教科書