Es gibt viele AnsĂ€tze zum Erstellen von Anwendungscode, um zu verhindern, dass die ProjektkomplexitĂ€t im Laufe der Zeit zunimmt. Der objektorientierte Ansatz und viele angehĂ€ngte Muster ermöglichen es beispielsweise, die KomplexitĂ€t des Projekts nicht auf dem gleichen Niveau zu halten, es zumindest wĂ€hrend der Entwicklung unter Kontrolle zu halten und den Code dem neuen Programmierer im Team zur VerfĂŒgung zu stellen.
Wie können Sie die KomplexitÀt eines ETL-Transformationsprojekts auf Spark verwalten?
Es ist nicht so einfach.
Wie sieht es im wirklichen Leben aus? Der Kunde bietet an, eine Anwendung zu erstellen, die eine Storefront sammelt. Es scheint notwendig zu sein, den Code ĂŒber Spark SQL auszufĂŒhren und das Ergebnis zu speichern. WĂ€hrend der Entwicklung stellt sich heraus, dass fĂŒr die Erstellung dieses Marts 20 Datenquellen erforderlich sind, von denen 15 Ă€hnlich sind, der Rest jedoch nicht. Diese Quellen mĂŒssen kombiniert werden. AuĂerdem stellt sich heraus, dass Sie fĂŒr die HĂ€lfte von ihnen Ihre eigenen Montage-, Reinigungs- und Normalisierungsverfahren schreiben mĂŒssen.
Und ein einfaches Schaufenster sieht nach einer detaillierten Beschreibung ungefĂ€hr so ââaus:
Als Ergebnis erhĂ€lt ein einfaches Projekt, das nur ein SQL-Skript ausfĂŒhren sollte, das das Schaufenster auf Spark sammelt, einen eigenen Konfigurator, einen Block zum Lesen einer groĂen Anzahl von Konfigurationsdateien, einen eigenen Zuordnungszweig und Ăbersetzer einiger Sonderregeln usw.
In der Mitte des Projekts stellt sich heraus, dass nur der Autor den resultierenden Code unterstĂŒtzen kann. Und er verbringt die meiste Zeit in Gedanken. In der Zwischenzeit bittet der Kunde, ein paar weitere Vitrinen zu sammeln, die wiederum auf Hunderten von Quellen basieren. Gleichzeitig mĂŒssen wir uns daran erinnern, dass Spark im Allgemeinen nicht sehr gut zum Erstellen eigener Frameworks geeignet ist.
Zum Beispiel ist Spark so konzipiert, dass der Code ungefĂ€hr so ââaussieht (Pseudocode):
park.sql(âselect table1.field1 from table1, table2 where table1.id = table2.idâ).write(...pathToDestTable)
Stattdessen mĂŒssen Sie so etwas tun:
var Source1 = readSourceProps(âsource1â) var sql = readSQL(âdestTableâ) writeSparkData(source1, sql)
Nehmen Sie also Codeblöcke in separate Prozeduren heraus und versuchen Sie, etwas Eigenes, Universelles zu schreiben, das durch Einstellungen angepasst werden kann.
Gleichzeitig bleibt die KomplexitĂ€t des Projekts natĂŒrlich auf dem gleichen Niveau, jedoch nur fĂŒr den Autor des Projekts und nur fĂŒr kurze Zeit. Jeder eingeladene Programmierer wird lange brauchen, um es zu beherrschen, und die Hauptsache ist, dass es nicht funktioniert, Leute, die nur SQL kennen, fĂŒr das Projekt zu gewinnen.
Dies ist bedauerlich, da Spark selbst eine groĂartige Möglichkeit ist, ETL-Anwendungen fĂŒr diejenigen zu entwickeln, die nur SQL kennen.
Und im Verlauf der Projektentwicklung stellte sich heraus, dass aus einer einfachen Sache eine komplexe wurde.
Stellen Sie sich nun ein reales Projekt vor, in dem es Dutzende oder sogar Hunderte solcher Schaufenster wie auf dem Bild gibt und die unterschiedliche Technologien verwenden. Einige davon können beispielsweise auf dem Parsen von XML-Daten und andere auf Streaming-Daten basieren.
Ich möchte die KomplexitÀt des Projekts irgendwie auf einem akzeptablen Niveau halten. Wie kann das gemacht werden?
Die Lösung kann darin bestehen, einen Tool- und Low-Code-Ansatz zu verwenden, wenn die Entwicklungsumgebung fĂŒr Sie entscheidet, was die gesamte KomplexitĂ€t in Anspruch nimmt und einen praktischen Ansatz bietet, wie er beispielsweise in diesem Artikel beschrieben wird .
Dieser Artikel beschreibt die AnsÀtze und Vorteile der Verwendung des Tools zur Lösung dieser Art von Problemen. Insbesondere bietet Neoflex eine eigene Lösung Neoflex Datagram an, die von verschiedenen Kunden erfolgreich eingesetzt wird.
Es ist jedoch nicht immer möglich, eine solche Anwendung zu verwenden.
Was ist zu tun?
In diesem Fall verwenden wir einen Ansatz, der ĂŒblicherweise Orc - Object Spark oder Orka genannt wird, wie Sie möchten.
Die anfÀnglichen Daten lauten wie folgt:
Es gibt einen Kunden, der einen Arbeitsplatz mit einem Standardsatz von Tools bereitstellt, nĂ€mlich: Farbton fĂŒr die Entwicklung von Python- oder Scala-Code, Farbtoneditoren fĂŒr das SQL-Debugging ĂŒber Hive oder Impala und Oozie-Workflow-Editor. Dies ist nicht viel, aber völlig ausreichend, um Probleme zu lösen. Es ist aus verschiedenen GrĂŒnden unmöglich, der Umgebung etwas hinzuzufĂŒgen, es ist unmöglich, neue Tools zu installieren.
Wie entwickeln Sie ETL-Anwendungen, die wie ĂŒblich zu einem groĂen Projekt werden, an dem Hunderte von Datenquellentabellen und Dutzende von Ziel-Marts beteiligt sind, ohne an KomplexitĂ€t zu ertrinken und nicht zu viel zu schreiben?
Eine Reihe von Bestimmungen wird verwendet, um das Problem zu lösen. Sie sind keine eigene Erfindung, sondern basieren vollstÀndig auf der Architektur von Spark.
- Alle komplexen VerknĂŒpfungen, Berechnungen und Transformationen werden ĂŒber Spark SQL ausgefĂŒhrt. Der Spark SQL-Optimierer verbessert sich mit jeder Version und funktioniert sehr gut. Daher geben wir dem Optimierer die gesamte Arbeit zur Berechnung von Spark SQL. Das heiĂt, unser Code basiert auf der SQL-Kette, in der Schritt 1 die Daten vorbereitet, Schritt 2 beitritt, Schritt 3 berechnet und so weiter.
- Spark, Spark SQL. (DataFrame) Spark SQL.
- Spark Directed Acicled Graph, , , , , 2, 2.
- Spark lazy, , , .
Dadurch kann die gesamte Anwendung sehr einfach gestaltet werden.
Es reicht aus, eine Konfigurationsdatei zu erstellen, in der eine einstufige Liste von Datenquellen definiert wird. Diese sequentielle Liste von Datenquellen ist das Objekt, das die Logik der gesamten Anwendung beschreibt.
Jede Datenquelle enthĂ€lt einen Link zu SQL. In SQL können Sie fĂŒr die aktuelle Quelle eine Quelle verwenden, die sich nicht in Hive befindet, sondern in der Konfigurationsdatei ĂŒber der aktuellen beschrieben ist.
Zum Beispiel sieht Quelle 2, wenn sie in Spark-Code ĂŒbersetzt wird, ungefĂ€hr so ââaus (Pseudocode):
var df = spark.sql(âselect * from t1â); df.saveAsTempTable(âsource2â);
Und Quelle 3 könnte bereits so aussehen:
var df = spark.sql(âselect count(*) from source2â) df.saveAsTempTable(âsource3â);
Das heiĂt, Quelle 3 sieht alles, was zuvor berechnet wurde.
FĂŒr Quellen, bei denen es sich um Zielvitrinen handelt, mĂŒssen Sie die Parameter zum Speichern dieser Zielvitrine angeben.
Infolgedessen sieht die Anwendungskonfigurationsdatei folgendermaĂen aus:
[{name: âsource1â, sql: âselect * from t1â}, {name: âsource2â, sql: âselect count(*) from source1â}, ... {name: âtargetShowCase1â, sql: â...â, target: True, format: âPARQETâ, path: â...â}]
Und der Anwendungscode sieht ungefĂ€hr so ââaus:
List = readCfg(...) For each source in List: df = spark.sql(source.sql).saveAsTempTable(source.name) If(source.target == true) { df.write(âformatâ, source.format).save(source.path) }
Dies ist in der Tat die gesamte Anwendung. AuĂer einem Moment ist nichts anderes erforderlich.
Wie kann man das alles debuggen?
Immerhin ist der Code selbst in diesem Fall sehr einfach, was zum Debuggen da ist, aber die Logik dessen, was getan wird, wĂ€re schön zu ĂŒberprĂŒfen. Das Debuggen ist sehr einfach - Sie mĂŒssen alle Anwendungen bis zur ĂŒberprĂŒften Quelle durchgehen. Dazu mĂŒssen Sie dem Oozie-Workflow einen Parameter hinzufĂŒgen, mit dem Sie die Anwendung an der erforderlichen Datenquelle stoppen können, indem Sie das Schema und den Inhalt in das Protokoll drucken.
Wir haben diesen Ansatz Object Spark in dem Sinne genannt, dass die gesamte Anwendungslogik vom Spark-Code entkoppelt und in einer einzigen, ziemlich einfachen Konfigurationsdatei gespeichert ist, bei der es sich um das Anwendungsbeschreibungsobjekt handelt.
Der Code bleibt einfach und nach seiner Erstellung können auch komplexe Storefronts mit Programmierern entwickelt werden, die nur SQL kennen.
Der Entwicklungsprozess ist sehr einfach. Zu Beginn ist ein erfahrener Spark-Programmierer beteiligt, der universellen Code erstellt. AnschlieĂend wird die Anwendungskonfigurationsdatei bearbeitet, indem dort neue Quellen hinzugefĂŒgt werden.
Was dieser Ansatz bietet:
- Sie können SQL-Programmierer in die Entwicklung einbeziehen.
- Unter BerĂŒcksichtigung des Parameters in Oozie wird das Debuggen einer solchen Anwendung einfach und unkompliziert. Dies ist das Debuggen eines Zwischenschritts. Die Anwendung arbeitet alles bis zur gewĂŒnschten Quelle, berechnet es und stoppt;
- ( ⊠), , , , , . , Object Spark;
- , . . , , , XML JSON, -. , ;
- . , , , , .