Representing Time in RDF Part 2
Approach 1: Conditions and Time Slices
Conditions were my invention to model the state of being of an individual at a point in time. They are basically time slices as used in OpenCyc (the original CYC notion of subAbstractions seems to be missing from OpenCyc).
Scenario 1
For this scenario I'm going to create a description of Maria which refers to two conditions to represent her before and after her marriage:
@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 ; bio:condition thing:mariaUnmarried ; bio:condition thing:mariaMarried .
thing:mariaUnmarried foaf:name "Maria Smith" ; time:start "1867" ; time:end "1888" .
thing:mariaMarried foaf:name "Maria Johnson" ; time:start "1888" ; time:end "9999" .
Original file: a1s1.ttl
The URI thing:maria represents Maria the person. thing:mariaUnmarried and thing:mariaMarried are representations of her state of being at various times. Because they are the subjects of foaf:name properties they must be foaf:Agents. They are also the subject of OWL-Time properties which also infers that they are time:Intervals too. This may be a hint that this approach may be flawed: can any foaf:Agent also be an interval of time? They can certainly exist for an interval of time, but is it appropriate to use the OWL-Time properties in this way?
Note that I have simplified this by putting an end year on her married name. A twist here is that even if Maria Johnson died in 1920 she is still known by that name, so realistically that name should hold for an open ended time interval. However, if I left it off then I would not be able to distinguish between her name remaining the same from a point in time onwards and the situation where it is not known when she next changed her name.
I can now write a SPARQL query to find Maria's name in 1891:
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 { thing:maria bio:condition ?x . ?x foaf:name ?name . ?x time:start ?start . ?x time:end ?end . filter (xsd:integer(?start) <= 1891 && xsd:integer(?end) >= 1891) . }
Original file: a1s1.sq
This works well for my simplified situation. If I had an open-ended time interval for her name after her marriage then I would need to add a union clause to this query to match that case. To cover intervals with an known end but unknown start would require still another union block.
Scenario 2
Scenario two is structured in a fairly similar way. I describe two resources as being counties and one as being a parish. Just like the description of Maria the description of Widford refers to two conditions that represent the parish's association with each county.
@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" ; bio:condition thing:widfordInGloucestershire ; bio:condition thing:widfordInOxfordshire .
thing:widfordInGloucestershire ex:partOf thing:gloucestershire ; time:start "1837" ; time:end "1844" .
thing:widfordInOxfordshire ex:partOf thing:oxfordshire ; time:start "1844" ; time:end "2009" .
Original file: a1s2.ttl
My SPARQL query is quite simple. I just need to find the name of the condition that starts in or before 1841 and ends in or after that year.
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 { thing:widford bio:condition ?cond . ?cond time:start ?start . ?cond time:end ?end . ?cond ex:partOf ?x . ?x foaf:name ?name . filter (xsd:integer(?start) <= 1841 && xsd:integer(?end) >= 1841) . }
Original file: a1s2.sq
Scenario 3
I describe resources representing the three places: thing:lymeregis, thing:charmouth and thing:hastings. Then I describe thing:anon which is a person with a condition for each location they have lived in. These conditions are described with an ex:residence property that links the condition to the place and some time properties to describe when the condition applied.
@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 ; bio:condition thing:anonInLymeRegis ; bio:condition thing:anonInCharmouth ; bio:condition thing:anonInHastings .
thing:anonInLymeRegis ex:residence thing:lymeRegis ; time:intervalBefore thing:anonInCharmouth ; time:intervalContains "1844" .
thing:anonInCharmouth ex:residence thing:charmouth ; time:intervalAfter thing:anonInLymeRegis ; time:intervalBefore thing:anonInHastings ; time:intervalContains "1871" .
thing:anonInHastings ex:residence thing:hastings ; time:intervalAfter thing:anonInCharmouth ; time:intervalContains "1881" .
Original file: a1s3.ttl
My SPARQL query needs to find the latest address that contains a date before 1874 and also the address following that one.
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#>Find the latest address that contains a date before 1874
Find the next address
select ?nameBefore ?nameAfter where { thing:anon bio:condition ?condBefore . ?condBefore ex:residence ?resBefore . ?resBefore foaf:name ?nameBefore . ?condBefore time:intervalContains ?dateBefore . filter (xsd:integer(?dateBefore) <= 1874) .
thing:anon bio:condition ?condAfter . ?condAfter ex:residence ?resAfter . ?resAfter foaf:name ?nameAfter . ?condAfter time:intervalContains ?dateAfter . filter (xsd:integer(?dateAfter) > 1874) .
?condBefore time:intervalBefore ?condAfter . }
Original file: a1s3.sq
So this seems to do the job. However I am omitting a major piece of detail: the places will also have conditions similar to those in Scenario 2. That is going to add a huge amount of complexity to the SPARQL query.
Approach 1 Conclusions
This approach seems very workable and there is a large body of philosophical work pertaining to this view of the world. In RDF terms though, there seems to be a problem with the domains of properties. Using the properties as I have done here implies that the "conditions" are both intervals of time and real-world things which seems awkward to me. I could separate the time intervals into new resources linked to the conditions with some kind of "existed during" predicate. This would complicate things a little, but perhaps not too greatly.
This post is part 2 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