Search code examples
rdfowlontologyrdfs

Ordering of entities in an ontology


I have a system that models some domain data in an ontology, the usual sort of triplestore.

I've been looking around for a way to express plurality and ordering but haven't found anything via the googles. My main use case is something like one entity in the domain can be a list of tasks, (get groceries, cook meal, eat meal, something like that) but in general I feel like having the ability to 'weight' your edges might be useful across the board.

Is there an accepted way of doing this? Just go to a quadstore? Intermediary items (list → listitem) with edges to an ordinality and a domain entity? Predicates from predicates to Weights?

Here's an example:

Example layout


Solution

  • To represent something like what you've shown in your figure, you'd typically treat it as an n-ary relation. You should have a look at the W3C working note Defining N-ary Relations on the Semantic Web, but the short version is that you've got a 3-ary relation, and you're expressing

    hasTask(list,1,socks)
    hasTask(list,2,shoes)
    hasTask(list,3,leash)
    

    For each one of those, you'd have a resource, usually a blank node, but it could be a URI, too, and have properties relating it to the various components, and perhaps a type:

    _:rel1 rdf:type :taskItem ;
           :hasList :list ;
           :hasord  1;
           :hasTask :socks .
    _:rel2 rdf:type :taskItem ;
           :hasList :list ;
           :hasord  2;
           :hasTask :shoes .
    _:rel3 rdf:type :taskItem ;
           :hasList :list ;
           :hasord  3;
           :hasTask :leash .
    

    There's some variability here, of course. Rather than having the reified relation have the list, number, and task as property values, the list could be related to each task item:

    :list :hasTaskItem [ rdf:type :taskItem ;
                         :hasord  1;
                         :hasTask :socks ] ,
                       [ rdf:type :taskItem ;
                         :hasord  2;
                         :hasTask :shoes ] ,
                       [ rdf:type :taskItem ;
                         :hasord  3;
                         :hasTask :leash ] .
    

    The basic idea is the same though. Alternatively, you could use a list. In pure RDF, you can use RDF lists and leave the numbers implicit, like:

    :list :hasTasks ( :socks :shoes :leash ) .
    

    That's just shorthand for

    :list :hasTasks [ rdf:first :socks ;
                      rdf:rest [ rdf:first :shoes ;
                                 rdf:rest [ rdf:first :leash ;
                                            rdf:rest rdf:nil ]]].
    

    In OWL, you can't use rdf:first and rdf:rest, but you can define your own analogous properties and implement the same structures. There's an example of specifying a list class in my answer ot Can I specify a range for rdf:List members? (where someone wanted a list all of whose elements had to be a certain type). If you do take this route, and you want to recover the position of each element in the list, you can actually do it using a SPARQL query over the RDF, as I've described in an answer to Is it possible to get the position of an element in an RDF Collection in SPARQL?.