4.3.1.2  Bi-Temporale Dokumente

Wenn wir zwischen der Zeit in der das Dokument, bspw. ein Vetrag in der DB angelegt wird, und der Zeit in der ein Vetrag zwischen zwei Vetragspartnern abgeschlossen wird unterscheiden, dann betrachten wir zwei Zeitachsen.
  • die gültige Zeit (Valid Time)
  • die Systemzeit (System Time)
Für die Vetragspartner ist nur die gültige Zeit relevant. Das Zeitfenster zwischen gültiger Zeit und Systemzeit ist jedoch in manchen Fällen ausschlaggebend.
Bsp: Kürzlich wurde meine Geldbörse mit meinem Perso geklaut. Beim Austellen eines vorläufigen Ausweises wurde ich schriftlich darauf hingewiesen, dass nun mein Perso bei Interpol zur Fahndung ausgeschrieben ist.
Kurze Zeit später fand ein netter Herr die Geldbörse (ohne Geld aber mit allen Papieren) in seinem Garten. Bei einer anschliessenden Busfahrt mit einem Fernbus, wurde ich bei einer Zollkontrolle festgehalten, da das System der Polizei noch nicht aktualisiert war.
Ich nehme an, dass nach meiner Unschuldsbekundung der Vorgang auch auf Seiten des Polizeicomputers aktualisiert wurde. Nun könnte man zwei Fragen stellen:
1.

Ist das Festhalten seitens der Zollbeamten rechtens?

2.

Habe ich mich durch ein verspätetes Anzeigen des Funds schuldig gemacht?

Hinweis
NOTIZ
Beachte, dass man diese Fragen auch noch nach 10 Jahren stellen könnte und das - bei meinem Pech in diesen Angelegenheiten - so ein Vorfall auch noch öfters passieren könnte...
Um diese Fragen zu beantworten, müsste unsere Datenbank in der Lage sein, eine bitemporale Query ↗↗ auszuführen. Zunächst registerieren wir den Vorgang des Persoverlustes in unserer Marklogic Datenbank:
Hinweis
NOTIZ
Da wir hier auf einer XML Datenbank arbeiten, sprechen wir von einem Dokument, wenn wir einen Datensatz meinen.
Der Datensatz bzw. das Dokument wird nicht aktualisiert, sondern stattdessen das Dokument mit den aktualisierten Daten in einer neuen Version angelegt.
Auf diese Weise bleibt die Änderungshistorie erhalten.
xquery version "1.0-ml";
import module namespace temporal = 
       "http://marklogic.com/xdmp/temporal" at "/MarkLogic/temporal.xqy";   
let $root :=    
  <vorgang>     
    <perso-id>XYZ</perso-id>    
    <name>Alex Düsel</name>   
    <status>gestohlen</status>
  </vorgang>
let $options :=   
  <options xmlns="xdmp:document-insert">     
    <metadata>        
      <map:map xmlns:map="http://marklogic.com/xdmp/map">          
        <map:entry key="validStart">            
	  <map:value>2019-02-01T08:23:11</map:value>          
	</map:entry>          
	<map:entry key="validEnd">            
	  <map:value>9999-12-31T11:59:59Z</map:value>          
	</map:entry>         
      </map:map>    
    </metadata>  

return  temporal:document-insert("/perso-verluste", 
                                 "duesel_alex_270774.xml", 
                                 $root, $options)
Unser Enddatum liegt in ferner Zukunft sicherzustellen, dass der Vorgang auf unbestimmte Zeit im System bleibt.
Drei Tage später hatte ich meinen Ausweis wieder und der Vorgang wurde vier Tage später, mit dem Status "gefunden" im Polizeicomputer aktualisiert:
xquery version "1.0-ml";
import module namespace temporal = 
       "http://marklogic.com/xdmp/temporal" at "/MarkLogic/temporal.xqy";   
let $root :=    
  <vorgang>     
    <perso-id>XYZ</perso-id>    
    <name>Alex Düsel</name>   
    <status>gefunden</status>
  </vorgang>
let $options :=   
  <options xmlns="xdmp:document-insert">     
    <metadata>        
      <map:map xmlns:map="http://marklogic.com/xdmp/map">          
        <map:entry key="validStart">            
	  <map:value>2019-02-06T08:00:00<map:value>          
	</map:entry>          
	<map:entry key="validEnd">            
	  <map:value>9999-12-31T11:59:59Z</map:value>          
	</map:entry>         
      </map:map>    
    </metadata>  

return  temporal:document-insert("/perso-verluste", 
                                 "duesel_alex_270774.xml", 
                                 $root, $options)
Nach der Aktualisierung enthält unsere Datenbank logisch gesehen drei Dokumente zu diesem Vorgang, die über eine Query gesucht werden können:
1.

Das Originaldokument, es ist vom 1.2.2019 bis zum 5.2.2019 im System aktiv

2.

Die Aktualisierung, sie ist ab dem 6.2.2019 aktiv

3.

Ein "Split"-Dokument, das aus der verspäteten Aktualisierung resultiert. Es ist ab dem 6.2.2019 im System aktiv, und zeigt den Zeitraum über einen Tag, vom 4.2.2019 bis 5.2.2019 - in dem ich ohne Perso registriert war, ihn aber tatsächlich schon wieder hatte.

Im Gegensatz zu einer herkömmlichen Datenhaltung, bei der ein Datensatz aktualisiert wird - ggf. noch eine neue Version angelegt wird - wird beim Dokument-basierten Ansatz mit bi-temporaler Datenhaltung jede Transaktion separat abgespeichert.
Das ist vergleichbar mit einer Simulation des tatsächlichen Papierverkehrs bei buchhalterischen Tätigkeiten.
Die Abfrage so einer Datenbank ist dadurch nicht einfacher. Drei Queries, die jeweils eines dieser drei Dokumente zurückgeben, könnten bspw. so aussehen:
Rückgabe des Originals
xquery version "1.0-ml";
cts:search(fn:doc(), cts:period-range-query(
  "system",     
  "ISO_CONTAINS",     
  cts:period(xs:dateTime("2019-02-02T00:00:00"),                
             xs:dateTime("2019-02-03T23:59:59")) )
Hier wird geprüft, ob ein Dokument im System aktiv war, dass den Zeitraum vom 2.3. bis zum 3.3. umfasste ( ISO_CONTAINS ). Diese Query ist erfolgreich und gibt das Original-Dokument des Vorgangs zurück: In diesem Zeitraum war ich also mit gestohlenem Perso registriert.
Rückgabe des Split-Dokuments
xquery version "1.0-ml";
cts:search(fn:doc(), cts:period-range-query(
   "valid",
   "ALN_FINISHES",
   cts:period(xs:dateTime("2019-02-06T08:00:00"),
              xs:dateTime("2019-02-06T08:00:00")) ))
Bei dieser Query wird geprüft, ob es ein Dokument gibt, dass zu einem bestimmten Datum auf inaktiv gesetzt wurde ( ALN_FINISHES ) - Das Split-Dokument wird automatisch auf inaktiv gesetzt, wenn die neue Version angelegt wird. Unser Suchdatum wäre also folgendes 2019-02-06T08:00:00 .
Rückgabe von Split und neuer Version
xquery version "1.0-ml";
cts:search(fn:doc(), cts:period-range-query(
   "system",
   "ALN_AFTER",
   cts:period(xs:dateTime("2019-02-05T11:00:00"),
              xs:dateTime("2019-02-05T11:20:00")) ))
Hier wird geprüft ob es Dokumente gibt, die nach einer bestimmten Zeitspanne im System aktiv waren. Man beachte hier, dass eine Periode angegeben ist, obwohl nur ein Datum notwendig wäre. Der Vergleichsoperator hierzu heisst ALN_AFTER .
Rückgabe von aktueller Version
xquery version "1.0-ml";
cts:search(fn:doc(), cts:period-compare-query(
   "system",
   "ISO_CONTAINS",
   "valid" ))
Die aktuelle Version kann in Erfahrung gebracht werden, indem geprüft wird, welche gültigen Dokumente innerhalb der Systemzeitspanne liegen. Das kann nur die aktuelle Version sein. Frühere gültige Versionen und Split-Dokumente wären vor der Systemzeit-Spanne.
Die letzte Version eines Dokuments kann aber auch einfach über ein latest flag in Erfahrung gebracht werden:
xquery version "1.0-ml";
cts:search(fn:doc(), cts:and-query((
    cts:collection-query(("koolorder.xml")),
    cts:collection-query(("latest")))))
Weiterführende Links
Previous Page Next Page
Version: 93
Jan 25 2021