Historisierung von Daten in der Versicherungswirtschaft
Dieser Beitrag beschreibt die Historisierung von Daten in der Versicherungswirtschaft. Dort müssen vergangenheitsbezogenen Vertragsänderungen z. B. für die Prüfung von Deckungsansprüchen bei Schadenmeldungen herangezogen werden. Zu diesem Zweck muss der rechtliche Stand der Bestandsdaten zu einem beliebigen Zeitpunkt wiederhergestellt werden können.
Dieses Festhalten der zeitlichen Entwicklung der Daten wird auch temporale Datenhaltung genannt.
Der Änderungsbaum der Daten entsteht durch das Aufzeichnen der Änderungen in Gültigkeitsabschnitten (Beginn- und Endzeitpunkte, Gültigkeitszeit). Diese Abschnitte können auf einer Zeitlinie aneinandergereiht dargestellt werden und bilden damit einen Pfad zum Zeitpunkt t1.
Die rückwirkende Änderung eines alten Zustands der Daten erzeugt eine neue Zeitlinie als Zweig zum Zeitpunkt t2.
Keine Historisierung von Daten (Ohne Zeitbezug)
In diesem Abschnitt wird der einfachste Fall der Historisierung beschrieben:
Bestandsdaten ohne Historie oder Non-temporal.
Es wird nur der letzte Zustand t2 der Daten zu einem beliebigen Zeitpunkt gespeichert. Der vorletzte Zustand zum Zeitpunkt t1 der Daten wird überschrieben und geht somit endgültig verloren.
Eindimensionale Historisierung von Daten (Abschnittshistorie)
In diesem Abschnitt wird der nächste Fall der Historisierung beschrieben:
Die eindimensionale Historisierung oder Actual Temporal.
Es werden nur die Änderungen der Zustände der Daten in einem einzelnen Pfad gespeichert. Bei einer rückwirkenden Änderung zum Zeitpunkt t2 geht der alte Pfad verloren.
Zwischen den Gültigkeitsabschnitten sind Lücken erlaubt, während Überschneidungen nicht erlaubt sind. Somit gilt für einen Zeitpunkt t:
GUELTIG_AB <= t < GUELTIG_BIS
Dieses beschreibt die fachliche Gültigkeit eines Zustandes der Daten. Hierbei reicht in der Regel Tagesgenauigkeit (DATE
) aus.
Bei einer lückenlosen Abschnittshistorie könnte auf das Attribut GUELTIG_BIS
verzichtet werden. Aber bei einem relationalen Datenbanksystem sollten die einzelnen Datensätze voneinander unabhängig sein.
Der Schlüssel der Daten setzt sich aus der Id der Daten (z. B. Vertragsnummer) und des Attributs GUELTIG_BIS
zusammen.
PRIMARY KEY (ID, GUELTIG_AB)
Das Attribute GUELTIG_BIS
wird auch zur Sortierung der Zustandsabfolge der Daten verwendet.
ORDER BY GUELTIG_BIS DESC
Beispiel der eindimensionalen Historisierung von Daten
Am 03.03. wird ein Versicherungsvertrag angelegt. Dieser Vertrag ist ab dem 01.03. (Vertragsbeginn) unbegrenzt wirksam.
ID | STATUS | GUELTIG_AB | GUELTIG_BIS | VERTRAGSATTRIBUTE |
---|---|---|---|---|
1 | N | 01.03. | NULL | 100… |
In der Spalte STATUS
steht N
für normal gültiger Datensatz und in der Spalte GUELTIG_BIS
wird NULL
für unbegrenzt gültig eingetragen.
Am 26.03. wird der Vertrag mit Wirkung zum 01.04. geändert.
ID | STATUS | GUELTIG_AB | GUELTIG_BIS | VERTRAGSATTRIBUTE |
---|---|---|---|---|
1 | N | 01.03. | 01.04. | 100… |
1 | N | 01.04. | NULL | 200… |
Am 27.03. wird der Vertrag geändert, diesmal mit Wirkung zum 01.05.
ID | STATUS | GUELTIG_AB | GUELTIG_BIS | VERTRAGSATTRIBUTE |
---|---|---|---|---|
1 | N | 01.03. | 01.04. | 100… |
1 | N | 01.04. | 01.05. | 200… |
1 | N | 01.05. | NULL | 250… |
Am 02.04. wird der Vertrag rückwirkend geändert, diesmal mit Wirkung zum 15.03.
ID | STATUS | GUELTIG_AB | GUELTIG_BIS | VERTRAGSATTRIBUTE |
---|---|---|---|---|
1 | N | 01.03. | 15.03. | 100… |
1 | N | 15.03. | NULL | 300… |
Am 02.04. wird der Vertrag mit Wirkung zum 01.06. aufgehoben. Der gelöschte Datensatz existiert über das Löschdatum 01.06. hinaus, damit er ggf. storniert werden kann.
Für die Löschung wird kein neuer Datensatz geschrieben.
ID | STATUS | GUELTIG_AB | GUELTIG_BIS | VERTRAGSATTRIBUTE |
---|---|---|---|---|
1 | N | 01.03. | 15.03. | 100… |
1 | L | 15.03. | 01.06. | 300… |
Im letzten Datensatz wird die Spalte STATUS
auf L
für gelöscht gesetzt und zusätzlich das Datum in die Spalte GUELTIG_BIS
geschrieben.
Die endgültige Löschung des Vertrages geschieht am 02.05. durch einen automatischen Prozess (Batch).
Auch bei der endgültigen Löschung wird kein neuer Datensatz geschrieben. Der Vertrag wird aus Dokumentationszwecken weiterhin aufbewahrt – somit findet auch keine physische Löschung (DELETE
) in der Datenbank statt.
ID | STATUS | GUELTIG_AB | GUELTIG_BIS | VERTRAGSATTRIBUTE |
---|---|---|---|---|
1 | N | 01.03. | 15.03. | 100… |
1 | E | 15.03. | 01.06. | 300… |
Im letzten Datensatz wird nun die Spalte STATUS
auf E
für endgültig gelöscht gesetzt.
Zweidimensionale Historisierung von Daten (Vollständige Historisierung, Vollprotokollierung)
In diesem Abschnitt wird der letzte Fall der Historisierung beschrieben:
Die zweidimensionale Historisierung oder Bitemporal.
Es werden alle Änderungen der Zustände der Daten in allen Pfaden gespeichert. Die eindimensionale Historisierung ist ein Spezialfall der zweidimensionalen Historisierung.
Gegenüber diesem Spezialfall muss zusätzlich eine Aussage über die Gültigkeit eines Zustandes der Daten in der Datenbank (Kenntnisstand, Record Temporal) vorgenommen werden. Auch hier gilt für einen Zeitpunkt t:
KENNTNIS_AB <= t < KENNTNIS_BIS
Allerdings ist hier eine höhere Genauigkeit (TIMESTAMP
) gefordert, da an einem Tag mehrere Änderungen (zu verschiedenen Zeitpunkten) vorgenommen werden können.
Beispiel der zweidimensionalen Historisierung von Daten
Am 03.03. wird ein Versicherungsvertrag angelegt. Dieser Vertrag ist ab dem 01.03. (Vertragsbeginn) unbegrenzt wirksam.
ID | STATUS | GUELTIG_AB | GUELTIG_BIS | KENNTNIS_AB | KENNTNIS_BIS | VERTRAGSATTRIBUTE |
---|---|---|---|---|---|---|
1 | N | 01.03. | NULL | 03.03. 10:00 | NULL | 100… |
In der Spalte STATUS
steht N
für normal gültiger Datensatz und in der Spalte GUELTIG_BIS
sowie KENNTNIS_BIS
ist NULL
für unbegrenzt gültig eingetragen.
Am 26.03. wird der Vertrag mit Wirkung zum 01.04. geändert. Der neue Zustand des Vertrages überlagern die vorhandenen Zustände. Die nicht überlagerten Teile des Gültigkeitsabschnitts sind gültig.
ID | STATUS | GUELTIG_AB | GUELTIG_BIS | KENNTNIS_AB | KENNTNIS_BIS | VERTRAGSATTRIBUTE |
---|---|---|---|---|---|---|
1 | N | 01.03. | NULL | 03.03. 10:00 | 26.03. 14:30 | 100… |
1 | N | 01.04. | NULL | 26.03. 14:30 | NULL | 200… |
In der Spalte GUELTIG_BIS
wird in diesem Beispiel immer NULL
eingetragen, da keine Änderung zeitlich begrenzt ist und immer unbegrenzt gültig ist.
Am 27.03. wird der Vertrag wieder geändert, diesmal mit Wirkung zum 01.05. Es entsteht eine Treppe.
ID | STATUS | GUELTIG_AB | GUELTIG_BIS | KENNTNIS_AB | KENNTNIS_BIS | VERTRAGSATTRIBUTE |
---|---|---|---|---|---|---|
1 | N | 01.03. | NULL | 03.03. 10:00 | 26.03. 14:30 | 100… |
1 | N | 01.04. | NULL | 26.03. 14:30 | 27.03. 09:15 | 200… |
1 | N | 01.05. | NULL | 27.03. 09:15 | NULL | 250… |
Am 02.04. wird der Vertrag rückwirkend geändert, diesmal mit Wirkung zum 15.03.
ID | STATUS | GUELTIG_AB | GUELTIG_BIS | KENNTNIS_AB | KENNTNIS_BIS | VERTRAGSATTRIBUTE |
---|---|---|---|---|---|---|
1 | N | 01.03. | NULL | 03.03. 10:00 | 26.03. 14:30 | 100… |
1 | N | 01.04. | NULL | 26.03. 14:30 | 27.03. 09:15 | 200… |
1 | N | 01.05. | NULL | 27.03. 09:15 | 02.04. 07:30 | 250… |
1 | N | 15.03. | NULL | 02.04. 07:30 | NULL | 300… |
Am 02.04. wird der Vertrag abermals mit Wirkung zum 01.06 aufgehoben. Der gelöschte Datensatz existiert auch über das Löschdatum 01.06. weiter, damit er ggf. storniert werden kann.
ID | STATUS | GUELTIG_AB | GUELTIG_BIS | KENNTNIS_AB | KENNTNIS_BIS | VERTRAGSATTRIBUTE |
---|---|---|---|---|---|---|
1 | N | 01.03. | NULL | 03.03. 10:00 | 26.03. 14:30 | 100… |
1 | N | 01.04. | NULL | 26.03. 14:30 | 27.03. 09:15 | 200… |
1 | N | 01.05. | NULL | 27.03. 09:15 | 02.04. 07:30 | 250… |
1 | N | 15.03. | NULL | 02.04. 07:30 | 02.04. 17:45 | 300… |
1 | L | 01.06 | NULL | 02.04. 17:45 | NULL | 300… |
Im neuen Datensatz wird die Spalte STATUS
auf L
für gelöscht gesetzt.
Die endgültige Löschung des Vertrags geschieht am 02.05. durch einen automatischen Prozess (Batch).
ID | STATUS | GUELTIG_AB | GUELTIG_BIS | KENNTNIS_AB | KENNTNIS_BIS | VERTRAGSATTRIBUTE |
---|---|---|---|---|---|---|
1 | N | 01.03. | NULL | 03.03. 10:00 | 26.03. 14:30 | 100… |
1 | N | 01.04. | NULL | 26.03. 14:30 | 27.03. 09:15 | 200… |
1 | N | 01.05. | NULL | 27.03. 09:15 | 02.04. 07:30 | 250… |
1 | N | 15.03. | NULL | 02.04. 07:30 | 02.04. 17:45 | 300… |
1 | L | 01.06 | NULL | 02.04. 17:45 | 02.05. 00:00 | 300… |
1 | E | 01.06. | NULL | 02.05. 00:00 | NULL | 300… |
Im neuen Datensatz wird die Spalte STATUS
auf E
für endgültig gelöscht gesetzt.
Alternative: Event-Sourcing
Eine Alternative bietet das Event-Sourcing (ES). Bei diesem Verfahren wird nicht der komplette Zustand eines fachlichen Geschäftsobjektes (Entität) festgehalten. Sondern es werden alle Änderungen (Events) einer Entität aufbewahrt. Die Änderungen werden chronologisch ihres Auftretens gespeichert und bilden den Event-Stream dieser Entität. Dadurch entsteht die gewünschte Historie der Entität (Event-Log und zusätzlich ein Audit-Log).
Event
Ein Event ist immutable. Aus diesem Grund sind in einer Persistenz nur lesende und schreibende Zugriffe von Nöten. Auf die destruktiven Zugriffe löschen und ändern wird verzichtet. Bei den destruktiven Zugriffen gehen die vorherigen Zustände verloren.
Ein Event wird in der Regel mit einigen Attributen angereichert:
- Wann aufgetreten (Gültig ab)
- Wann bemerkt (Kenntnis ab)
- Wer hat es bearbeitet
- Betroffene Geschäftslogik
- Type des Events
- …
Diese Art der Speicherung ist extrem schnell, da nur neue Datensätze angelegt bzw. Datensätze selektiert werden. Für den lesenden Zugriff können die Verfahren Caching oder Snapshots verwendet werden. Das Caching hält den Event-Stream vor und der Snapshot speichert den Zustand einer Entität. Die Snapshots können regelmäßig gebildet werden. Z. B. nach einer Anzahl von neuen Events oder zu definierten Zeitpunkten (z. B. Monatsende).
Event-Stream
Die folgenden Aktionen sind auf dem Event-Stream möglich:
Complete Rebuild
Der aktuelle Zustand einer Entität wird aus dem chronologischen Abarbeiten des kompletten Event-Streams neu erstellt. Der so gewonnene Zustand sollte als Snapshot gespeichert werden.
Event Reply
Ausgehen von einem Snapshot werden alle neueren Events chronologisch angewendet und der aktuelle Zustand der Entität gebildet.
Temporal Query
Es wird ein Snapshots zu einem Zeitpunkt gebildet, in dem der Event-Stream entweder vom Anfang oder ab einem Snapshots bis zum Zeitpunkt abgearbeitet wird.
Reversing Event
Durch ein Reversing-Event kann ein vorheriger fehlerhafter Event wieder rückgängig gemachte werden. Dazu müssen Event aber einen Unterschied beschreiben und nicht ein Ergebnis. In Form des Differenzansatzes: „Erhöhe um 10“ statt „Setze auf 110“.
Weiterführende Links zur Historisierung von Daten
Nachfolgend eine Liste von weiterführenden Links auf zusätzliche Informationsquellen.
- Automatische Historisierung von Daten mit Hibernate und Evers.
- Beschreibung der temporale Datenhaltung bei Wikipedia.
- Artikel Temporale Datenhaltung in der Praxis mit Java bei Heise Online.
Die Literaturempfehlung
- Wer ist der optimale Java Bean Mapper? - Freitag, 22. September 2023
- Spring Boot Webanwendung: Die ersten Schritte (Tutorial) - Montag, 28. März 2016
- Mainframe-Zugriff via Java - Sonntag, 04. Mai 2014
Hinterlasse einen Kommentar
An der Diskussion beteiligen?Hinterlasse uns deinen Kommentar!