Von bitemporaler Compliance bis hin zu partiellen Datensatz-Updates: Bereitstellung von robustem, revisionssicherem Change Data Capture ohne benutzerdefinierten Code
von Josh Seidel, Shanelle Roman und Sudhanva Huruli
Die Erfassung von Datenänderungen (Change Data Capture, CDC) gehört zu den häufigsten Aufgaben, die Data Engineers auf Spark aufbauen, und ist manuell besonders mühsam fehlerfrei umzusetzen. In unserem vorherigen Beitrag Schluss mit dem manuellen Schreiben von Change-Data-Capture-Pipelines haben wir gezeigt, wie AUTO CDC in Apache™ Spark Declarative Pipelines (SDP) SCD Typ 1, SCD Typ 2 und Snapshot-CDC automatisiert, indem Hunderte von Zeilen fehleranfälliger MERGE-Logik durch wenige einfache Deklarationen ersetzt werden.
Da sich die Anforderungen an Pipelines ständig weiterentwickeln, stoßen Engineers auf Situationen, die mit diesen Standard-CDC-Mustern nur schwer zu lösen sind:
Heute heben wir AUTO CDC auf die nächste Stufe, um genau diese praktischen Herausforderungen zu lösen, und erweitern diese Funktionen im Open-Source-Projekt Apache Spark 4.2.
Standard-SCD-Typ-2-Tabellen können Ihnen zwar sagen, wann sich ein Fakt in der realen Welt geändert hat, aber nicht, welchen Zustand Ihr System zu einem bestimmten Zeitpunkt angenommen hat.
Gemäß der SEC-Regel 17a-4 und den FINRA-Aufbewahrungsvorschriften müssen Unternehmen in der Lage sein, Datensätze so zu rekonstruieren, wie sie zu einem bestimmten Zeitpunkt existierten. Allein die SEC-Untersuchungen zur Einhaltung der Aufbewahrungspflichten haben seit 2021 zu Bußgeldern von über 2 Milliarden US-Dollar bei mehr als 100 Unternehmen geführt. Die Schwierigkeit liegt selten darin, den heutigen Wert zu speichern. Die Herausforderung besteht darin, Monate später zu beantworten, was die Referenzdaten am Berichtstag besagten und welchen Zustand unsere Systeme zu diesem Zeitpunkt angenommen hatten.
Standard-SCD-Typ-2 erfasst eine Zeitachse: wann sich ein Fakt geändert hat. Bitemporales AUTO CDC erfasst zwei Zeitachsen unabhängig voneinander:
Jede Zieltabelle erhält vier systemseitig verwaltete Spalten: __START_AT und __END_AT für die Gültigkeitszeit (Business Time) sowie __SYSTEM_START_AT und __SYSTEM_END_AT für die Systemzeit. Ein einzelner logischer Fakt kann mehrere physische Zeilen haben – eine pro Kombination aus Business-Version und System-Version. Dies ermöglicht die historische Rekonstruktion entlang beider Achsen. Die wichtigste Verhaltensgarantie dabei: Ereignisse können in beliebiger Reihenfolge auf beiden Zeitachsen eingehen.
Wenn eine Korrektur mit einer früheren Gültigkeits- oder Systemzeit als bereits verarbeitete Daten eingeht, schreibt die Engine den betroffenen Verlauf neu, anstatt ihn einfach nur hinten anzuhängen. Keine manuell geschriebene Logik – deklarieren Sie einfach die beiden Sequenzierungsspalten, und die Engine pflegt beide Intervalle. Dies funktioniert gleichermaßen für Dimensionstabellen wie Symbol-Stammdaten als auch für Faktentabellen wie Handelsverläufe oder Sensorwerte, die eine strenge Revisionssicherheit erfordern. So sieht das Ganze im Vergleich zu den FINRA CAT-Referenzdaten aus:
Beachten Sie, dass die genaue SQL-Klausel STORED AS BITEMPORAL lautet, nicht STORED AS SCD TYPE BITEMPORAL, und dass sie sowohl SEQUENCE BY als auch SYSTEM SEQUENCE BY erfordert. Angenommen, das Kennzeichen für die Meldepflicht von Acme ändert sich am 1. Januar (Gültigkeitszeit), aber der Feed empfängt diese Änderung erst am 5. Januar (Systemzeit). Am 8. Januar geht dann eine rückdatierte Korrektur ein, die besagt, dass die tatsächliche Änderung am 1. Januar stattfand, jedoch mit einem anderen Wert. Bitemporales AUTO CDC kann beide Fragen beantworten:
Am 3. Januar liefert die erste Abfrage kein Ergebnis – die korrekte, revisionssichere Antwort darauf, was das System zu diesem Zeitpunkt anzeigte. Die zweite Abfrage, die heute ausgeführt wird, spiegelt die korrigierte Wahrheit wider. Zwei Uhren, zwei Antworten, beide richtig. Sequenzierungsspalten müssen sortierbare Typen sein und dürfen keine NULL-Werte enthalten. Die Funktion läuft auf Serverless SDP oder den Produkt-Editionen Pro/Advanced und befindet sich derzeit in der Beta-Phase. Heften Sie die Pipeline daher an den Channel an: PREVIEW.
Wenn ein Modell auf Referenz- oder Feature-Daten trainiert wird, bedeutet Reproduzierbarkeit, dass man Monate später bei einer Überprüfung oder einem Audit genau den Datensatz rekonstruieren kann, den das Modell verwendet hat. Der erste Impuls ist oft, das Time Travel von Delta Lake zu nutzen, aber das ist eine Eigenschaft des Dateiverlaufs der Tabelle, kein dauerhafter Datensatz. VACUUM löscht dauerhaft Datendateien, auf die neuere Versionen nicht mehr verweisen. Nach Ablauf des standardmäßigen 7-tägigen Aufbewahrungsfensters kann ein zum Trainingszeitpunkt protokolliertes TIMESTAMP AS OF unbemerkt nicht mehr aufgelöst werden. Eine bitemporale Tabelle speichert diesen Verlauf als Daten, nicht als Dateiversionen. VACUUM und OPTIMIZE komprimieren Dateien, rühren den logischen Verlauf jedoch nicht an, sodass jede frühere Business- oder Systemversion weiterhin als abfragbare Zeile existiert. Es gibt zwei Möglichkeiten, wie Sie hierdurch Reproduzierbarkeit erzielen können: Protokollieren Sie zwei Zeitpunkte (Gültigkeits- und Systemzeit) als MLflow-Parameter und heften Sie die Trainingsabfrage an diesen Zustand an:
Oder, falls die Tabelle eine aktuelle Ansicht bereitstellt, protokollieren Sie einen einzelnen Systemzeitpunkt beim Training und rekonstruieren Sie diesen später mit einer Systemzeit-Abfrage zu diesem Zeitstempel:
In jedem Fall besteht die Vereinbarung zur Reproduzierbarkeit aus einigen Zeitstempeln im MLflow-Run. Da der bitemporale Verlauf als Zeilen gespeichert wird, bleibt diese Vereinbarung auch dann bestehen, wenn VACUUM die zugrunde liegenden Dateien bereinigt hat.
Nicht alle Change-Data-Capture-Quellen (CDC) geben bei Aktualisierungen vollständige Zeilen aus. Stattdessen senden viele nur die geänderten Felder und stellen alle anderen Spalten als NULL dar. Ohne spezielle Behandlung können diese NULL-Werte versehentlich vorhandene Daten in der Zieltabelle überschreiben. Bisher mussten Kunden eigene Logik entwickeln, um dieses Verhalten zu umgehen. Mit den partiellen Updates für AutoCDC wird dies nun automatisch erledigt.
Partielle Updates erweitern AutoCDC, indem sie es ermöglichen, dass Aktualisierungsereignisse nur eine Teilmenge der Spalten ändern. Für ausgewählte Spalten werden NULL-Werte in einer eingehenden Aktualisierung als „nicht aktualisieren“ interpretiert, anstatt den vorhandenen Wert zu überschreiben.
Dies ist besonders nützlich für CDC-Quellen, die unveränderte Werte weglassen, indem sie NULL ausgeben. Ohne partielle Updates würden diese NULL-Werte vorhandene Daten in der Zieltabelle überschreiben.
Angenommen, die Zieltabelle enthält beispielsweise: (1, 'A', 20)
Ein eingehendes Update-Ereignis enthält: (1, NULL, 30)
Standardmäßig würde AutoCDC die Zeile wie folgt aktualisieren: (1, NULL, 30).
Wenn Partial Updates aktiviert sind, wird der NULL-Wert in name als „bestehenden Wert unver ändert lassen“ behandelt, was zu Folgendem führt: (1, 'A', 30).
Das Aktivieren von Partial Updates erfordert lediglich das Hinzufügen eines Parameters zu Ihrer AutoCDC-Definition. Sie können aus drei Möglichkeiten wählen, um anzugeben, welche Spalten als partielle Updates behandelt werden sollen:
IGNORE NULL UPDATES ON columnListIGNORE NULL UPDATES ON * EXCEPT (columnList)COLUMNS TO UPDATEVollständige Syntax, Beispiele und Anleitungen zur Verwendung finden Sie in der Dokumentation zum Anwenden von Partial Updates.
Spark Declarative Pipelines ist Open Source, daher sollte es auch der am häufigsten verwendete Flow-Typ sein. Wir beginnen damit, die Python-API für AUTO CDC Typ 1 zu Apache Spark 4.2 beizutragen.
Wir haben diesen Beitrag so geleistet, wie sich auch der Rest von Spark entwickelt: als eine Reihe von geprüften Vorschlägen und Pull Requests, nicht als einmalige Code-Übergabe (siehe SPIP und SPARK-56249). Die Korrektheit bei ungeordneten Daten ist direkt integriert: Eine kleine Hilfstabelle verfolgt den Status von früh eintreffenden Ereignissen wie Delete Tombstones, wiederholte Microbatches konvergieren, anstatt das Ziel zu beschädigen, und da sie auf den Streaming- und Tabellenabstraktionen von Spark aufbaut und nicht auf einem Speicherformat, läuft sie sowohl auf Delta Lake als auch auf Apache Iceberg.
Was als Nächstes in der Open-Source-Community ansteht:
CREATE FLOW ... AS AUTO CDC INTO) bereits in den Master-Branch gemergt, was im nächsten Release von Apache Spark enthalten sein wird.NULL-Werte Zieldaten überschreiben.Ganz gleich, ob Sie bitemporale Compliance implementieren, Partial Updates einrichten oder Open-Source-AutoCDC in Apache Spark erkunden möchten – werfen Sie einen Blick auf die folgenden Ressourcen, um loszulegen:
(Dieser Blogbeitrag wurde mit KI-gestützten Tools übersetzt.) Originalbeitrag
Abonnieren Sie unseren Blog und erhalten Sie die neuesten Beiträge direkt in Ihren Posteingang.