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

Viewed 525

I have a query that selects some items. If these items belong to a specific class (:UserSuitability), then I need to check if the user is also from the same class. There are four possible scenarios:

  1. The item is from a class that is rdfs:subClassOf :UserSuitability, and the user is also from the same class. Then check if the item contains a value for hasSuitabilityValue and assign it to the variable ?suitabilityValue.
  2. The item is from a class that is rdfs:subClassOf :UserSuitability, but the user is not, then check if the item contains a value for hasSuitabilityNotValue and assign it to the variable ?suitabilityValue.
  3. The item is not from a class that is rdfs:subClassOf: UserSuitability, then assign 1 to the variable ?suitabilityValue.
    1. The item is not from a class that is rdfs:subClassOf:UserSuitability, and neither is the user. In this case, do nothing.

My query so far, and the data to test it with are provided below. Note that :item1 in the data should match the left hand side of the union, while :item2 should match the right hand side. It seems that the right hand side never matches.

Data

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

Query

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)
    }
  }
}
1 Answers
Related