Über unsMediaKontaktImpressum
Christopher Münch 15. März 2022

Mit Apache Spark Big Data zähmen

Wahrscheinlich hat jeder den folgenden Satz in den letzten Jahren schon einmal in der ein oder anderen Form gehört: "Daten sind das Gold des 21. Jahrhunderts". Zieht man das Wachstum der Daten über die letzten zehn Jahre heran, stellt man schnell fest, dass an dieser Aussage definitiv etwas dran ist.

Gerade zu Zeiten von Industrie 4.0, des Internets der Dinge und insbesondere von Social Media werden immer mehr Daten generiert, dauerhaft gesichert und weitergenutzt. Die Speicherung und Verarbeitung von riesigen Datenmengen wird heutzutage oft mit dem Begriff "Big Data" zusammengefasst.

Big Data

Große Datenmengen bringen auch einige Aufgaben mit sich, die zu bewältigen sind. Diese Herausforderungen werden oft als die "großen vier Vs" bezeichnet.

  • Dies ist einerseits die schiere Datenmenge (Volume), welche gesichert und verarbeitet werden soll. Daten müssen auf eine effiziente Art und Weise gesichert werden, sodass überhaupt eine Analyse vorgenommen werden kann.
  • Die zweite Herausforderung ist die Geschwindigkeit (Velocity). Damit ist einerseits die Zeit gemeint, welche benötigt wird, um die Daten zu verarbeiten, andererseits auch die Häufigkeit oder Frequenz, mit der neue Daten generiert werden.
  • Bei all diesen Datenmengen spielt auch die Art (Variety) der Daten eine wichtige Rolle. Dies fängt mit klassischen strukturierten und semistrukturierten Daten an und reicht bis hin zu Bildern, Audio- oder Videoaufnahmen oder etwa Streaming-Daten von IoT-Geräten.
  • Zu guter Letzt muss die Wahrhaftigkeit, Zuverlässigkeit und Qualität (Veracity) der Daten sichergestellt werden.

Klassische Datenverarbeitungs- und Speichersysteme sind oftmals nicht mehr dazu in der Lage, diese Herausforderungen in einer akzeptablen Zeit zu bewältigen – wenn überhaupt. Vor allem in klassischen Server-Landschaften sind Hardwareressourcen wie Festplattenkapazität, Arbeitsspeicher und CPU stark limitiert und daher umkämpft. Zwar lassen sich einige Probleme mit einer vertikalen Skalierung (Upgrade der Serverhardware) hinauszögern, aber auch diese wird früher oder später das Problem nicht mehr lösen können.

Zusätzlich zu den technischen Herausforderungen im Big-Data-Bereich gibt es jedoch auch fachliche Herausforderungen.

  • Ein Data Engineer versucht, allerlei Daten über ETL- bzw. ELT-Prozesse (Extract, Load & Transform) zu verarbeiten, die üblicherweise in einem Data Warehouse bereitgestellt werden.
  • Data Analysts verwenden diese Daten, um Reporte oder Dashboards zu erstellen.
  • Ein Data Scientist arbeitet hingegen eher mit Rohdaten und versucht beispielsweise über Machine-Learning-Algorithmen Informationen aus Daten herauszuziehen. Aus diesen Erkenntnissen werden unter anderem Prognosen erstellt, welche für ein Unternehmen von wichtiger Bedeutung sein können.

All diese Fachbereiche arbeiten in den meisten Fällen mit verschiedenen, oft proprietären, Systemen. Ein Datenaustausch zwischen einzelnen Bereichen ist oftmals mit hohem Aufwand verbunden. So ist z. B. ein Data Warehouse meistens eine relationale Datenbank, während ein Data Scientist mit Daten auf einem Hadoop-System arbeitet. Apache Spark versucht, all die Big-Data-Herausforderungen zu bändigen und alle Fachbereiche unter einen Hut zu bringen.

Apache Spark

Im Großen und Ganzen kann man Spark vorerst als eine verteilte Datenverarbeitungs-Engine bezeichnen [1], welche erstmals im Jahr 2010 mit einer Open-Source-Lizenz erschien und seit 2013 Teil der Apache Software Foundation ist. Der gesamte Quellcode ist hauptsächlich in Scala und Java geschrieben und steht auf GibHub zur Verfügung [2].

Spark wirbt damit, dass es Daten bis zu hundertmal schneller als Apache Hadoop – welches in den letzten Jahren oft verwendet wurde – verarbeiten kann. Um dies zu ermöglichen, findet die gesamte Datenverarbeitung im Arbeitsspeicher und einem Cluster mit verteilten Maschinen statt – dazu aber später mehr.

Das Spark-Ökosystem

Spark an sich setzt sich aus mehreren einzelnen Komponenten zusammen, die je nach Anforderung verwendet werden können:

  • Spark Core: Herz des gesamten Frameworks, auf dem alle anderen Komponenten aufbauen. Es stellt die entsprechenden Dienste für die verteilte Datenverarbeitung, Job-Scheduling und I/O bereit.
  • Spark SQL: Die wohl wichtigste Komponente von Spark, mit der die meisten Entwickler arbeiten. Dieses Modul stellt Dienste bereit, um mit strukturellen und semistrukturellen Daten zu arbeiten. Es ermöglicht, Daten mithilfe von sogenannten DataFrames und über ANSI-SQL abzufragen, zu transformieren und zu speichern.
  • Spark Streaming: Während Spark SQL hauptsächlich für Batch-Processing verwendet wird, ermöglicht dieses Modul, Echtzeitdaten in Form von Streams zu verarbeiten.
  • MLib: Wie der Name schon vermuten lässt, werden über diese Komponente verschiedene Machine-Learning-Algorithmen bereitgestellt.
  • GraphX: Mithilfe dieses Moduls lassen sich in Spark Graphen verarbeiten.

Neben all diesen Kernkomponenten ist Spark jedoch sehr modular und lässt sich um beliebig viele weitere Komponenten erweitern. In diesem Artikel werden wir uns jedoch hauptsächlich auf die Spark SQL-Komponente konzentrieren.

Databricks

Als Teil dieses Beitrages werden im späteren Verlauf Screenshots und Code-Ausschnitte gezeigt. Dafür wird Azure Databricks verwendet [3]. Databricks ist eine branchenführende Plattform, die von den Entwicklern von Apache Spark entwickelt wurde. Es stellt eine einfach zu verwendende Cluster-Verwaltung und Entwicklungsumgebung zur Verfügung und erweitert Spark um viele nützliche Features.

Spark Cluster

Wenn man Daten mit Spark verarbeitet, geschieht dies üblicherweise über ein Spark-Cluster. Ein Cluster setzt sich dabei aus einem Verbund mehrerer Rechner zusammen, bei denen die Daten und die Verarbeitung ebendieser auf verschiedene sogenannte Worker Nodes (auch Executors genannt) verteilt wird. Der Anwender selbst kommuniziert dabei mit einem sogenannten Driver Node. Dieser stellt eine Spark-Session bereit, über die Abfragen und Befehle an Spark übermittelt werden. Für alle weiteren Beispiele werde ich ein Spark-Cluster verwenden, welches sich aus einem Driver Node und insgesamt vier Worker Nodes zusammensetzt.

Im Hintergrund verwendet (und erstellt) Databricks virtuelle Linux-Maschinen in Azure, die in einem virtuellen Netzwerk miteinander verbunden sind. Das Cluster kann so konfiguriert werden, dass es sich nach einer bestimmten Zeit Inaktivität automatisch ausschaltet. Da Databricks ausschließlich in der Cloud verwendet werden kann, ist dies ein Feature, welches man unbedingt nutzen sollte – vor allem um die Kosten für die virtuellen Maschinen so gering wie möglich zu halten. Inaktive Spark-Cluster müssen vor der Nutzung natürlich vorab wieder gestartet werden, was einige Minuten in Anspruch nimmt.

Datenstrukturen in Spark

Wenn Daten in Spark verarbeitet werden, werden intern sogenannte Resilient Distributed Datasets (RDDs) verwendet. Diese stellen die fundamentale Datenstruktur dar, mit der Spark arbeitet. Ein RDD kann man sich dabei als eine nicht veränderliche, partitionierte Sammlung von Datensätzen vorstellen, die auf die verschiedenen Executors des Spark-Clusters verteilt sind. Da die RDD-API jedoch (relativ) maschinennah ist, war es früher insbesondere für Neueinsteiger nicht so einfach, mit Spark zu arbeiten. In Spark Version 1.3 wurde daraufhin die DataFrame-API eingefügt, welche bis heute die gängigste und empfohlene Schnittstelle ist, mit der man in Spark arbeitet.

Ein DataFrame setzt sich aus Zeilen mit benannten Spalten zusammen und besitzt ein Schema. Klingt wie eine Tabelle aus einer relationalen Datenbank, oder? Genau so können wir uns diese auch erstmal vorstellen. Spark stellt über die DataFrame-API etliche Funktionen zur Verfügung, mit deren Hilfe die Daten eines DataFrames transformiert werden können.

Unser erstes Notebook

Genug mit der Theorie, schauen wir uns mal an, wie wir mit Spark arbeiten können! Die wohl einfachste und interaktivste Art, um mit Spark zu arbeiten, ist über Jupyter Notebooks [4]. Dabei handelt es sich um ein Dokument, welches in einzelne Zellen aufgeteilt ist. In einer Zelle kann dabei vom Anwender entweder Code oder Markdown (formatierter Text) definiert werden. Zu jeder Code-Zelle wird daraufhin bei der Ausführung eine Ergebnis-Zelle erzeugt, in der die Ausgabe angezeigt wird. In solchen Zellen können einfache Texte, Tabellen oder sogar Charts ausgegeben werden.

Es gibt verschiedene Programmiersprachen, mit denen in Spark gearbeitet werden kann. Standardmäßig bietet Spark Support für die Sprachen Python (pyspark), SQL, R und Scala an. Mit Ausnahme von SQL ähneln sich die APIs der einzelnen Programmiersprachen jedoch sehr, sodass Entwickler selbst entscheiden können, welche Sprache sie verwenden möchten. Ich werde hauptsächlich einen Mix aus Python und SQL verwenden.

In Abb. 2 werden einige CSV-Dateien von einem Azure Storage Account in ein DataFrame geladen. Bei den Daten handelt es sich um insgesamt 200 Millionen Datensätze über zufällig generierte fiktive Personen. Die einzulesenden Dateien sind insgesamt rund 17 GB groß.

Ein Notebook ist immer an Spark-Cluster angehängt. Dieses Cluster stellt eine Variable mit dem Namen spark bereit, welche die aktuelle Session darstellt und ist die primäre Schnittstelle, über die mit dem Spark-Clusters kommuniziert wird. Mit der einen Zeile Code haben wir Spark nun mitgeteilt, dass es alle Dateien aus dem angegebenen Pfad parsen und in das DataFrame laden soll. Spark bietet umfangreiche Konfigurationsparameter für alle möglichen Datenquellen an. Hier wurde mit der Option header eingestellt, dass die CSV-Dateien Spaltenbezeichner in der ersten Zeile besitzen, welche daraufhin als Bezeichner für die einzelnen Spalten im DataFrame verwendet werden. Über die Option inferSchema habe ich Spark zusätzlich noch mitgeteilt, dass es versuchen soll, die Datentypen anhand ihres Inhaltes zu bestimmen. Wird diese Option bei CSV-Dateien nicht gesetzt, werden alle Spalten als String eingelesen. Als Ergebnis wird daraufhin das DataFrame-Schema angezeigt – die Spalte Birthday wurde von Spark dabei als Timestamp identifiziert.

Datentransformation

Da wir die Daten nun in ein DataFrame geladen haben, wollen wir im nächsten Schritt ein paar Transformationen vornehmen und die Daten genauer betrachten. Dazu werden wir aus der Spalte Birthday ein Datum machen, da uns die Uhrzeit in dem Fall nicht interessiert. Zusätzlich wollen wir wissen, wie alt diese fiktiven Personen denn sind.

Arbeitsweise von Spark

Wie bereits zu Beginn erwähnt, baut Spark auf einem Cluster mit mehreren Knoten auf und jegliche Abfragen und Transformationen werden verteilt abgearbeitet. Doch intern macht Spark noch einiges an Optimierungen, um die bestmögliche Performance zu gewährleisten.

Lazy Evaluation & der Catalyst Optimizer

Spark ist faul! Aber in dem Sinne, dass es Lazy Evaluation verwendet. Das heißt, dass jegliche Transformationen, die definiert werden, erst dann wirklich ausgeführt werden, wenn das Ergebnis benötigt wird. Würde Spark das Ergebnis jeder Transformation direkt verarbeiten, würde dies schnell den gesamten Arbeitsspeicher aller Nodes belegen und Daten müssten auf einen langsameren Speicher wie (optimalerweise) eine SSD geschrieben werden – insofern dieser überhaupt verfügbar ist.

Ähnlich wie auch relationale Datenbanksysteme verwendet Spark einen Query-Optimizer, der Catalyst genannt wird. Jedes DataFrame lässt sich somit auch als eine Folge von Transformationen verstehen. Für diese Transformationen erzeugt Spark einen logischen Plan, der wiederum vom Query-Optimizer analysiert und optimiert wird. Das Ergebnis ist ein optimierter physischer Plan, der schlussendlich beim eigentlichen Abfragen der Daten ausgeführt wird.

Caching

Durch die Lazy-Evaluation von Spark werden Transformationen erst dann ausgewertet, wenn sie wirklich gebraucht werden. Oftmals benötigt man das Ergebnis einer Transformation allerdings mehrmals. Für solche Fälle lassen sich Daten nach einer erstmaligen Transformation für künftige Transformationen explizit im Arbeitsspeicher (oder der Platte) persistieren.

Mit Caching ist es so möglich, das Ergebnis komplexer Transformationen weiter zu verwenden, ohne dass diese erneut ausgeführt werden müssen. Caching sollte ebenfalls in Erwägung gezogen werden, wenn Daten aus langsamen Datenquellen stammen, wie beispielsweise großen CSV-Dateien, die sonst jedes Mal erneut von Spark eingelesen werden müssten.

Durch die Lazy-Evaluation werden die Daten erst bei einer Aktion – in diesem Fall durch Aufruf der count-Methode – vollständig ausgewertet und somit alle 200 Mio. Zeilen aus den CSV-Dateien geladen. Durch das Caching werden die Daten in den Arbeitsspeicher geschrieben, sodass die zweite Abfrage nur noch einen Bruchteil der Zeit benötigt.

Scheduling

Wird in Spark – z. B. durch den Aufruf der count-Funktion – eine Aktion gestartet, die das Ergebnis einer Transformation benötigt, wird der Query-Plan, den der Catalyst Optimizer erzeugt hat, ausgeführt.

Spark legt für den Aufruf dieser Aktion Jobs an, welche an den Job-Scheduler übergeben werden. Dieser ist dabei ein integraler Teil von Spark, welcher für die Abarbeitung von Jobs zuständig ist. Standardmäßig werden diese Jobs nach dem First-In/First-Out-Prinzip (FIFO) abgearbeitet. Jeder Job ist dabei wieder unterteilt in verschiedene Stages, die vom Catalyst-Optimizer erzeugt werden. Eine Stage ist dabei als ein Teil eines gerichteten azyklischen Graphen (Directed Acyclic Graph (DAG)) zu verstehen, auf dem der eigentliche Query-Plan eines Spark-Jobs intern aufbaut. Diese Stages müssen demnach in einer bestimmten Reihenfolge abgearbeitet werden, da diese aufeinander aufbauen.

Jede Stage setzt sich dann wiederum aus mehreren, kleineren Tasks zusammen. Diese sind die eigentlichen Transformationen, die auf den RRDs, welche auf die verschiedenen Executor verteilt sind, angewendet werden. Diese vorerst komplex wirkende Aufteilung ermöglicht es Spark, Daten effektiv und verteilt zu verarbeiten. Durch die Verwendung von DAGs ist ebenfalls eine hohe Ausfallsicherheit sichergestellt. Sollte wider Erwarten ein Executor ausfallen, können dessen Daten hergestellt werden, indem die einzelnen Stages wiederholt werden.

SQL in Spark

Neben der Möglichkeit, über verschiedene Programmiersprachen und die DataFrame-API zu arbeiten, lässt sich in Spark auch direkt mit SQL arbeiten. Dies ist besonders für Entwickler interessant, die in der Vergangenheit hauptsächlich mit SQL gearbeitet haben.

SQL-API

Daten können direkt von einem Data-Lake oder Spark-Tabellen über SQL abgefragt werden, ohne auf die Vorzüge der parallelisierten Verarbeitung verzichten zu müssen. Innerhalb von Notebooks lässt sich die Sprache einer Code-Zelle ganz einfach mit dem Magic-Command %sql in SQL umwandeln. Hier stehen einem nahezu alle Transformationen zur Verfügung, die auch über die DataFrame-API bereitgestellt werden.

Das Team von Spark bemüht sich, die SQL-API möglichst ANSI-kompatibel zu halten; die verfügbaren Datentypen gehen hier aber auf die Datentypen in Java zurück. Für Text gibt es in Spark-SQL beispielsweise nur den Datentyp string. Neben gängigen Transformationen ist es mit SQL-Spark ebenfalls möglich, komplexere SQL-Abfragen zu definieren, die z. B. Unterabfragen, rekursive Abfragen (Common Table Expressions) oder Window-Funktionen beinhalten. Dazu stellt Spark einen breiten Katalog von SQL-Funktionen zur Verfügung, die in jeglichen Abfragen verwendet werden können [5].

SQL- und DataFrame-API verbinden

Oftmals ist es während der Entwicklung hilfreich, sich Daten, die man vorab in ein DataFrame geladen und transformiert hat, über SQL abzufragen. DataFrames können ohne großen Aufwand in temporären Views gespeichert werden, die dann direkt mit SQL abgefragt werden können. Dies lässt sich allerdings auch umdrehen – temporäre Views können ebenfalls von SQL aus angelegt werden und über die DataFrame-API abgefragt werden. Das folgende Beispiel zeigt, wie Daten mithilfe der DataFrame-API geladen und in eine temporäre View geschrieben werden. Mithilfe von Spark-SQL wird auf diesen Daten dann eine Aggregation vorgenommen, deren Ergebnis wiederum in einer temporären View gespeichert wird. Das Ergebnis kann dann wieder in ein DataFrame eingelesen werden.

In diesem Beispiel wird das Ergebnis der vorherigen Transformation in einer temporären View gespeichert. Im nächsten Schritt führe ich eine Aggregation über SQL durch und speichere dieses Ergebnis in einer weiteren temporären View, die dann über die SQL-Methode ausgelesen werden kann. Temporäre Views sind lediglich in der Spark-Session verfügbar, in der sie definiert wurden. Sie ähneln also Variablen in Python und sind an sich auch nichts anderes als eine Reihe von Transformationen mit einem Alias.

Datenpersistierung

Neben dem Lesen und Transformieren von Daten kann Spark selbstverständlich auch Daten speichern. Im Gegensatz zu relationalen Datenbanksystemen wird in Spark hauptsächlich auf ein hadoop-basiertes Dateisystem und offene Dateiformate wie Apache Parquet oder Avro gesetzt.

Da Spark primär in Cloud-Umgebungen Anwendung findet, wird hier hauptsächlich auf schnelle und kostengünstige Cloud-Speicher-Anbieter wie Amazon S3 oder Azure Data Lake Storage gesetzt. Im Vergleich zu proprietären Systemen wie Microsoft SQL-Server, Oracle oder anderen relationalen Datenbanksystemen sind diese um ein Vielfaches günstiger. Außerdem sind sie skalierbarer, ausfallsicher und haben oftmals speziell für Spark optimierte Treiber.

Speichern im Data Lake

Das wohl am häufigsten verwendete Dateiformat beim Speichern von Daten mithilfe von Spark ist Apache Parquet [6]. Bei diesem Dateiformat werden die Daten spaltenweise, binär und hochkomprimiert abgespeichert. Dies ist insbesondere für analytische Zwecke vorteilhaft. Beim Lesen müssen demnach nur noch die Teile der Datei eingelesen werden, welche die Daten der benötigten Spalten beinhalten.

Um Daten in Spark zu speichern, muss lediglich die write-Funktion des DataFrames aufgerufen werden. Spark ermöglicht es nun, weitere Optionen anzugeben – etwa in welchem Dateiformat die Daten gespeichert werden sollen oder an welchem Ort und wie die Daten eventuell partitioniert werden sollen.

Hier wurden die Daten im Parquet-Format auf einem Azure Data Lake Storage gespeichert. Die Daten wurden dabei nach der Spalte Region partitioniert. Bei einer Partitionierung erzeugt Spark so für jeden Wert einen eigenen Ordner, in dem sich alle Daten befinden, die denselben Wert für Region besitzen.

Speichern als Tabelle

Neben dem einfachen Speichern von Daten in einem Ordner auf einem Data Lakes gibt es auch die Möglichkeit, die Daten in Tabellen zu speichern. Im Gegensatz zu Datenbank-Tabellen, wie man sie aus relationalen Datenbanken kennt, sind diese in Spark eher als Metadaten zu verstehen. Die Struktur wird anhand der eigentlichen Daten im Data Lake definiert.

Während ich im vorherigen Schritt die save-Funktion aufgerufen habe, lässt sich auch die saveAsTable-Funktion verwenden. Dabei werden die Daten ebenfalls auf dem Data Lake (oder im Fall von Data Bricks im Cluster selbst, wenn kein expliziter Pfad angegeben wird) gespeichert und lediglich eine Tabelle als Metadaten definiert, die auf die eigentlichen Daten zeigt. Diese Tabelle lässt sich dann direkt über die SQL- oder auch die DataFrame-API abfragen.

Auch beim Speichern der Daten als Tabelle werden die Daten im Hintergrund im Parquet-Format gespeichert. Wie bereits vorher erwähnt, ist Spark an sich keine voll verwaltete Datenbank. Tabellen, Views etc. werden lediglich als Metadaten im sogenannten Hive-Metastore gespeichert. Allerdings ist es nicht ohne weiteres möglich, Daten innerhalb einer Tabelle – wie man es von einer relationalen Datenbank kennt – direkt zu verändern. Und damit komme ich auch zum letzten Abschnitt dieses Beitrags.

Delta Lake

Spark macht es zwar sehr einfach, riesige Datenmengen zu transformieren und auf einem Data Lake zu speichern, allerdings fehlt einem Data Lakes das, was für relationale Datenbanken eine Selbstverständlichkeit ist: Support für ACID-Transaktionen. So ist es nicht – wie in einer normalen Datenbank-Tabelle – möglich, DML-Statements (Data Manipulation Language) auf einer Data-Lake- Tabelle auszuführen.

Dies liegt daran, dass es sich bei den Daten auf einem Data Lake lediglich um eine Vielzahl von Dateien handelt – häufig im Parquet-Format. Parquet eignet sich hervorragend, um große Datenmengen abzuspeichern und abzufragen. Allerdings lassen sich Parquet-Dateien nach dem Schreiben nicht mehr ändern. Somit müssen die Daten in einem Prozess wieder in ein DataFrame eingelesen werden und entsprechende Zeilen aktualisiert, gelöscht oder hinzugefügt werden. Dann muss dieses DataFrame erneut gespeichert werden – sprich die alten Daten müssen überschrieben werden. Und wenn bei diesem Prozess etwas schieflaufen sollte, kann es sein, dass die Daten entweder korrupt oder komplett unbrauchbar werden. Davor schützen ACID-Transaktionen.

Ein Feature, welches ursprünglich ein exklusiver Teil von Databricks war – aber mittlerweile als Open-Source-Projekt veröffentlicht wurde – ist Delta Lake[7]. Delta Lake setzt zusätzlich Layer auf einen Data Lake auf und bietet Support für ACID-Transaktionen und weitere Features, die man aus einem relationalen Datenbanksystem kennt, allerdings ohne auf die Vorzüge eines Data Lakes verzichten zu müssen.

Die hier explizit definierte Delta-Tabelle wird über das Delta-Lake-Modul angelegt und verwaltet. In der zweiten Zelle werden die 200 Mio. Datensätze aus dem DataFrame in diese Tabelle geschrieben. Spark erkennt, dass es sich dabei um eine Delta-Tabelle handelt. Delta-Lake stellt dabei die transaktionsbasierte Speicherung der Daten sicher und ermöglicht zusätzlich, nahezu alle DML-Statements zu verwenden. Gespeichert werden die eigentlichen Daten weiterhin im Parquet-Dateiformat. Delta Lake hält ebenfalls eine komplette Historie aller Transaktionen parat und bietet die Möglichkeit, sich die Daten mithilfe von Time-Traveling zu jeder Version anzeigen zu lassen.

In der ersten Zelle wurden jegliche Datensätze aus der Tabelle entfernt, deren Region nicht Westeuropa ist. Über den SQL-Befehl in der mittleren Zelle lässt sich die Historie einer Delta-Tabelle anzeigen. Hier kann man die drei einzelnen Transaktionen sehen: Anlegen der Tabelle, Schreiben in die Tabelle & das Löschen aus der Tabelle. In der letzten Zelle wurde die Anzahl der Zeilen für jede Version der Tabelle ausgegeben.

Aus dieser Kombination hat sich unter anderem der Begriff Data Lakehouse etabliert – bei dem die Vorzüge eines Data Lakes mit dem eines Data Warehouse kombiniert werden. Doch Delta Lake ist nur eines von vielen Projekten, welche ACID-Transaktionen auf einem Data Lake ermöglichen – andere nennenswerte Projekte sind z. B. Apache Iceberg oder Snowflake.

Fazit

Apache Spark ist ein sehr mächtiges Tool, um die immer größer werdende Datenmenge, mit denen Unternehmen konfrontiert werden, zu bewältigen. Spark-SQL macht es sehr einfach, skalierbare ETL- und ELT-Prozesse zu erstellen, um Daten aus verschiedensten Quellen in einem Data Lake oder Data Lakehouse zu speichern. Neben der Verarbeitung von strukturellen und semistrukturellen Daten via Spark-SQL kann Spark aber durch seine Vielfalt an Modulen auch für viele weitere Anwendungsbereiche verwendet werden.

Autor

Christopher Münch

Christopher Münch arbeitet seit 2018 als IT-Berater für die arelium GmbH. Als Data-Engineer kann er auf langjährige Erfahrung mit dem Microsoft SQL-Server zurückblicken und hat sich auf das Big-Data-Umfeld im Azure-Bereich…
>> Weiterlesen
Das könnte Sie auch interessieren
Kommentare (0)

Neuen Kommentar schreiben