sparql 检查属性的存在并给答案零

标签 sparql rdf semantic-web owl ontology

这是我的最少数据:

@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

结果

enter image description here

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

的情况下为零

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

更新一

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

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

我的查询生成这些字段:

项目跳过...

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

项目跳过

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       |
----------------------------

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

bind(exists { … } as ?skip)

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

?item :hasContext/:doNotRecommend true

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

?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 属性也是如此。如果你真的想避免不必要的计算,那么你应该先找出哪些项目是可推荐的,然后计算那些项目的分数,找出哪些项目是不可推荐的,并为那些项目返回零。

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

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    |
-------------------------

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

关于sparql 检查属性的存在并给答案零,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36621269/

相关文章:

sparql - 如何从维基百科获取完整的页面标题列表?

web - 删除查询 SPARQL FUSEKI

java.lang.OutOfMemory错误: GC overhead limit exceeded when I load RDF file in Web Service

tags - 内容的自动分类

rdf - 如何构建正确的 SPARQL 查询

rdf - 学习RDF/OWL的最佳方法是什么?

java - 我正在使用 Jena 启动 SPARQL 查询。该查询在 DBpedia SPARQL 端点中有效!我在查询 validator 验证了查询并得到了相同的错误

rdf - 基于 SParQL 中的 URI 进行过滤

hyperlink - rdf :seeAlso and rdfs:seeAlso 之间的区别

java - RDF/XML Jena getValue