Representing Time in RDF Part 5
<h2>Approach 4: N-ary Relations</h2>
In this approach a new class is created for each time-dependent predicate. This new class represents the context of the property and allows more specific predicates to be used that provide extra meaning.
Scenario 1
In the first scenario we use a new ex:NameInContext class. This provides two predicates ex:individual and ex:name to link an individual to a name in a particular context.
@prefix bio: <http://purl.org/vocab/bio/0.1/> . @prefix foaf: <http://xmlns.com/foaf/0.1/> . @prefix time: <http://www.w3.org/2006/time#> . @prefix ex: <http://example.org/ex#> . @prefix thing: <http://example.org/thing#> .thing:maria a foaf:Person .
thing:mariaUnmarried a ex:NameInContext ; ex:individual thing:maria ; ex:name "Maria Smith" ; time:start "1867" ; time:end "1888" .
thing:mariaMarried a ex:NameInContext ; ex:individual thing:maria ; ex:name "Maria Johnson" ; time:start "1888" ; time:end "9999" .
Original file: a4s1.ttl
The query is very similar to that in Approach 3:
prefix bio: <http://purl.org/vocab/bio/0.1/> prefix foaf: <http://xmlns.com/foaf/0.1/> prefix time: <http://www.w3.org/2006/time#> prefix xsd: <http://www.w3.org/2001/XMLSchema#> prefix ex: <http://example.org/ex#> prefix thing: <http://example.org/thing#>select ?name where { ?p a ex:NameInContext . ?p ex:individual thing:maria . ?p time:start ?start . ?p time:end ?end . ?p ex:name ?name . filter (xsd:integer(?start) <= 1891 && xsd:integer(?end) >= 1891) . }
Original file: a4s1.sq
Scenario 2
For this scenario I use a class to represent the part-of relationship with two new predicates: ex:part and ex:whole. Once again, for simplicity I assume the place name information is timeless.
@prefix bio: <http://purl.org/vocab/bio/0.1/> . @prefix foaf: <http://xmlns.com/foaf/0.1/> . @prefix time: <http://www.w3.org/2006/time#> . @prefix ex: <http://example.org/ex#> . @prefix thing: <http://example.org/thing#> .thing:oxfordshire a ex:County ; foaf:name "Oxfordshire" .
thing:gloucestershire a ex:County ; foaf:name "Gloucestershire" .
thing:widford a ex:Parish ; foaf:name "Widford" .
thing:widfordInGloucestershire a ex:PartOfContext ; ex:part thing:widford ; ex:whole thing:gloucestershire ; time:start "1837" ; time:end "1844" .
thing:widfordInOxfordshire a ex:PartOfContext ; ex:part thing:widford ; ex:whole thing:oxfordshire ; time:start "1844" ; time:end "9999" .
Original file: a4s2.ttl
The query here looks like:
prefix bio: <http://purl.org/vocab/bio/0.1/> prefix foaf: <http://xmlns.com/foaf/0.1/> prefix time: <http://www.w3.org/2006/time#> prefix xsd: <http://www.w3.org/2001/XMLSchema#> prefix ex: <http://example.org/ex#> prefix thing: <http://example.org/thing#>select ?name where { ?p a ex:PartOfContext . ?p ex:part thing:widford . ?p ex:whole ?x . ?p time:start ?start . ?p time:end ?end . ?x foaf:name ?name filter (xsd:integer(?start) <= 1841 && xsd:integer(?end) >= 1841) . }
Original file: a4s2.sq
Scenario 3
For the final scenario I use ex:ResidenceContext to represent the context of someone being resident somewhere. The person and the place are referred to using new predicates ex:individual and ex:place:
@prefix bio: <http://purl.org/vocab/bio/0.1/> . @prefix foaf: <http://xmlns.com/foaf/0.1/> . @prefix time: <http://www.w3.org/2006/time#> . @prefix ex: <http://example.org/ex#> . @prefix thing: <http://example.org/thing#> .thing:lymeRegis a ex:Town ; foaf:name "Lyme Regis" .
thing:charmouth a ex:Town ; foaf:name "Charmouth" .
thing:hastings a ex:Town ; foaf:name "Hastings" .
thing:anon a foaf:Person .
thing:anonInLymeRegis a ex:ResidenceContext ; ex:individual thing:anon ; ex:place thing:lymeRegis ; time:intervalBefore thing:anonInCharmouth ; time:intervalContains "1844" .
thing:anonInCharmouth a ex:ResidenceContext ; ex:individual thing:anon ; ex:place thing:charmouth ; time:intervalAfter thing:anonInLymeRegis ; time:intervalBefore thing:anonInHastings ; time:intervalContains "1871" .
thing:anonInHastings a ex:ResidenceContext ; ex:individual thing:anon ; ex:place thing:hastings ; time:intervalAfter thing:anonInCharmouth ; time:intervalContains "1881" .
Original file: a4s3.ttl
Once again the query is very similar to that in Approach 3:
prefix bio: <http://purl.org/vocab/bio/0.1/> prefix foaf: <http://xmlns.com/foaf/0.1/> prefix time: <http://www.w3.org/2006/time#> prefix xsd: <http://www.w3.org/2001/XMLSchema#> prefix ex: <http://example.org/ex#> prefix thing: <http://example.org/thing#>select ?nameBefore ?nameAfter where { ?pBefore a ex:ResidenceContext . ?pBefore ex:individual thing:anon . ?pBefore ex:place ?placeBefore . ?placeBefore foaf:name ?nameBefore .
?pBefore time:intervalContains ?dateBefore . filter (xsd:integer(?dateBefore) <= 1874) .
?pAfter a ex:ResidenceContext . ?pAfter ex:individual thing:anon . ?pAfter ex:place ?placeAfter . ?placeAfter foaf:name ?nameAfter .
?pAfter time:intervalContains ?dateAfter . filter (xsd:integer(?dateAfter) > 1874) .
?pBefore time:intervalBefore ?pAfter . }
Original file: a4s3.sq
Approach 4 Conclusions
In the examples shown here Approach 4 is identical to Approach 3 in complexity. In fact the key difference is the use of rdf:type rather than ex:property to distinguish the different types of relationships. In this respect it seems to offer no advantage over Approach 3 and adds the complexity of specific property names for each context relationship.
However, it does potentially offer a wider use beyond simply recording time-varying properties. A context could include other factors such as provenance or location. Also it could be easier to model multi-agent contexts such as a marriages with predicates to represent the bride and groom separately. For example:
thing:marriage a ex:MarriedContext ; ex:husband thing:person1 ; ex:wife thing:person2 ; time:start "1820" ; time:end "1862" .
This post is part 5 of a series about representing time in RDF. All posts in this series: part 1, part 2, part 3, part 4, part 5 and part 6