2013-08-02 36 views
5

我是新來的SPARQL,我試圖創建一個屬性路徑查詢,它將沿着路徑中的每個中間步驟吐出。到目前爲止,我有這樣的:查找屬性路徑中的所有步驟

select ?object 
where { 
    <subjectURI> <isRelatedTo>+ ?object . 
} 

這給了我所有的關係到我的主題整個URI路徑列表,無論多麼遙遠的關係(糾正我,如果我錯了,至今)。

但是,我想看看關係是如何組織的。例如:

<subjectURI> <isRelatedTo> <object1> 
<object1> <isRelatedTo> <object2> 
<object2> <isRelatedTo> <object3> 

等等......這可能嗎?

+0

剛剛看到通知,對不起!除了下面的評論,我沒有取得任何進展。該項目目前暫停,但我希望很快回來! – bdkauff

回答

2

不,這是屬性路徑設計的限制。

路徑可用於壓縮更復雜的查詢模式,也可用於測試任意長度的路徑,如示例中所示。

前者可以轉換爲一種形式,爲您提供中間步驟,例如

SELECT * WHERE 
{ 
    ?s <http://predicate>/<http://predicate> ?o 
} 

可以轉換爲下面:

SELECT * WHERE 
{ 
    ?s <http://predicate> ?intermediate . 
    ?intermediate <http://predicate> ?o . 
} 

不幸的是,同樣不能對任意長度的路徑來進行。但是,如果你知道在路徑的上限是你可以重寫查詢,如下所示:

SELECT * 
WHERE 
{ 
    { 
    ?s <http://predicate> ?step1 . 
    ?step1 <http://predicate> ?o . 
    } 
    UNION 
    { 
    ?s <http://predicate> ?step1 . 
    ?step1 <http://predicate> ?step2 . 
    ?step2 <http://predicate> ?o . 
    } 
    # Add additional UNION for each length of path you want up to your upper bound 
} 

雖然你可以馬上看到這使事情變得非常冗長。

+0

謝謝!我想我回想一下這個限制。該解決方案是冗長的,但可能不如嘗試重建跳躍後查詢。 – bdkauff

+1

@ user2350906儘管可以使用屬性路徑做什麼有一些限制,但我認爲您可以從使用屬性路徑的查詢中獲取您要查找的信息,並且我已在[答案]( http://stackoverflow.com/a/18032019/1281433)。 –

4

雖然有some limitations屬性路徑可以做,根據您的具體要求,你可能能夠得到你需要的東西在這裏。考慮一下這個數據:

@prefix : <urn:ex:>. 

:a :relatedTo :b . 
:b :relatedTo :c . 
:c :relatedTo :d . 

:a :relatedTo :e . 
:e :relatedTo :f . 
:f :relatedTo :g . 

:h :relatedTo :i . 
:i :relatedTo :j . 
:j :relatedTo :k . 
:k :relatedTo :l . 

其中有三個:relatedTo路徑:

a --> b --> c --> d 
a --> e --> f --> g 
h --> i --> j --> k --> l 

我知道你的情況,你有一個特定的主題,但我們可以概括一點點,並要求在每個這些路徑的每個邊緣與這樣的查詢:

prefix : <urn:ex:> 
select * where { 
    # start a path 
    ?begin :relatedTo* ?midI . 
    FILTER NOT EXISTS { [] :relatedTo ?begin } 

    # grab next edge 
    ?midI :relatedTo ?midJ . 

    # get to the end of the path. 
    ?midJ :relatedTo* ?end . 
    FILTER NOT EXISTS { ?end :relatedTo [] } 
} 
order by ?start ?end 

$ arq --data data.n3 --query query.sparql 
----------------------------- 
| begin | midI | midJ | end | 
============================= 
| :a | :a | :b | :d | 
| :a | :b | :c | :d | 
| :a | :c | :d | :d | 
| :a | :a | :e | :g | 
| :a | :e | :f | :g | 
| :a | :f | :g | :g | 
| :h | :h | :i | :l | 
| :h | :i | :j | :l | 
| :h | :j | :k | :l | 
| :h | :k | :l | :l | 
----------------------------- 

它顯示每個:relatedTo路徑的每個邊緣。你可以使輸出有點漂亮,太:

prefix : <urn:ex:> 
select (concat(str(?begin),"--",str(?end)) as ?path) ?midI ?midJ where { 
    # start a path 
    ?begin :relatedTo* ?midI . 
    FILTER NOT EXISTS { [] :relatedTo ?begin } 

    # grab next edge 
    ?midI :relatedTo ?midJ . 

    # get to the end of the path. 
    ?midJ :relatedTo* ?end . 
    FILTER NOT EXISTS { ?end :relatedTo [] } 
} 
order by ?path 

$ arq --data data.n3 --query query.sparql 
-------------------------------------- 
| path     | midI | midJ | 
====================================== 
| "urn:ex:a--urn:ex:d" | :a | :b | 
| "urn:ex:a--urn:ex:d" | :b | :c | 
| "urn:ex:a--urn:ex:d" | :c | :d | 
| "urn:ex:a--urn:ex:g" | :a | :e | 
| "urn:ex:a--urn:ex:g" | :e | :f | 
| "urn:ex:a--urn:ex:g" | :f | :g | 
| "urn:ex:h--urn:ex:l" | :h | :i | 
| "urn:ex:h--urn:ex:l" | :i | :j | 
| "urn:ex:h--urn:ex:l" | :j | :k | 
| "urn:ex:h--urn:ex:l" | :k | :l | 
-------------------------------------- 

同樣的方法將讓你做一些有趣的事情就像找到了相隔較遠某些節點如何:

prefix : <urn:ex:> 
select ?begin ?end (count(*) as ?length) where { 
    # start a path 
    ?begin :relatedTo* ?midI . 
    FILTER NOT EXISTS { [] :relatedTo ?begin } 

    # grab next edge 
    ?midI :relatedTo ?midJ . 

    # get to the end of the path. 
    ?midJ :relatedTo* ?end . 
    FILTER NOT EXISTS { ?end :relatedTo [] } 
} 
group by ?begin ?end 

------------------------ 
| begin | end | length | 
======================== 
| :a | :g | 3  | 
| :a | :d | 3  | 
| :h | :l | 4  | 
------------------------ 

在上面提供的數據中,路徑碰巧按字母順序排列,因此排序會按正確的順序生成邊。但是,即使邊緣節點不是按字母順序排列,我們仍然可以通過計算它們在列表中的位置來按順序打印它們。這個查詢:

prefix : <urn:ex:> 
select ?begin ?midI ?midJ (count(?counter) as ?position) ?end where { 
    ?begin :relatedTo* ?counter . 
    ?counter :relatedTo* ?midI . 
    FILTER NOT EXISTS { [] :relatedTo ?begin } 

    ?midI :relatedTo ?midJ . 

    ?midJ :relatedTo* ?end . 
    FILTER NOT EXISTS { ?end :relatedTo [] } 
} 
group by ?begin ?end ?midI ?midJ 

---------------------------------- 
| begin | midI | midJ | .1 | end | 
================================== 
| :a | :a | :b | 1 | :d | 
| :a | :b | :c | 2 | :d | 
| :a | :c | :d | 3 | :d | 
| :a | :a | :e | 1 | :g | 
| :a | :e | :f | 2 | :g | 
| :a | :f | :g | 3 | :g | 
| :h | :h | :i | 1 | :l | 
| :h | :i | :j | 2 | :l | 
| :h | :j | :k | 3 | :l | 
| :h | :k | :l | 4 | :l | 
---------------------------------- 

我們沒有必要需要看到表示,計數,但你可以,而不是選擇的位置,你可以用它作爲排序條件:

prefix : <urn:ex:> 
select ?begin ?midI ?midJ ?end 
where { 
    ?begin :relatedTo* ?counter . 
    ?counter :relatedTo* ?midI . 
    FILTER NOT EXISTS { [] :relatedTo ?begin } 

    ?midI :relatedTo ?midJ . 

    ?midJ :relatedTo* ?end . 
    FILTER NOT EXISTS { ?end :relatedTo [] } 
} 
group by ?begin ?end ?midI ?midJ 
order by ?begin ?end count(?counter) 

並保證讓你的邊緣順序。

+0

謝謝你的迴應。你提出的建議可以達到某個程度,但是當我添加了幾個步驟時,查詢就沒有任何反應。根據這個查詢: 'select?x(COUNT(?z)AS?linkTotal) 其中{0}:relatedTo +?z。 } 組由?X HAVING(讀數(X)> 1)' 我得到12的最大值,這是否意味着最長的最短路徑是12步,所以我應該能夠爲你的查詢添加12個(err,10?)中間步驟,仍然得到一個匹配的案例? – bdkauff

+0

@ user2350906沒有看到您的數據,很難說出查詢將返回什麼。但我注意到,你正在使用'+',而這在我的任何查詢中都沒有使用。 「+」表示一個或多個,而「*」是0或更多。 –

+0

@ user2350906你能詳細解釋一下嗎? '+'之間的區別很明顯,如果你用'?x'分組,那麼'HAVING'子句應該是'HAVING(COUNT(?z)> 1)'而不是'HAVING COUNT(?x)> 1)'(即計數'?z',而不是'?y')? –