包含 FILTER NOT EXISTS 和 OPTIONAL 的 UNION 案例不会产生结果?

UNION case containing FILTER NOT EXISTS and OPTIONAL doesn't produce results?

我有一个选择某些项目的查询。如果这些项目属于特定的 class (:UserSuitability),那么我需要检查用户是否也来自同一个 class。有四种可能的情况:

  1. 该项目来自 class,即 rdfs:subClassOf:UserSuitability,用户也来自同一个 class。然后检查该项目是否包含 hasSuitabilityValue 的值并将其分配给变量 ?suitabilityValue.
  2. 该项目来自 class 即 rdfs:subClassOf :UserSuitability,但用户不是,然后检查该项目是否包含 hasSuitabilityNotValue 的值并将其分配给变量 ?suitabilityValue。
  3. 该项目不是来自 class 即 rdfs:subClassOf:UserSuitability,然后将 1 分配给变量 ?suitabilityValue。
    1. 该项目不是来自 class 即 rdfs:subClassOf:UserSuitability,用户也不是。在这种情况下,什么都不做。

到目前为止我的查询以及用于测试它的数据在下面提供。请注意,数据中的 :item1 应匹配并集的左侧,而 :item2 应匹配右侧。右边似乎永远不会匹配。

数据

@prefix : <http://www.semanticrecommender.com/rs#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .

:user1 a :class1 .
:user1 :likes :item1 .
:user1 :likes :item2 .
:class1 rdfs:subClassOf :UserSuitability .
:item1 a :class1 .
:item1 :hasSuitabilityWeight 1.5 .
:item1 :hasNotSuitabilityWeight 0.5 .
:item2 a :class2 .
:class2 rdfs:subClassOf :UserSuitability .

查询

prefix : <http://www.semanticrecommender.com/rs#>
prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>

select ?item ?suitabilityValue where
{
  values ?user {:user1}
  ?user :likes ?item

  optional{
    #-- check if the item is from a class that is
    #-- rdfs:subClassOf :UserSuitability
    ?item a ?suitabilityClass.
    ?suitabilityClass rdfs:subClassOf :UserSuitability.
    {
      #-- if the user is also from the same class
      ?user a ?suitabilityClass
        optional{
        #-- check if the item has a value for :hasSuitabilityWeight
        ?item :hasSuitabilityWeight ?suitabilityValueOptional.
      }
      #-- if it does, assign it to the variable
      #-- ?suitabilityValue, otherwise, assign 1
      #-- to the variable suitabilityValue
      bind(if(bound(?suitabilityValueOptional), ?suitabilityValueOptional, 1) as ?suitabilityValue)

    }
    union
    {
      #-- if the user is not from the same class
      filter not exists {?user a ?suitabilityClass}
      optional{
        #-- if the item has a value to hasNotSuitabilityWeight
        ?item :hasNotSuitabilityWeight ?suitabilityNotValueOptional.
      }
      #-- assign it to suitabilityValue, otherwise, assign 0
      bind(if(bound(?suitabilityNotValueOptional), ?suitabilityNotValueOptional, 0) as ?suitabilityValue)
    }
  }
}

所以,我尝试从头开始重现这个问题,最终得到的数据与您的非常相似,只是稍微简单了一点。这是我最终使用的数据,它让我避免了一些关于 class 是否真的合适的过滤。

@prefix : <urn:ex:>

:user a :A ;
      :likes :i , :j .

:i a :A ;
   :hasValueYes 1 ;
   :hasValueNo  2 .

:j a :B .

现在,这是类似于您的查询;它只会得到两个项目之一的结果,即使看起来另一个应该匹配。有一个注释行,我稍后会解释。

prefix : <urn:ex:>

select ?item ?value {
  values ?user { :user }

  ?user :likes ?item .
  ?item a ?itemClass .

  {
    ?user a ?itemClass
    optional {
      ?item :hasValueYes ?valueYes
    }
    bind(if(bound(?valueYes), ?valueYes, "default yes value") as ?value)
  }
  union
  {
    #-- ?item ?anyP ?anyO   # (***)
    filter not exists { ?user a ?itemClass }
    optional {
      ?item :hasValueNo ?valueNo
    }
    bind(if(bound(?valueNo), ?valueNo, "default no value") as ?value)
  }
}  
----------------
| item | value |
================
| :i   | 1     |
----------------

现在,该查询中有一行注释:

#-- ?item ?anyP ?anyO   # (***)

如果您取消注释该行,您将得到预期的结果:

-----------------------------
| item | value              |
=============================
| :i   | 1                  |
| :j   | "default no value" |
-----------------------------

认为这里发生的是在第二种可选情况下,因为没有引入绑定的三重模式(因为可选 不匹配),union 的那一边没有被包括在内,即使 bind 如果允许边匹配,将引入一些绑定。通过添加模式:

?item ?anyP ?anyO

对于查询,至少有 something 将在 union 的那部分匹配,此时其余部分块被包括在内。我使用 ?anyP?anyO 来强调它是任意的,但是因为你已经知道 ?item 是一个 ?itemClass,你可以再次包含那个三元组,即 ?item a ?itemClass.

所以,在你的情况下,如果你只添加

?user :likes ?item

右边的 union 块,你会得到你期待的结果:

-----------------------------
| item   | suitabilityValue |
=============================
| :item2 | 0                |
| :item1 | 1.5              |
-----------------------------