0

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:

  • First optional statement: Here I just want to retrieve the fragment verbalization.
  • Second optional statement: If my IRI is actually pointing to an employee, I want to return all my employee's preferred Labels as ?final. Basically, I am returning a list of all my employees.
  • Third optional statement: If my IRI is pointing to a room, I want to return all room numbers for ?final. The regex Filter is not important for my questions here.
  • Fourth (outcommented) optional statement: If the second and third statement did not fit, ?final should not be bound

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".
  • can you show what you tried regarding issue 1 please?. I'm aksing because you should be able to always get the `rdf:type` of the object and apply a filter. does this not work? – UninformedUser Feb 16 '21 at 01:31
  • Sadly my Server got deleted by accident so I do not have the exact call anymore, but I think I used something like `FILTER (?object = room:concept)` and `FILTER (?object rdy:type room:concept`). I tried around quite a bit but I'd say all along those lines but I am also rather a beginner so I might have missed something. – AnnemarieWittig Feb 16 '21 at 10:42
  • ah, I see. Well, the type information has to be retrieved the same way you did for the other data, by means of triple patterns. So, you have to use a triple pattern `?object rdf:type ?objectType.` and then you could use a filter like `FILTER(?objectType IN (:room, :person))` – UninformedUser Feb 16 '21 at 11:23
  • So I tried this: `OPTIONAL { FILTER(isIRI(?second2)). ?second2 relation:hasFragmentVerbalisation ?secondVerb. } OPTIONAL { FILTER (?second2 IN ()) BIND( ?secondVerb as ?second ) . }` and returned ?second2 just to check but whenever I have it being `urn:hsanhalt:beziehungen#hasBureau`, ?second is just an empty String. Did I miss something? And thanks for the help already! – AnnemarieWittig Feb 17 '21 at 10:30
  • hm, it's rather hard to read parts of a query in comments. Would it be possible for you to somehow provide the whole current query as well as some sample data such that I could run the query and modify it accordingly? Github Gist for example to share the data or just edit the current question here. – UninformedUser Feb 17 '21 at 11:45
  • 1
    @UninformedUser I provided the complete query in the original Question, I hope it helps clearing things up! I also added some quickly written data it works on - sorry for the weird wording in there. – AnnemarieWittig Feb 17 '21 at 18:18
  • thanks for providing the data and query - one question, you mentioned `rdf:type` triples, but I cannot see those in the data - also, you said the query is "working" now? Which part exactly does not work on which data? – UninformedUser Feb 17 '21 at 18:32
  • Not a solution to your original problem I guess, but I started simplifying your query a bit: https://pastebin.com/imt6U6Pp – UninformedUser Feb 17 '21 at 20:02
  • @UninformedUser I wanted to change the query so that instead of asking if ?secondVerb = "Person", I simply wanted to ask "?second2 == ". I realize my comment was misleading. I sadly cannot open the pastebin link. – AnnemarieWittig Feb 19 '21 at 13:31
  • I see. Given that you want to get permutations for your I guess QA or dialogue system, do you want to replace the place holder URIs resp. their labels with the labels of particular employee or room number, or is it sufficient to get the labels? What I get for now is a row like `"In welchem" | "Buero"@de | "ist" | "Lehrender"@de | "?" | room:number` – UninformedUser Feb 19 '21 at 15:14
  • I added some query in an answer which isn't indeed an answer nor do I think it does solve your issue. Just to clarify things – UninformedUser Feb 19 '21 at 15:25

1 Answers1

3

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 |
--------------------------------------------------------------------------------
UninformedUser
  • 8,397
  • 1
  • 14
  • 23
  • Here I'd sadly have the issue that if e.g. ?second2 is an employee / represents an employee uri, I don't want the fragment-verbalisation of that uri but replace it with all employee names (in your query that'd be ?employeename). Same goes for :room. Using Coalesce is a great idea though – AnnemarieWittig Feb 21 '21 at 15:06
  • @AnnemarieWittig please see my edit. Now I use the instances, i.e. either employees or rooms depending on the corresponding place holder. – UninformedUser Feb 21 '21 at 17:11
  • Regarding your data: I think the resulttype should depend on something that I'm not aware of - at least for the last 4 patterns it shouldn't be a room:number but basically just a boolean, i.e. either true/false. – UninformedUser Feb 21 '21 at 17:17
  • You are an absolute lifesaver! This is exactly what I needed, thank you so much! As for the data/result type: it's all as I'd expect it to be, but I see that without the proper context it does not seem like it. I'll think about renaming it. – AnnemarieWittig Feb 21 '21 at 21:48
  • @AnnemarieWittig Glad it helps, took me a while to understand the expected result ... I've got another question, in your data you have `relation:hasBureau owl:minCardinality "1" ;` - what does this mean? Or better said, what do you want to express with it? – UninformedUser Feb 22 '21 at 08:54
  • I am sorry, I didn't see you wrote again. I'm using owl:minCardinality to state that the respective relation has to appear at least once for the domain – AnnemarieWittig Mar 12 '21 at 12:54
  • 1
    hi - ok, that's what I was thinking. In that case, it's not correct how you use it. `owl:minCardinality` is an OWL construct which is applied to OWL class expressions only and not directly to properties. So in your example, it should be a statement about the class `employee:name` (by the way, this an odd naming for an employee class, I'd suggest to use a different vocabulary namespace, and call the class `Employee`)). – UninformedUser Mar 12 '21 at 13:04
  • 1
    The OWL statement would be `employee:name rdfs:subClassOf [rdf:type owl:Restriction ; owl:onProperty relation:hasBureau ; owl:minCardinality 1 ].` - looks weird, but that's in fact the RDF serialization of OWL axioms, see https://www.w3.org/TR/owl2-mapping-to-rdf/ – UninformedUser Mar 12 '21 at 13:06
  • and yes, maybe you don't care in your application, I just want to let you know that your current form of data model doesn't have any implicit implications w.r.t. to the RDF and OWL standards. – UninformedUser Mar 12 '21 at 13:08
  • This is very helpful, thank you. So if I'd have multiple relations that need to appear at least once, would I write it like this: `employee:name rdfs:subClassOf [rdf:type owl:Restriction ; owl:onProperty relation:hasBureau ; owl:minCardinality 1 ]; rdfs:subClassOf [rdf:type owl:Restriction ; owl:onProperty relation:hasEmail ; owl:minCardinality 1 ].`? I am currently working on restructuring the ontology (actually mainly because of my odd naming, it's been a year and definetely needs a little update) so the inputs come at the perfect time. – AnnemarieWittig Mar 12 '21 at 13:11
  • 1
    well, yes that's basically how it would work. It works because multiple superclasses (which you add by means of `rdfs:subClassOf` triples work like an intersection implicitely. This is sometimes counter-intuitive for people, especially when the define domain/range of properties - like when people want to say a property can be used by several classes they often tend to write `:p rdfs:domain :A , :B` - but this statement means that any entity using `:p` is of both types `:A` and `:B` at the same time. one of many common pitfalls of OWL – UninformedUser Mar 12 '21 at 13:16
  • In your case, I'd really **suggest to use Protege as an ontology editor when writing OWL axioms**. Things like those property restrictions, union and intersection of complex class expression etc are rather verbose in RDF as you can see from my previous hint. – UninformedUser Mar 12 '21 at 13:18
  • Yes it is a bit confusing, but now that you pointed it out I should be able to recognize my errors better at least.. And maybe do better research before I reuse something again. Well, I guess I will need to go over my ontology now and fix quite some parts -- thank you again, I appreciate the input a lot. EDIT: I did check Protége but arrogantly assumed I can do it like that because I didn't quite understand the software right away, but I will look into it again. Cannot have errors like that in my system. – AnnemarieWittig Mar 12 '21 at 13:20
  • :D that's not arrogancy, computer scientists as well as other people sometimes tend to avoid graphical editors like Protege as they think it's slower and not necessary for their small ontologies. But the reality shows, that writing complex OWL axioms manually is sometimes quite error prone, especially when doing it in an RDF serialization format. – UninformedUser Mar 14 '21 at 12:01
  • In the end designing an ontology also depends on what you can make out of it. Does your application have any benefits from a complex ontology? Do you need things like inference. Or is it more like constraints in which case OWL is the wrong language - at least things like the term *"property restrictions"* are a bit misleading. they are not restrictions but can be used to infer things. Same for domain and range. For example, when defining `:A` is the domain of property `:p` the only formal consequence is that any instance `:x` "having" such a `:p` to a resource `:y`, then `:x` belongs to `:A` – UninformedUser Mar 14 '21 at 12:06