如何返回实体id的联合

时间:2014-01-14 14:24:14

标签: sparql

考虑列出人员(父母)及其职位(儿童)。

请注意,我已经简化了示例,但它可能是parent-child-childofChild-etc,因此某些实体具有子树。

我想有一个查询返回一些过滤(在某些条件下)人ID和它们的帖子ID的联合,如下所示:

person1Id
person2Id
person1Post1Id
person1Post2Id
.......

鉴于具有3人(具有房产年龄,姓名)的具体情况,其中Person1有2个帖子而其他人没有帖子我设法以2种方式做到这一点,但两者都有限制。所以在where子句中我们有:

 ?entityId ?p ?o.
 {
    #persons/posts graph pattern
 } 
 filter (?entityId =?person || ?entityId=?post) # || otherChildFitler

这有效,但使用过滤器,所以我想避免使用union:

    {
            SELECT (?person as ?s) WHERE{ #criteria}
            order by ...
            limit 1
    }
    UNION
    {
            {
                    SELECT ?person WHERE{ #criteria}
                    order by ...
                    limit 1
            }
            ?s a <http://www.example.org/schema/Post> .
            ?s  <http://www.example.org/schema/postedBy> ?person .
    }

这也有效,但我必须为每个孩子复制人物内部查询。 所以我尝试以某种方式使用bind如此: (假设内部查询返回1个有2个帖子的人。)

select ?s ?person ?projectedOutPerson

where
{
#tag 1      
        {
                #returns 1 person with 2 posts
                SELECT ?person WHERE
                { 
                        ?person a <http://www.example.org/schema/Person> .
                        optional{?person <http://www.example.org/schema/age> ?age.}
                }
                order by desc(?age)
                limit 1
        }

#tag 2    
        bind(?person as ?projectedOutPerson)
#tag 3      
        {
                bind(?projectedOutPerson as ?s)
        }
#tag 4
        UNION
        {
                ?s a <http://www.example.org/schema/Post> .
                ?s  <http://www.example.org/schema/postedBy> ?projectedOutPerson.
        }
#tag 5        

}

这会重新发布帖子ID,但不添加personIds,并且有一些奇怪的行为。

我在bigdata 1.3和stardog 2上进行测试。

  • ?如果我选择没有帖子的人没有回复帖子,那么projectionOutPerson就会被绑定(标签2-3)。

  • 在两个db中,tag3-4之间的绑定没有完成/加入所以?s没有绑定到某个人(返回空结果)。

  • 如果我删除部分标签4-5 bigdata显示选定人(所以现在绑定标签3-4工作)但stardog返回(空结果,person1,person1)所以在stardog链接绑定不起作用

    bind(?person as ?p1) #only this is bound
    bind(?p2 as ?p3)
    bind(?p3 as ?s)
    

在sparql1.1 docs中“BIND子句引入的变量不得在组图形模式中使用到BIND中的使用点。”但每次引入新变量时,我认为应该工作

那么如何在不重复子查询或使用过滤器的情况下解决这个问题。

1 个答案:

答案 0 :(得分:1)

如果提供一些数据,回答这类问题要容易得多。如果我正确理解您的问题,您会得到以下数据。我在Turtle中提供它,因为它具有相当人性化的可读性。

@prefix : <http://stackoverflow.com/q/21115947/1281433/> .

# person1 has two posts, person2 has one post, and 
# person3 has no posts at all.

:person1 a :Person ;
         :hasPost :person1post1 , :person1post2 .

:person2 a :Person ;
         :hasPost :person2post1 .

:person3 a :Person .

现在,如果您想要选择每个人及其所有帖子,您可以使用以下查询来执行此操作:

prefix : <http://stackoverflow.com/q/21115947/1281433/>

select ?id where {
  ?person a :Person ;    
          :hasPost? ?id .
}
-----------------
| id            |
=================
| :person3      |
| :person2      |
| :person2post1 |
| :person1      |
| :person1post2 |
| :person1post1 |
-----------------

这里的诀窍在于查询模式

  ?person a :Person ;    
          :hasPost? ?id .

?person a :Person确保?person是一个人。然后,模式?person :hasPost? ?id找到?id s,以便存在从?person?id的长度为零或一的路径。长度为零的情况意味着?id可以绑定到?person的相同值。长度为1的情况意味着您将获得x的所有?person :hasPost x

现在,就个人和帖子而言,谈论有其他帖子的帖子并没有多大意义(我认为),但如果你只是在树形结构中寻找后代,你可以在您的媒体资源路径中使用*代替?。例如,如果您有这些数据:

@prefix : <http://stackoverflow.com/q/21115947/1281433/> .

#      1
#     / \
#    /   \
#   2     3
#  / \   / \
# 4   5 6   7
#  \     \   \
#   8     9   10 

:node1 :hasChild :node2 , :node3 .
:node2 :hasChild :node4 , :node5 .
:node3 :hasChild :node6 , :node7 .
:node4 :hasChild :node8 .
:node6 :hasChild :node9 .
:node7 :hasChild :node10 .

您可以使用以下查询获取:node3及其所有后代:

prefix : <http://stackoverflow.com/q/21115947/1281433/>

select ?node where {
  :node3 :hasChild* ?node
}
-----------
| node    |
===========
| :node3  |
| :node7  |
| :node10 |
| :node6  |
| :node9  |
-----------