How can I express owl:inverseOf in JSON-LD?
Let's say I have the famous Library.jsonld example:
{
"@context": {
"dc11": "http://purl.org/dc/elements/1.1/",
"ex": "http://example.org/vocab#",
"xsd": "http://www.w3.org/2001/XMLSchema#",
"ex:contains": {
"@type": "@id"
}
},
"@graph": [
{
"@id": "http://example.org/library",
"@type": "ex:Library",
"ex:contains": "http://example.org/library/the-republic"
},
{
"@id": "http://example.org/library/the-republic",
"@type": "ex:Book",
"dc11:creator": "Plato",
"dc11:title": "The Republic",
"ex:contains": "http://example.org/library/the-republic#introduction"
},
{
"@id": "http://example.org/library/the-republic#introduction",
"@type": "ex:Chapter",
"dc11:description": "An introductory chapter on The Republic.",
"dc11:title": "The Introduction"
}
]
}
How can I say express that ex:contains is an inverse of ex:containedIn?
Thanks, Radu
owl:inverseOf can be used as with any other property in RDF, but it is used when defining a property to indicate it's semantic relationship to another property.
Within a document, you can achieve something similar without resorting to OWL reasoning using the @reverse keyword (see Reverse Properties).
In this case, you could define a "contains" term using @reverse like so:
{
"@context": {
"dc11": "http://purl.org/dc/elements/1.1/",
"ex": "http://example.org/vocab#",
"xsd": "http://www.w3.org/2001/XMLSchema#",
"contains": {"@reverse": "ex:containedIn", "@type": "@id"}
},
"@graph": [
{
"@id": "http://example.org/library",
"@type": "ex:Library",
"contains": "http://example.org/library/the-republic"
},
{
"@id": "http://example.org/library/the-republic",
"@type": "ex:Book",
"dc11:creator": "Plato",
"dc11:title": "The Republic",
"contains": "http://example.org/library/the-republic#introduction"
},
{
"@id": "http://example.org/library/the-republic#introduction",
"@type": "ex:Chapter",
"dc11:description": "An introductory chapter on The Republic.",
"dc11:title": "The Introduction"
}
]
}
Thought I'd weigh in, as I've wrestled with a similar issue.
If we treat JSON object keys (that are not reserved words for JSON-LD) as OWL properties, we can define a new term with a new JSON-LD object. Note however, that OWL makes a distinction between properties that can be assigned an Object (i.e. owl:ObjectProperty), and ones that can be assigned a Literal (i.e. owl:DatatypeProperty). It's the former you need in this case.
Assuming the ex:containedIn property already exists, you can include a node declaring a new property in OWL and include owl:inverseOf in a node, with a @type of owl:ObjectProperty as follows:
{
"@context": {
"dc11": "http://purl.org/dc/elements/1.1/",
"ex": "http://example.org/vocab#",
"ex:contains": { "@type": "@vocab" },
"xsd": "http://www.w3.org/2001/XMLSchema#",
"owl": "http://www.w3.org/2002/07/owl#",
"owl:inverseOf" : {"@type": "@vocab"}
},
"@graph": [
{
"@id": "http://example.org/vocab#contains",
"@type": "owl:ObjectProperty",
"owl:inverseOf": "ex:containedIn"
},
{
"@id": "http://example.org/library",
"@type": "ex:Library",
"ex:contains": "http://example.org/library/the-republic"
},
{
"@id": "http://example.org/library/the-republic",
"@type": "ex:Book",
"dc11:creator": "Plato",
"dc11:title": "The Republic",
"ex:contains": "http://example.org/library/the-republic#introduction"
},
{
"@id": "http://example.org/library/the-republic#introduction",
"@type": "ex:Chapter",
"dc11:description": "An introductory chapter on The Republic.",
"dc11:title": "The Introduction"
}
]
}
Edit: added namespaces. Thanks @pchampin for the correction. Edit: corrections. Plural.
Your example answers the original question, but in a very different way than @gkellogg's example above. More precisely, running your example through toRdf produces (among others), the following triples, which @gkellogg's example does not produce:
<http://example.org/library> ex:contains <http://example.org/library/the-republic>.
<http://example.org/library/the-republic> ex:contains <http://example.org/library/the-republic#introduction>.
ex:contains owl:inverseOf ex:containedIn.
On the other hand, the following triples are produced by @gkellogg's example, but not by yours:
<http://example.org/library/the-republic> ex:containedIn <http://example.org/library>.
<http://example.org/library/the-republic#introduction> ex:containedIn <http://example.org/library/the-republic>.
Mind you: from your example, one can infer the two triples above, but that requires extra machinery (namely, an OWL2 compliant inference engine) in addition to the JSON-LD processor. Depending on your use-case, that extra machinery might or might not be available, making one or the other approach preferable.
In my particular use case, I wanted objects with references to BOTH ancestors and descendants, but @reverse discarded the inverse predicate. I also wasn't using a triple store, but MongoDB. I thought another may have had a similar use case, so I threw my example out there.
In my particular use case, I wanted objects with references to BOTH ancestors and descendants, but
@reversediscarded the inverse predicate.
Indeed. JSON-LD's expansion maps every JSON key to at most one RDF property.
I also wasn't using a triple store, but MongoDB. I thought another may have had a similar use case, so I threw my example out there.
Absolutely. I thought it was important to underline the differences between the two examples (for future readers), but as I wrote, both have their pros and cons.