Der Blog-Bei­trag Data Engi­nee­ring mit Tal­end aus dem letz­ten Jahr war dem Tal­end-Öko­sys­tem und den all­ge­mei­nen Mög­lich­kei­ten für das Data Engi­nee­ring gewid­met. An die­ser Stelle wird nun beschrie­ben, wie mit zwei grund­le­gen­den Design­ent­schei­dun­gen die Erfolgs­wahr­schein­lich­keit von Tal­end-Pro­jek­ten erhöht wer­den kann. Diese Design­kon­zepte kön­nen die Ent­wick­lungs­ar­beit und die Feh­ler­an­fäl­lig­keit der Daten­stre­cken deut­lich redu­zie­ren und wei­ter­hin die Anwen­dungs­sze­na­rien ein­zel­ner Daten­stre­cken und Job­ket­ten erwei­tern bzw. gene­ra­li­sie­ren. Der Anspruch dabei ist es die Mög­lich­kei­ten von Tal­end so ein­zu­set­zen, dass die Ent­wick­lung so sim­pel wie mög­lich ist, eine hohe Kon­sis­tenz auf­weist und die Jobs gut wart­bar sind. Ins­be­son­dere die her­aus­ste­chende Eigen­schaft von Tal­end, eige­nen Java-Code ein­zu­bin­den, führt zu neuen Her­aus­for­de­run­gen, die in der Ent­wick­lung berück­sich­tigt wer­den müs­sen. Einer­seits ergibt sich zwar eine hohe Fle­xi­bi­li­tät in der Ent­wick­lung, da nicht nur auf vor­ge­fer­tigte Funk­tio­nen und Daten­bank­fä­hig­kei­ten gesetzt wer­den muss. Ande­rer­seits ent­steht dadurch auch die Anfor­de­rung Stan­dards in der Ent­wick­lung ein­zu­füh­ren, die zu wie­der­ver­wend­ba­ren Code und einer kon­sis­ten­ten Ent­wick­lung bei­tra­gen. Des Wei­te­ren kann die Fähig­keit von Tal­end genutzt wer­den, um wäh­rend der Job-Aus­füh­rung auf unter­schied­li­che Varia­blen zuzu­grei­fen und somit dyna­misch gene­rier­ten SQL-Code zu nut­zen, wel­cher eine hohe Fle­xi­bi­li­tät der Ver­wend­bar­keit von ein­zel­nen Jobs ermöglicht.

Das Java-Repo­si­tory

In Tal­end kann kom­ple­xer und häu­fig gebrauch­ter Java-Code in einem gemein­sa­men Repo­si­tory abge­legt wer­den, den Code-Rou­ti­nen. Diese Java-Rou­ti­nen kön­nen dann in sämt­li­chen Jobs direkt ver­wen­det wer­den. Auch wenn Tal­end bereits von Haus aus die Viel­zahl an nati­ven Java-Funk­tio­nen unter­stützt und diese auch um eigene Funk­tio­nen erwei­tert, bie­tet ein gut gepfleg­tes Java-Code-Repo­si­tory in Tal­end viele Vor­teile. Der größte Mehr­wert von eige­nen Code-Rou­ti­nen bie­tet die Wie­der­ver­wend­bar­keit des Codes. So müs­sen häu­fig genutzte Trans­for­ma­tio­nen nur ein­mal ent­wi­ckelt und Ände­run­gen ledig­lich ein­ma­lig vor­ge­nom­men wer­den, da alle Tal­end-Jobs die geän­derte Logik auto­ma­tisch über­neh­men. Dies kann den Auf­wand in der Ent­wick­lung, die Feh­ler­an­fäl­lig­keit und War­tung in den Daten­stre­cken deut­lich reduzieren.

Braucht man zum Bei­spiel regel­mä­ßig Sub­strings bis zu einem bestimm­ten Trenn­zei­chen, bie­tet es sich an dafür eine Java-Klasse zu erstel­len, da somit nicht bei jeder Anwen­dung eine Trans­for­ma­tion mit den Tal­end nati­ven Metho­den geschrie­ben wer­den muss. Diese Java-Funk­tion würde dann den voll­stän­di­gen String und das gewünschte Trenn­zei­chen als Ein­gabe benö­ti­gen und schließ­lich den gewünsch­ten Sub­string als Ergeb­nis liefern:

package routines;
public class MyStringUtil {
public static String getStringToDelim(String text, String delimiter) {
	String result = null;
	if (text != null && !text.trim().equals("")
				&& text.indexOf(delimiter) != -1)  {
		result = text.substring(0, text.indexOf(delimiter));
	} else {
		result = text;
	}
	return result;
  }
}

Das Code-Bei­spiel macht dabei von den Java-Metho­den “sub­string()” und “indexOf()” Gebrauch, um einen neuen String zu erzeu­gen. Bei der Ent­wick­lung mit Tal­end ist es wich­tig zu berück­sich­ti­gen, dass nur von den Java-Metho­den unter­stützte Inputs ver­ar­bei­tet wer­den. Wird bei der Ent­wick­lung auf native Java-Funk­tio­nen direkt in Tal­end-Kom­po­nen­ten gesetzt, muss der Ent­wick­ler bei jeder Trans­for­ma­tion die mög­li­chen Pro­bleme, zu denen unge­wöhn­li­che Input-Werte füh­ren kön­nen, berück­sich­ti­gen. Nutzt man hin­ge­gen die Code-Rou­ti­nen lässt sich direkt im Code sicher­stel­len, dass nur gül­tige Werte mit den jewei­li­gen Funk­tio­nen ver­ar­bei­tet wer­den. In dem Bei­spiel wird dabei zum einen dar­auf geach­tet, dass bei einem null-Wert als Ein­gabe die Funk­tion null zurück­gibt, da sonst der Tal­end-Job mit einer „Null­Poin­ter­Ex­cep­tion“ als Feh­ler­mel­dung abbre­chen würde. Der letzte Teil der If-Anwei­sung ver­hin­dert “IndexOu­tOf­Bounds­Excep­ti­ons” als Feh­ler­mel­dung, wenn der ein­ge­ge­bene String leer ist oder aber das Trenn­zei­chen nicht in dem String ent­hal­ten ist. Im ers­ten Fall wird ein null-Wert zurück­ge­ge­ben im zwei­ten Fall der voll­stän­dige String.

Diese Funk­tion lässt sich anschlie­ßend an jeder mög­li­chen Stelle in den Daten­stre­cken aufrufen:

MyStringUtil.getStringToDelim(row1.exampleString,".")

Der Code aus dem eige­nen Java-Repo­si­tory bie­tet somit eine Lösung für häu­fige Auf­ga­ben an, die bereits aus­führ­lich getes­tet ist und daher den Auf­wand wie die Feh­ler­an­fäl­lig­keit in der Ent­wick­lung redu­zie­ren kann.

Dyna­mi­scher SQL-Code

Wer­den bestimmte SQL-Frag­mente in der Ent­wick­lung der Tal­end-Jobs öfter ver­wen­det, kann es sinn­voll sein diese eben­falls als Java-Code im Repo­si­tory abzu­le­gen, da diese dann auch für alle Jobs simul­tan geän­dert wer­den kön­nen. Soll der SQL-Code hin­ge­gen wäh­rend der Aus­füh­rung des Jobs erstellt wer­den, müs­sen andere Eigen­schaf­ten von Tal­end ange­wandt wer­den. Denn in die­sem Fall kann die SQL-Syn­tax nicht direkt in die jewei­li­gen Kom­po­nen­ten ein­ge­tra­gen wer­den, son­dern muss dyna­misch beim Aus­füh­ren des Jobs erzeugt wer­den. Tal­end bie­tet zwei Mög­lich­kei­ten, um Varia­blen dyna­misch beim Aus­füh­ren eines Jobs zu erzeu­gen, wel­che dann für einen dyna­mi­schen SQL-Code genutzt wer­den können:

  • Kon­text­va­ria­blen: Kön­nen vor der Aus­füh­rung des Jobs durch Aus­wäh­len einer bestimm­ten Kon­text-Umge­bung oder durch einen impli­zi­ten Kon­text­load gesetzt wer­den. Auch eine tJava-Kom­po­nente ermög­licht das Set­zen von Kon­text­va­ria­blen wäh­rend der Aus­füh­rung. Sie eig­nen sich vor allem zum Set­zen der Daten­bank-Ebene, um das Aus­füh­ren der Jobs in unter­schied­li­chen Umge­bun­gen zu ermöglichen.
  • glo­bal­Map: Diese zen­trale Java Hash­Map ermög­licht es inner­halb von Tal­end-Jobs Daten zu spei­chern, auf wel­che im wei­te­ren Ver­lauf zuge­grif­fen wer­den kön­nen. So kann die glo­bal­Map genutzt wer­den, um rele­vante Infor­ma­tio­nen, die für das Erstel­len von SQL-State­ments benö­tigt wer­den, aus ande­ren Quel­len zu extra­hie­ren. Die glo­bal­Map wird nicht nur vom Ent­wick­ler aktiv genutzt, son­dern auch von Tal­end selbst. So wer­den für viele Kom­po­nen­ten die Anzahl der ver­ar­bei­te­ten Spal­ten sowie Feh­ler­mel­dun­gen in die glo­bal­Map geschrie­ben. Diese Infor­ma­tio­nen las­sen sich gut für eine früh­zei­tige Feh­ler­er­ken­nung mit Hilfe von tWarn oder tDie Kom­po­nen­ten nutzen.

In fol­gen­der Abbil­dung ist ein Bei­spiel für die Anwen­dung von dyna­mi­schen SQL-Code in Tal­end gegeben:

Talend Designentscheidungen zur Entwicklung flexibler ETL-Strecken Bild1
Abbil­dung 1 Dyna­mi­scher SQL

Dabei wird zum einen von der Kon­text­va­ria­ble „DB_Ebene“ Gebrauch gemacht, um die Umge­bung, auf wel­che die Daten­bank-Kom­po­nente (5.) zugreift, zu defi­nie­ren. Zum ande­ren sind not­wen­dige Ein­schrän­kun­gen für das SQL-State­ment in einer Text­da­tei abge­legt, wel­che in der Kon­struk­tion der Daten­bank-Quelle (5.) genutzt wer­den sol­len. Dies kann sinn­voll sein, wenn die benö­tig­ten Ein­schrän­kun­gen für unter­schied­li­che Daten­bank-Ebe­nen abwei­chen oder aber durch Busi­ness-Ana­lys­ten geän­dert wer­den sol­len. Die­ser Ansatz ermög­licht eine Steue­rung der Jobs außer­halb der Tal­end-Umge­bung, da ledig­lich durch Ände­run­gen die­ser Dateien die Tal­end-Jobs direkt beein­flusst werden.

Für das beschrie­bene Sze­na­rio wird die Anwen­dung der glo­bal­Map not­wen­dig, da die benö­tig­ten Infor­ma­tio­nen nicht mehr extra­hiert wer­den kön­nen sobald die Daten­bank­kom­po­nente (5.) aktiv wird. Daher muss ein vor­ge­la­ger­ter Sub­job erstellt wer­den, der die benö­tig­ten Where-Bedin­gun­gen aus der Datei aus­liest und diese zur Wei­ter­ver­wen­dung in die glo­bal­Map schreibt. Dateien zur dyna­mi­schen Kon­struk­tion von SQL-State­ments kön­nen unter­schied­li­che For­men auf­wei­sen, im Bei­spiel wird ange­nom­men, dass die Datei zwei Zei­len ent­hält, eine für den Namen der betrof­fe­nen Spalte und eine mit den rele­van­ten Ein­schrän­kun­gen. Nun kann mit einer tFi­xed­FlowIn­put-Kom­po­nen­ten (1.), wel­che alle Spal­ten­na­men der Quell­ta­belle ent­hält ein Lookup auf die Datei (2.) erfol­gen. Damit las­sen sich die rele­van­ten Spal­ten und ihre vor­ge­se­he­nen Ein­schrän­kun­gen ermit­teln, die im nächs­ten Schritt mit der tMap (3.) in die end­gül­ti­gen Where-Klau­seln mit SQL kon­for­mer Schreib­weise kon­ka­te­niert wer­den. Anschlie­ßend wird eine tJa­va­Row-Kom­po­nente (4.) genutzt, um so viele Bedin­gun­gen wie aus dem Lookup her­vor­ge­hen in die glo­bal­Map zu schrei­ben. Abschlie­ßend kann dann aus der Ver­bin­dung der Ein­träge in der glo­bal­Map und der Kon­text­fä­hig­kei­ten von Tal­end ein dyna­mi­sches SQL erstellt wer­den, für wel­ches erst wäh­rend der Job­aus­füh­rung alle not­wen­di­gen Infor­ma­tio­nen erzeugt werden.

Fazit

Tal­end bie­tet mit sei­ner offe­nen Art viele Frei­hei­ten, die es zu einer sehr fle­xi­blen Ent­wick­lungs­um­ge­bung für ETL-Stre­cken macht. Aller­dings soll­ten vor Pro­jekt­be­ginn grund­sätz­li­che Über­le­gun­gen getrof­fen wer­den, wie der opti­male Ent­wick­lungs­pro­zess aus­se­hen soll, damit diese Frei­hei­ten nicht ein unnö­tig kom­pli­zier­tes Ergeb­nis nach sich zie­hen. In die­sem Bei­trag wur­den fort­ge­schrit­tene Kon­zepte vor­ge­stellt, die dazu füh­ren sol­len, dass die Ent­wick­lungs­ar­beit ver­ein­facht wird, die Jobs eine höhere Kon­sis­tenz auf­wei­sen und vor allem auch bes­ser wart­bar wer­den und eine effi­zi­en­tere Feh­ler­su­che ermög­li­chen. Ins­be­son­dere das gute Pfle­gen des Tal­end Java-Repo­si­to­ries und der Kon­text­grup­pen ermög­licht es Ände­run­gen, wel­che eine Viel­zahl von Tal­end-Jobs betref­fen, an zen­tra­ler Stelle vor­zu­neh­men. Das Ver­wen­den von dyna­mi­schen SQL-Code hin­ge­gen ermög­licht einen viel­fäl­ti­gen Ein­satz der Jobs in unter­schied­li­chen Ebe­nen, mit abwei­chen­den Schema, Tabel­len oder Ein­schrän­kun­gen und kann somit den Ent­wick­lungs­auf­wand wei­ter redu­zie­ren. Die ange­spro­che­nen Fähig­kei­ten von Tal­end kön­nen zu einer bes­se­ren Ent­wick­lungs­ar­beit bei­tra­gen, wenn andere logi­sche Schritte wie klare Namens­kon­ven­tio­nen, sim­pel gehal­tene Job­ket­ten und dass sinn­volle Erstel­len von Joblets im Ent­wick­lungs­pro­zess Berück­sich­ti­gung finden.