Ani*_*vid 2 rdf semantic-web owl ontology sparql
这是我的最低数据:
@prefix : <http://example.org/rs#>
:item :hasContext [:weight 0.1 ; :doNotRecommend true] , [:weight 0.2 ] .
:anotherItem :hasContext [:weight 0.4] , [ :weight 0.5 ] .
Run Code Online (Sandbox Code Playgroud)
如您所见,每个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
Run Code Online (Sandbox Code Playgroud)
查看 的值: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
Run Code Online (Sandbox Code Playgroud)
在@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) )
}
Run Code Online (Sandbox Code Playgroud)
它适用于我拥有的数据,但我现在只有一个测试数据,所以我想问你它是否正确
我的查询生成这些字段:
item skip ...
并且过滤器删除确实具有跳过绑定的行,但假设一个项目有两行,如下所示:
item skip
A 1
A
A
所以在我的情况下,我将只删除第一行,我需要知道我是否可以删除该项目的所有行。
There are lots of ways to do this; here's one that gets each item's sum weight, and then checks whether the item has a do not recommend flag, and if it does, uses 0 as the total weight:
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)
}
Run Code Online (Sandbox Code Playgroud)
----------------------------
| item | sumWeight |
============================
| :item | 0.0 |
| :anotherItem | 0.0 |
----------------------------
Run Code Online (Sandbox Code Playgroud)
Conceptually, this query checks once for each item whether any of its contexts mark it as non-recommendable. I think that's relatively efficient.
Note that combination of bind and exists. You already know how bind works, as you've used it plenty of times. bind(expr as ?variable) evaluates the expression expr and assigns it to the variable ?variable. You'd probably used exists and (not exists) in filter expressions before. exists { … } is true if the pattern inside the braces matches in the graph, and false otherwise. not exists { … } is similar, but reversed. The pattern
?item :hasContext/:doNotRecommend true
Run Code Online (Sandbox Code Playgroud)
is just shorthand, using a property path, for the pattern:
?item :hasContext ?something .
?something :doNotrecommend true .
Run Code Online (Sandbox Code Playgroud)
In this case, if that pattern exists, then we want to skip the item's sum weight and use zero instead.
If you're willing to compute the sum for all the items, and then exclude those that have at least non-recommendable context, you can do that, too. The trick is just to figure out how to count the number of skips:
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)
Run Code Online (Sandbox Code Playgroud)
You mentioned that
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
The solution above computes the sum weights first, and then decides which to use and which to discard. That means that there's some unnecessary computation. Your solution does something similar: it computes weights for contexts that don't have the :doNotRecommend property, even if some other context for the same item has a doNotRecommend property. If you really want to avoid the unnecessary computation, then you should figure out which items are recommendable first, and then compute scores for those, and figure out which items are not recommendable, and just return zero for those.
It's easy to get a list of which items are which: something like
select distinct ?item ?skip {
?item :hasContext ?anything .
bind(exists{ :hasContext/:doNotRecommend true} as ?skip)
}
Run Code Online (Sandbox Code Playgroud)
will do it just fine. However, since you'd want to do different things with the skippable and the non-skippable values, and that would probably take the form of a union of the two alternatives, and then you have the problem that you'd have to repeat the same subquery in each one. (Or use exists in one and not exists in the other, which is essentially repeating the same query.) It would get ugly pretty quickly. It might look something like this:
----------------------------
| item | sumWeight |
============================
| :item | 0.0 |
| :anotherItem | 0.0 |
----------------------------
Run Code Online (Sandbox Code Playgroud)
-------------------------
| item | weight |
=========================
| :item | 0.0 |
| :anotherItem | 0.9 |
-------------------------
Run Code Online (Sandbox Code Playgroud)
The problem, in my opinion, is that the lines marked with (*) are really doing the same thing. The other computation doesn't happen multiple times, which is good, but we're still checking twice for each item whether it's recommendable or not.
| 归档时间: |
|
| 查看次数: |
2573 次 |
| 最近记录: |