Search code examples
sparqlrdf

SPARQL: Split one variable by object type


I've some RDF data which looks something like this:

WatchObject -subclassOf-> Accessory
BagObject -subclassOf-> Accessory
Person -hasAccessory-> Accessory

Where WatchObject and BagObject are both subclasses of "Accessory", which has the relation has(is)Accessory(of) with Person.

I would like to query it now to get a persons watches and bags in seperate variables. So I thought of something like:

SELECT DISTINCT ?person ?watch ?bag
WHERE {
    ?person rdf:type x:Person .
    ?person x:hasAccessory ?bag^^x:BagObject .
    ?person x:hasAccessory ?watch^^x:WatchObject .
}

Is it possible to express something like this in a SPARQL query? Another question would be if it's reasonable to model my data like this, or would it be better to add two more ObjectProperties like this?

WatchObject -subclassOf-> Accessory
BagObject -subclassOf-> Accessory
Person -hasAccessory-> Accessory
Person -hasWatch-> WatchObject
Person -hasBag-> BagObject

Solution

  • You just need to add triples specifying a type of the ?bag and ?watch variables, just like you specified a type for the ?person variable:

    SELECT DISTINCT ?person ?watch ?bag {
        ?person a x:Person .
        ?person x:hasAccessory ?bag .
        ?bag a x:BagObject .
        ?person x:hasAccessory ?watch .
        ?watch a x:WatchObject .
    }
    

    Note that that will get you the cross product of bags and watches; i.e., you'll get each combination of a person's bags and watches. Also, it requires that the person have at least one bag and at least one watch, otherwise the query won't match. You might look into optional to see how to make these optional.

    Another question would be if it's reasonable to model my data like this, or would it be better to add two more ObjectProperties like this?

    WatchObject -subclassOf-> Accessory
    BagObject -subclassOf-> Accessory
    Person -hasAccessory-> Accessory
    Person -hasWatch-> WatchObject
    Person -hasBag-> BagObject
    

    You could do this, too. If you do, then it might also be good to add the triples:

    hasWatch rdfs:subPropertyOf hasAccessory
    hasBag   rdfs:subPropertyOf hasAccessory
    

    Then, if you have inference enabled, or you adjust your query a little bit, then you can still retrieve things with just the one hasAccessory property.