这是我的最低数据:
@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
(提示,我知道我总是可以在此查询的更高级别上运行另一个查询并解决它,或者我可以使用不存在的过滤器来解决它,但是我希望在同一查询中解决它,因为我应该是什么最少的数据,而在我的本体中,获得权重和这些对象是一个很长的查询
这是我真正的查询,第一部分(在联合之前)检查用户是否确认上下文,第二部分(在联合之后)检查用户是否不符合上下文,在这里我要检查是否上下文具有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
在获得@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) )
}
它可以处理我拥有的数据,但是我现在只有一个测试数据,所以我想问你是否正确
我的查询生成以下字段:
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 |
----------------------------
从概念上讲,此查询为每个项目检查一次,是否其上下文中的任何内容将其标记为不可推荐。我认为这是相对有效的。
需要注意的是组合绑定和存在。您已经知道绑定是如何工作的,因为您已经使用了很多次。bind(expr as?variable)计算表达式expr并将其分配给变量?variable。你可能使用存在和(不存在)的过滤器之前的表达式。如果括号内的模式在图中匹配,则存在{…}为true,否则为false。不存在的{…}与之相似,但是相反。图案
?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)
你提到过
我知道我总是可以在此查询的更高级别上运行另一个查询并解决它,或者我可以使用不存在的过滤器来解决它,但是我希望在同一查询中解决它,因为我应该是一个最小的数据,而在我的本体中,获得重量和这些对象是一个很长的查询
上面的解决方案首先计算和权重,然后确定要使用和丢弃的权重。这意味着有一些不必要的计算。您的解决方案执行类似的操作:即使没有相同的其他上下文具有doNotRecommend属性,它也会为没有:doNotRecommend属性的上下文计算权重。如果您真的想避免不必要的计算,则应先确定哪些项目是可推荐的,然后为这些项目计算分数,确定哪些项目不值得推荐,并为这些项目返回零。
很容易获得哪些项目的清单:
select distinct ?item ?skip {
?item :hasContext ?anything .
bind(exists{ :hasContext/:doNotRecommend true} as ?skip)
}
会做的很好。但是,由于您想对skippable和non-skipable值执行不同的操作,并且这可能采用两种选择的并集形式,因此,您遇到的问题是必须重复执行每个子查询中都有相同的子查询。(或者使用存在于一个中而不存在于另一个中,这实际上是在重复相同的查询。)它将很快变得很丑陋。它可能看起来像这样:
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 |
-------------------------
我认为问题在于,标有(*)的行确实在做同一件事。其他计算不会多次发生,这很好,但是我们仍在检查每个项目是否值得推荐两次。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句