Temporale data – deel 1: de concepten
By: gnoij, 19 November 2008In een serie van 4 artikelen wil ik een framework voor gebruik van temporale data presenteren. In dit eerste deel wordt uitgelegd wat temporale data is en wat de consequenties zijn. In de volgende delen wordt het framework in een aantal stappen gepresenteerd.
Een korte introductie in temporale data
Temporale data is data waarbij tijdsaspecten een rol spelen.
Ter illustratie even een voorbeeld van een simpel HRM systeem:
Kees werkte vanaf 1-1-2003 op de afdeling Inkoop. Vanaf 1-1-2006 werkt hij op de afdeling Verkoop. Deze overgang werd op 1-2-2006 geregistreerd in het systeem.
Schematisch ziet dat er als volgt uit:
Uit bovenstaand voorbeeld blijkt dat de tijdsaspecten die een rol kunnen spelen zijn: een ingangsdatum, een einddatum en een registratiedatum. Welke tijdaspecten voor de te ontwikkelen applicatie een rol spelen hangt af van de vragen die de applicatie moet kunnen beantwoorden.
De mogelijke vragen met betrekking tot de tijdsaspecten in bovenstaand voorbeeld zijn:
- Waar werkt Kees nu?
- Sinds wanneer werkt Kees op de afdeling Verkoop?
- Gedurende welke periode werkte Kees op de afdeling Inkoop?
- Op welke afdeling werkte Kees op 15-1-2006 als we keken in het systeem op 15-1-2006?
Om elke vraag te kunnen beantwoorden heb je andere tijdsaspecten nodig.
Vraag 1 kun je beantwoorden zonder extra tijdsgegevens op te slaan.Vraag 2 kun je beantwoorden door een ingangsdatum te gebruiken.Voor vraag 3 heb je een ingangsdatum en een einddatum nodig en voor vraag 4 heb je naast de ingangs- en einddatum ook registratiedata nodig.
Om de vragen 2, 3 en 4 ook voor het verleden te kunnen beantwoorden moet er ook historie van de data worden bijgehouden. Dat betekent dat elke wijziging leidt tot een nieuw record in de database.
De historievormen met geldigheid (een ingangsdatum en een einddatum) noemen we temporale data en met geldigheid en registratiedata bitemporale data.
temporale data
Bij temporale data hebben we te maken met de tijdsaspecten ingangsdatum en einddatum. Willen we ook historie gaan bijhouden, moeten de wijzigingen op een temporal object leiden tot een nieuw record in de database. Dat betekent dat een object in principe immutable is. Wijzigingen op een object leiden altijd tot een nieuw object.
In principe onderscheiden we drie situaties: inschrijving, wijziging en beëindiging van de data.
Bij inschrijving wordt er een record aan een tabel toegevoegd in de database toegevoegd. Voor ons voorbeeld ziet dat er als volgt uit:
De FK kolom wijst naar de tabel Werknemer met Primary Key 1.
Voor een wijziging wordt er een nieuw record in de tabel geschreven, en wordt het vorige record afgesloten met een einddatum.
Tenslotte voor een beëindiging wordt het actuele record afgesloten met een einddatum. Als in het voorbeeld Kees uit dienst gaat op 1-1-2008 krijgen we de volgende records te zien.
We kunnen nu de vragen 1 tot en met 3 beantwoorden, maar niet vraag 4.
Antwoorden:
- Nergens, want Kees is per 1-1-2008 uit dienst.
- Sinds 1-1-2006 werkte Kees op de afdeling Verkoop
- Tussen 1-1-2003 en 1-1-2006 werkte Kees op de afdeling Inkoop
- Op 15-1-2006 wisten wij dat Kees op de afdeling Verkoop werkte. (Terwijl het systeem dit pas op 1-2-2006 heeft geregistreerd, dus is het antwoord fout. Dit moet Inkoop zijn)
bitemporale data
Zoals uit bovenstaande records blijkt kunnen we niet achterhalen wanneer iets is geregistreerd. Of wanneer de organisatie wist wanneer een wijziging is doorgevoerd. In sommige (vooral juridische) situaties is dit wel nodig. Hiervoor moeten we de geldigheid uitbreiden met registratiedata voor opvoer en afvoer. Dit noemen we bitemporale data
We kunnen dezelfde drie situaties als bij temporale data onderscheiden: inschrijving, wijziging en beëindiging.
Bij inschrijving wordt er een record aan de database toegevoegd. Dit is te zien in onderstaande tabel.
Hierbij zijn de kolommen Opvoer en Afvoer toegevoegd aan de tabel.
Bij wijziging wordt het eerste record afgesloten, wordt er een kopie gemaakt met einddatum en wordt de wijziging toegevoegd.
Per wijziging wordt dus (naast de wijziging) een extra record in de database toegevoegd met de oorspronkelijke informatie plus een afvoerdatum.
Bij beëindiging wordt een kopie gemaakt van het actuele record, de actuele versie krijgt een afvoerdatum en de kopie krijgt een einddatum.
Ook voor beëindiging wordt een extra record toegevoegd met de oorspronkelijke informatie plus een afvoerdatum.
Met het gebruik van zowel geldigheid als registratiedata is ook vraag 4 juiste te beantwoorden. Door te zoeken naar het record dat opgevoerd is voor 15-1-2006 en niet voor die datum is afgevoerd zien we dat het juiste antwoord Inkoop is.
Mogelijke oplossingen
Mogelijke oplossingsrichtingen voor de bouw van applicaties met (bi)temporale data zijn:
- Temporale databases en SQL/Temporal (o.a. Oracle Flashback en TimeDB)
- Gebruik van SQL code (zie o.a. http://www.cs.arizona.edu/people/rts/tdbbook.pdf)
- Maatwerk oplossing in (Java) code (o.a. via de Temporal patterns van Martin Fowler)
Het framework dat ik in de volgende artikelen wil presenteren is gebaseerd op de maatwerkoplossing, waarbij gebruik wordt gemaakt van de Temporal patterns van Fowler.
Dit framework bestaat uit patterns voor temporale data en bitemporale data. In het volgende artikel zal ik patterns voor temporale data presenteren. Het derde deel zal patterns voor bitemporale data behandelen en in het (voorlopig) laatste deel zullen we deze patterns uitbreiden voor collections.








20 November 2008 om 9:30 pm
Temporale data is inderdaad altijd een priegelwerk. Ik ben benieuwd wat je voor oplossing bedacht hebt om het gemakkelijker te maken.
25 November 2008 om 9:05 pm
Interessant onderwerp. Temporale data is typisch een aspect wat na verloop van tijd (lees: bij veranderende requirements) sterk in complexiteit kan toenemen. Ben benieuwd naar de mogelijkheden om hiermee om te gaan.
30 November 2008 om 11:26 am
Binnen de basisregistratie BAG hebben we een volledig historiemodel, incl. historie over meerdere tabellen heen. Er zijn een paar implementaties mogelijk, afhankelijk van het aantal betrokken tabellen.
Belangrijke aandachtspunten voor modelleren en implementeren van historie:
- Scheiding mutatieomgeving en verstrekking omgeving
- OO vs ER
- Audittrail
- Key management (let op backup/restore/rollforward)
- Sneeuwbaleffecten bij meer dan 2 betrokken entiteiten / tabellen
- Hoe mutaties doorgeven aan andere systemen
7 December 2008 om 12:32 pm
[...] al in het eerste deel te zien was is temporale data op te delen in temporale (alleen geldigheid) of bitemporale data [...]
7 December 2008 om 12:41 pm
Binnen het project waar we dit gebruiken heeft elke (historische) klasse zijn eigen lifecycle en dus zijn eigen historie. En houden we inderdaad rekening met een audittrail en het doorgeven van mutaties aan andere systemen (deze kunnen zich abonneren op ’soorten wijzigingen’).
Dit soort aspecten vallen buiten de scope van deze blog. Hier presenteer ik alleen de kern van de temporale patterns.
22 December 2008 om 1:20 pm
[...] Het verschil van de BiTemporalProperty met de TemporalProperty is dat er nu twee tijdstippen worden meegegeven om de juiste versie te bepalen. Naast de peildatum is dat ook het registratietijdstip. Als er een actuele versie wordt toegevoegd of beëindigd, wordt de op dat moment geldende versie gekopieerd en afgevoerd. De gekopieerde versie wordt beëindigd. Hierdoor zal er altijd bij beëindiging of wijziging een extra record ontstaan. Dit wordt verklaard in de concepten voor bitemporale data in deel 1. [...]
30 December 2008 om 1:05 pm
[...] Auditing is een van de belangrijkste onderdelen in ieder systeem. Er zijn al enkele manieren om dit te regelen. Het makkelijkste is een audit log, Gerry Noij is nu bezig met het beschrijven van het temporal object pattern. [...]
7 December 2009 om 12:36 pm
[...] is alweer enige tijd geleden dat ik heb geschreven over temporale patterns. In dit voorlopig laatste deel wil ik het bitemporale pattern uitbreiden met bitemporale [...]