【问题标题】:Finding all steps in property path查找属性路径中的所有步骤
【发布时间】:2013-08-02 19:07:23
【问题描述】:

我是 SPARQL 的新手,我正在尝试创建一个属性路径查询,该查询将沿路径输出每个中间步骤。到目前为止,我有这个:

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

这给了我一个在整个路径中与我的主题 URI 的所有关系的列表,无论这种关系有多远(如果到目前为止我错了,请纠正我)。

但是,我想看看这些关系是如何组织的。比如:

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

等等……这可能吗?

【问题讨论】:

  • 刚刚看到这个通知,抱歉!除了下面的 cmets 之外,我没有取得任何进展。该项目目前处于搁置状态,但我希望尽快恢复!

标签: rdf sparql


【解决方案1】:

虽然属性路径中有 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)

并保证按顺序获得优势。

【讨论】:

  • 感谢您的回复。您的建议在一定程度上有效,但是当我添加了多个步骤时,查询什么也没有响应。根据此查询:select ?x (COUNT(?z) AS ?linkTotal) where { ?x:relatedTo+ ?z . } group by ?x HAVING (COUNT(?x) &gt; 1) 我得到的最大值为 12。这是否意味着最长的最短路径是 12 步,因此我应该能够在您的查询中添加 12(错误,10?)中间步骤仍然得到一个匹配的案例?
  • @user2350906 没有看到您的数据,很难判断查询将返回什么。不过我确实注意到,您使用的是+,我在任何查询中都没有使用它。 + 表示一个或多个,而 * 表示 0 个或多个。
  • @user2350906 你能再详细说明一下吗? + 之间的区别很大,如果您按 ?x 分组,那么 HAVING 子句应该是 HAVING (COUNT(?z) &gt; 1) 而不是 HAVING COUNT(?x) &gt; 1)(即计数 ?z,而不是 ?y)?
  • @JoshuaTaylor 感谢您的出色回答。我有一个与此类似的问题。就我而言,两个节点之间有多个路径。我想获取从开始到结束节点的所有路径。请帮忙。
  • @DixitSingla 我不确定您是否可以在 SPARQL 中方便地做到这一点。您可以获得两个节点之间所有路径的所有 ,但之后您仍然需要提取单个 paths
【解决方案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
}

尽管您可以立即看到这使事情变得非常冗长。

【讨论】:

  • 谢谢!我想我记得读过这个限制。解决方案很冗长,但可能不如尝试在查询后重建跃点。
  • @user2350906 虽然您可以对属性路径执行的操作有一些限制,但我认为您可以从使用属性路径的查询中获取您正在寻找的信息,我已经描述了它在an answer
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-21
  • 1970-01-01
  • 2017-08-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多