sparql 检查是否存在 属性 并将答案设为零

sparql check for existing of a property and give zero to the answer

这是我的最低数据:

@prefix : <http://example.org/rs#>

:item :hasContext [:weight 0.1 ; :doNotRecommend true] , [:weight 0.2 ] .

:anotherItem :hasContext [:weight 0.4] , [ :weight 0.5 ] .

如你所见,每个 item 都有 一个或多个 hasContext ,那个 hasContext 的对象是 可以有一个doNotRecommed谓词。

我想要的是,如果这些实例之一(它们是 hasContext 的对象)包含 donNotRecommed,我希望总和为零。 ** 总和是指权重的总和**,换句话说,如果 属性 存在,则忽略所有权重(无论是否存在),只需将零

我的查询

select ?item (SUM(?finalWeight) as ?summedFinalWeight) {
 ?item :hasContext ?context .
  optional 
  {
    ?context :doNotRecommend true .
    bind( 0 as ?cutWeight) 
  }
  optional
  {
    ?context :weight ?weight .
  } 
  bind ( if(bound(?cutWeight), ?cutWeight , if(bound(?weight), ?weight, 0.1) ) as ?finalWeight )
}
group by ?item

结果

看看 :item 的值,它是 0.2(我知道原因,这是因为 0.2 加上零(这个零是因为 doNotRecommend 在那里)但我不知道' 知道解决方案,我想要的是在 :item

的情况下为零

(提示,我知道我总是可以在此查询的上层 运行 另一个查询并解决它,或者我可以使用不存在的过滤器来解决它,但我希望以相同的方式解决它查询,因为我应该你是一个最小的数据,而在我的 ontology 中,获得那个重量和这些对象是一个很长的查询

更新 1

这是我的真实查询,第一部分(联合之前)检查用户是否确认上下文,第二部分(联合之后)检查用户是否不符合上下文 在这里我想检查该上下文是否有 doNotRecommendOrNot 。请确保两部分一起验证是很重要的

SELECT  ?item (SUM(?finalWeightFinal) AS ?userContextWeight)
WHERE
  { VALUES ?user { bo:ania }
    ?item  rdf:type  rs:RecommendableClass
    OPTIONAL
      {   { FILTER EXISTS { ?item  rdf:type  ?itemClass }
            ?item     rdf:type           rs:RecommendableClass .
            ?userContext  rdf:type       rs:UserContext ;
                      rs:appliedOnItems  ?itemClass ;
                      rs:appliedOnUsers  ?userClass
            FILTER EXISTS { ?user  rdf:type  ?userClass }
            OPTIONAL
              { ?userContext  rs:hasWeightIfContextMatched  ?weight }
            BIND(if(bound(?weight), ?weight, 0.2) AS ?finalWeight)
          }
        UNION
          { ?item     rdf:type           rs:RecommendableClass .
            ?userContext  rdf:type       rs:UserContext ;
                      rs:appliedOnItems  ?itemClass ;
                      rs:appliedOnUsers  ?userClass
            FILTER EXISTS { ?item  rdf:type  ?itemClass }
            FILTER NOT EXISTS { ?user  rdf:type  ?userClass }
            OPTIONAL
                #Here is the skip
              { ?userContext  rs:doNotRecommendInCaseNotMatch  true
                BIND(0 AS ?skip)
              }
            OPTIONAL
              { ?userContext  rs:hasWeightIfContextDoesNotMatch  ?weight }
            BIND(if(bound(?weight), ?weight, 0.1) AS ?finalWeight)
          }
      }
    BIND(if(bound(?finalWeight), ?finalWeight, 1) AS ?finalWeightFinal)
  }
GROUP BY ?item

更新 2

在@Joshua Taylor 的赞赏回答后,我尝试将他的方法应用到实际案例中,但这次添加了 filter !bound(?skip)

这里是查询

SELECT  ?item ?itemClass ?userContext ?skip ?finalWeight 
WHERE
  { #{ 
    in this block i just select the items that i want to calculate the user context to.
    } #
    OPTIONAL
      { FILTER EXISTS { ?item  rdf:type  ?itemClass }
        ?userContext  rdf:type       rs:UserContext ;
                  rs:appliedOnItems  ?itemClass ;
                  rs:appliedOnUsers  ?userClass
        OPTIONAL
          { ?userContext  rs:hasWeightIfContextMatched  ?weightMatched }
        OPTIONAL
          { ?userContext  rs:hasWeightIfContextDoesNotMatch  ?weightNotMatched }
        OPTIONAL
          { ?userContext  rs:doNotRecommendInCaseNotMatch  true
            BIND(1 AS ?skip)
          }
        BIND(if(EXISTS { ?user  rdf:type  ?userClass }, coalesce(?weightMatched, "default User Matched"), coalesce(?weightNotMatched, "default User not matched")) AS ?weight)
      }
    BIND(if(bound(?weight), ?weight, "no user context found for this item") AS ?finalWeight)
    FILTER ( ! bound(?skip) )
  }

它适用于我现有的数据,但我现在只有一个测试数据,所以我想问你它是否正确

更新 3

我的查询生成了这些字段:

item skip ...

过滤器会删除确实具有跳过绑定的行,但假设一个项目有两行,如下所示:

item skip

A 1

A

A

所以在我的例子中,我将只删除第一行,我需要知道我是否可以删除该项目的所有行。

有很多方法可以做到这一点;这是一个获取每个项目的总重量,然后检查该项目是否有不推荐标志,如果有,则使用 0 作为总重量:

select ?item (if(bound(?skip), 0.0, ?sumWeight_) as ?sumWeight) {
  { select ?item (sum(?weight) as ?sumWeight_) where {
      ?item :hasContext/:weight ?weight .
    }
    group by ?item
  }
  bind(exists { ?item :hasContext/:doNotRecommend true } as ?skip)
}
----------------------------
| item         | sumWeight |
============================
| :item        | 0.0       |
| :anotherItem | 0.0       |
----------------------------

从概念上讲,此查询会为每个项目检查一次是否有任何上下文将其标记为不推荐。我觉得这样比较有效率。

绑定(存在 { … } 作为 ?skip)

请注意 bindexists 的组合。您已经知道 bind 的工作原理,因为您已经使用了很多次。 bind(expr as ?variable) 计算表达式 expr 并将其分配给变量 ?variable。您之前可能在 filter 表达式中使用过 exists 和 (not exists) 。 exists { … } 如果大括号内的模式在图中匹配则为真,否则为假。 not exists { … } 类似,但相反。模式

?item :hasContext/:doNotRecommend true

只是 shorthand,使用 属性 路径,用于模式:

?item :hasContext ?something .
?something :doNotrecommend true .

在这种情况下,如果该模式存在,那么我们要跳过项目的总重量并使用零代替。

备选

如果您愿意计算所有项目的总和,然后排除那些至少具有不推荐上下文的项目,您也可以这样做。诀窍就是弄清楚如何计算跳过的次数:

select ?item (sum(?weight_) as ?weight){
  ?item :hasContext ?context .
  ?context :weight ?weight_ .
  bind(exists { ?context :doNotRecommend true } as ?skip)
}
group by ?item
having (sum(if(?skip,1,0)) = 0)

注意事项

你提到

i know that i can always run another query in an upper level of this query and solve it or i can solve it using filter not exist but i am looking to solve it in the same query, because what i should u is a minimal data, while in my ontology, getting that weight and these objects is a very long query

上面的解决方案首先计算和权重,然后决定使用哪个和丢弃哪个。这意味着有一些不必要的计算。您的解决方案做了类似的事情:它计算没有 :doNotRecommend 属性 的上下文的权重,即使同一项目的某些其他上下文有 doNotRecommend 属性。如果你真的想避免不必要的计算,那么你应该先找出哪些项目是可推荐的,然后计算那些项目的分数,并找出哪些项目是不可推荐的,那些只是 return 零。

很容易得到哪些项目是哪些的列表:类似

select distinct ?item ?skip {
  ?item :hasContext ?anything .
  bind(exists{ :hasContext/:doNotRecommend true} as ?skip)
}

会做的很好。但是,由于您想要对可跳过值和不可跳过值执行不同的操作,并且这可能采用两种选择的并集形式,因此您遇到的问题是您必须重复每个子查询都相同。 (或者在一个中使用 exists,在另一个中使用 not exists,这实际上是在重复相同的查询。)它很快就会变得丑陋。它可能看起来像这样:

select ?item ?weight {
  {
     #-- get non recommendable items and
     #-- set their weights to 0.0.
     select distinct ?item (0.0 as ?weight) {
       ?item :hasContext/:doNotRecommend true      #-- (*)
     }
  }
  union
  {
     #-- get recommendable items and
     #-- their aggregate weights
     select ?item (sum(?weight_) as ?weight) {
       #-- find the recommendable items
       { select distinct ?item {
           ?item :hasContext ?x .
           filter not exists { ?item :hasContext/:doNotRecommend true }   #-- (*)
         }
       }
       #-- and get their context's weights.
       ?item :hasContext/:weight ?weight_
     }
     group by ?item
  }
}
-------------------------
| item         | weight |
=========================
| :item        | 0.0    |
| :anotherItem | 0.9    |
-------------------------

在我看来,问题在于标有 (*) 的行实际上在做同样的事情。其他计算不会发生多次,这很好,但我们仍在为每个项目检查两次是否值得推荐。