sparqlstardog

Optional Sparql-Statement for unbound variable is not working in Stardog


Context

Hi!
I have a specification that displays questions associated with certain relationships in another specification. All objects in my specification have so-called fragment-verbalizations (relation:hasFragmentVerbalisation).
To display my questions correctly, I need to differentiate cases where I have a "simple" Iri whose verbalization I can use directly or if it is of a certain type (in this case if it is the iri of a room or a employee) in which cases I want to return the preferred labels of all resources of said type (so basically if my object represents a room, I want to return all rooms I have in my database).

I am currently working on a query and trying to add a statement-part that looks like this:

    OPTIONAL {
        FILTER(isIRI(?object)).
        ?object relation:hasFragmentVerbalisation ?objectVerb .
    }

   OPTIONAL {
        FILTER (?objectVerb= "Person"@en || ?objectVerb = "Teacher"@en)
        ?a employee:prefLabel ?employeename .
        BIND( ?employeename as ?final ) .
    }

    OPTIONAL {
        FILTER (?objectVerb= "room"@en || ?objectVerb = "lecture hall"@en)
        ?b room:prefLabel ?roomnumber .
        BIND( ?roomnumber as ?final) .
        FILTER (regex(?roomnumber, "20" ))
    }

    #OPTIONAL {
    #    FILTER (!BOUND(?final))
    #    BIND( IF ( isURI(?object), ?objectVerb, ?object) as ?final ) .
    #}

What I want to happen here

I retrieved the ?object. The main result of my query is the ?final object. I now want to cover three possible cases:

The issues

In general, all but the out commented one work. However, I am having two issues here:

  1. For the second and third Optionals instead of comparing the ?objectVerb to predefined strings, I'd rather ask (only pseudo-code:) Do this only if ?object rdf:type iri:for:person:or:room. However, I cannot seem to make a statement like that work.
  2. The "outcommented" optional call (the last one) does not work at all and I am a bit confused as to why. What I am trying here is:
    • If my ?final variable is not yet bound by anything, I want to check if ?object is an IRI and if not, I want the previously retrieved ?objectVerb-value to be set as the value of ?final

Can anyone here point out a solution? Thanks for the help.

EDIT: The full Query:

PREFIX relation: <urn:xxx:beziehungen#> 
PREFIX yyy: <urn:xxx#> 
PREFIX employee: <urn:xxx:fb5:employee#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> 
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX room: <urn:yyy:assets:location:room#>  
PREFIX label: <urn:xxx:assets:labels#>
PREFIX wording: <urn:xxx:assets:wording#>

SELECT DISTINCT ?first ?second ?third ?fourth ?fourt4 ?fifth ?resulttype
WHERE {
    ?wording rdf:first ?first1 .
    ?wording rdf:rest/rdf:first ?second2 .
    ?wording rdf:rest/rdf:rest/rdf:first ?third3 .
    ?wording rdf:rest/rdf:rest/rdf:rest/rdf:first ?fourt4 .
    ?wording rdf:rest/rdf:rest/rdf:rest/rdf:rest/rdf:first ?fifth5 .

    relation:hasBureau rdfs:range ?resulttype .
    
    {
        SELECT distinct ?wording (COUNT(?wording) AS ?sum) 
        WHERE {
            relation:hasBureau relation:bigWord ?wording .
            ?wording rdf:rest*/rdf:first ?element .
        }
        GROUP BY ?wording
        HAVING (?sum = 5)
    }

    OPTIONAL {
        FILTER(isIRI(?first1)).
        ?first1 relation:fragmentWord ?firstVerb.
    }
    BIND( IF ( isURI(?first1), ?firstVerb , ?first1) as ?first ) .
    FILTER(BOUND(?first)).

    OPTIONAL {
        FILTER(isIRI(?second2)).
        ?second2 relation:fragmentWord ?secondVerb.
    }

    OPTIONAL {
        FILTER(isIRI(?third3)).
        ?third3 relation:fragmentWord ?thirdVerb.
    }
    BIND( IF ( isURI(?third3), ?thirdVerb , ?third3) as ?third ) .
    FILTER(BOUND(?third)).

    OPTIONAL {
        FILTER(isIRI(?fourt4)).
        ?fourt4 relation:fragmentWord ?fourthVerb .
    }

    OPTIONAL {
        FILTER(isIRI(?fifth5)).
        ?fifth5 relation:fragmentWord ?fifthVerb.
    }
    BIND( IF ( isURI(?fifth5), ?fifthVerb, ?fifth5) as ?fifth ) .
    FILTER(BOUND(?fifth)).

    OPTIONAL {
        FILTER (?fourthVerb = "Person"@de || ?fourthVerb = "Dozent"@de || ?fourthVerb = "Lehrender"@de || ?fourthVerb = "Angestellter"@de)
        ?a employee:prefLabel ?employeename .
        BIND( ?employeename as ?fourth ) .
    }

    OPTIONAL {
        FILTER (?fourthVerb = "Hörsaal"@de || ?fourthVerb = "Zimmer"@de || ?fourthVerb = "Seminarraum"@de)
        ?b room:prefLabel ?roomnumber .
        BIND( ?roomnumber as ?fourth ) .
    }
    FILTER(BOUND(?fourth)).

    #OPTIONAL {
    #    FILTER (!BOUND(?fourth))
    #    BIND( IF ( isURI(?fourt4), ?fourthVerb, ?fourt4) as ?fourth ) .
    #}

    OPTIONAL {
        FILTER (?secondVerb = "Büro"@de)
        BIND( "Büro"@de as ?second ) .
    }

        OPTIONAL {
        FILTER (?secondVerb = "Buero"@de)
        BIND( "Buero"@de as ?second ) .
    }

    OPTIONAL {
        FILTER (?secondVerb = "Person"@de || ?secondVerb = "Dozent"@de || ?secondVerb = "Lehrender"@de || ?secondVerb = "Angestellter"@de)
        ?a employee:prefLabel ?employeename .
        BIND( ?employeename as ?second ) .
    }

    #OPTIONAL {
    #    FILTER (!BOUND(?second))
    #    BIND( IF ( isURI(?second2), ?secondVerb, ?second2) as ?second ) .
    #}
}

And an extremely shortened dataset to run it on for which it works:

PREFIX relation: <urn:xxx:beziehungen#> 
PREFIX yyy: <urn:xxx#> 
PREFIX employee: <urn:xxx:fb5:employee#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> 
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX room: <urn:yyy:assets:location:room#>  
PREFIX label: <urn:xxx:assets:labels#>
PREFIX wording: <urn:xxx:assets:wording#>

<urn:xxx:fb5:employee#>
    rdfs:subClassOf wording:fragment ;
    relation:fragmentWord "Person"@de , "Dozent"@de, "Lehrender"@de, "Angestellter"@de .

<urn:yyy:assets:location:room#> 
    rdfs:subClassOf wording:fragment ;
    relation:fragmentWord "Raum"@de , "Zimmer"@de, "Seminarraum"@de, "Hörsaal"@de .

relation:hasBureau 
    rdf:type rdf:Property ;
    owl:minCardinality "1" ;
    rdfs:domain employee:name ;
    rdfs:range room:number ;
    rdfs:label "hat ein Büro"@de, "has a bureau"@en ;
    relation:fragmentWord "Büro"@de , "Buero"@de ;
    relation:bigWord ("In welchem" relation:hasBureau "ist" <urn:xxx:fb5:employee#> "?") ;
    relation:bigWord ("Finde ich"  <urn:xxx:fb5:employee#> "in" <urn:yyy:assets:location:room#> "?") .

employee:PersonOne employee:prefLabel "Employee One".
employee:PersonOne relation:hasBureau room:23129 . 
room:23129 room:prefLabel "23-129".
employee:PersonTwo employee:prefLabel "Employee Two".
employee:PersonTwo relation:hasBureau room:23232 . 
room:23232 room:prefLabel "23-232".

Solution

  • Not meant to be an answer but showing some query to get feedback:

    Data:

    PREFIX relation: <urn:xxx:beziehungen#> 
    PREFIX yyy: <urn:xxx#> 
    PREFIX employee: <urn:xxx:fb5:employee#>
    PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> 
    PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
    PREFIX room: <urn:yyy:assets:location:room#>  
    PREFIX label: <urn:xxx:assets:labels#>
    PREFIX wording: <urn:xxx:assets:wording#>
    PREFIX owl: <http://www.w3.org/2002/07/owl#>
    
    <urn:xxx:fb5:employee#>
        rdfs:subClassOf wording:fragment ;
        relation:fragmentWord "Person"@de , "Dozent"@de, "Lehrender"@de, "Angestellter"@de .
    
    <urn:yyy:assets:location:room#> 
        rdfs:subClassOf wording:fragment ;
        relation:fragmentWord "Raum"@de , "Zimmer"@de, "Seminarraum"@de, "Hörsaal"@de .
    
    relation:hasBureau 
        rdf:type rdf:Property ;
        owl:minCardinality "1" ;
        rdfs:domain employee:name ;
        rdfs:range room:number ;
        rdfs:label "hat ein Büro"@de, "has a bureau"@en ;
        relation:fragmentWord "Büro"@de , "Buero"@de ;
        relation:bigWord ("In welchem" relation:hasBureau "ist" <urn:xxx:fb5:employee#> "?") ;
        relation:bigWord ("Finde ich"  <urn:xxx:fb5:employee#> "in" <urn:yyy:assets:location:room#> "?") .
    
    employee:PersonOne employee:prefLabel "Employee One".
    employee:PersonOne relation:hasBureau room:23129 . 
    room:23129 room:prefLabel "23-129".
    
    employee:PersonTwo employee:prefLabel "Employee Two".
    employee:PersonTwo relation:hasBureau room:23232 . 
    room:23232 room:prefLabel "23-232".
    

    Query:

    PREFIX relation: <urn:xxx:beziehungen#> 
    PREFIX yyy: <urn:xxx#> 
    PREFIX employee: <urn:xxx:fb5:employee#>
    PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> 
    PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
    PREFIX room: <urn:yyy:assets:location:room#>  
    PREFIX label: <urn:xxx:assets:labels#>
    PREFIX wording: <urn:xxx:assets:wording#>
    
    SELECT DISTINCT ?first ?second ?third ?fourth ?fifth ?resulttype
    WHERE {
        ?wording rdf:first ?first1 .
        ?wording rdf:rest/rdf:first ?second2 .
        ?wording rdf:rest/rdf:rest/rdf:first ?third3 .
        ?wording rdf:rest/rdf:rest/rdf:rest/rdf:first ?fourth4 .
        ?wording rdf:rest/rdf:rest/rdf:rest/rdf:rest/rdf:first ?fifth5 .
    
        relation:hasBureau rdfs:range ?resulttype .
        
        ?a employee:prefLabel ?employeename .
        ?b room:prefLabel ?roomnumber .
    
        
        {
            SELECT ?wording (COUNT(?wording) AS ?sum) 
            WHERE {
                relation:hasBureau relation:bigWord ?wording .
                ?wording rdf:rest*/rdf:first ?element .
            }
            GROUP BY ?wording
            HAVING (?sum = 5)
        }
    
        OPTIONAL {
            ?first1 relation:fragmentWord ?firstVerb .
        }
        BIND( COALESCE(?firstVerb, ?first1) as ?first )
    
        OPTIONAL {
            ?second2 relation:fragmentWord ?secondVerb .
        }
        BIND( IF(?second2 = <urn:xxx:fb5:employee#>, ?employeename, IF(?second2 = room:, ?roomnumber, COALESCE(?secondVerb, ?second2))) as ?second )
    
    
        OPTIONAL {
            ?third3 relation:fragmentWord ?thirdVerb .
        }
        BIND( COALESCE(?thirdVerb, ?third3) as ?third )
    
        OPTIONAL {
            ?fourth4 relation:fragmentWord ?fourthVerb .
        }
        BIND( IF(?fourth4 = <urn:xxx:fb5:employee#>, ?employeename, IF(?fourth4 = room:, ?roomnumber, COALESCE(?fourthVerb, ?fourth4))) as ?fourth )
    
        OPTIONAL {
            ?fifth5 relation:fragmentWord ?fifthVerb .
        }
        BIND( COALESCE(?fifthVerb, ?fifth5) as ?fifth )
    
        
    }
    

    Result:

    --------------------------------------------------------------------------------
    | first        | second         | third | fourth         | fifth | resulttype  |
    ================================================================================
    | "In welchem" | "Buero"@de     | "ist" | "Employee Two" | "?"   | room:number |
    | "In welchem" | "Büro"@de      | "ist" | "Employee Two" | "?"   | room:number |
    | "In welchem" | "Buero"@de     | "ist" | "Employee One" | "?"   | room:number |
    | "In welchem" | "Büro"@de      | "ist" | "Employee One" | "?"   | room:number |
    | "Finde ich"  | "Employee Two" | "in"  | "23-232"       | "?"   | room:number |
    | "Finde ich"  | "Employee Two" | "in"  | "23-129"       | "?"   | room:number |
    | "Finde ich"  | "Employee One" | "in"  | "23-232"       | "?"   | room:number |
    | "Finde ich"  | "Employee One" | "in"  | "23-129"       | "?"   | room:number |
    --------------------------------------------------------------------------------