# Daten "Normalisierung" aus verschiedenen Quellen



## OnDemand (13. Mrz 2021)

Hallo zusammen,

ich überlege grad ob es noch einfachere Möglichkeiten für folgendes gibt:

Für ein Projekt hole ich aus 13 Quellen Daten, diese Daten müssen im System zwischengespeichert werden um dann für andere Systeme verfügbar gemacht zu werden. Dabei ist jede Datenquelle komplett anders aufgebaut.

Man kann sich das so vorstellen als hätte man ein ERP System. In dieses ERP System holen wir Produktdaten von sämtlichen Herstellern (jeder Hersteller hat dabei eine andere API was Aufbau & Co angeht). 

Nun haben wir es so geplant, dass wir eine nennen wir es "normalisierte" Form eines ERP-Entity erstellen und alle anderen Daten darauf passend machen und speichern.

Hier mal eine sehr vereinfachte Form (Dummycode)


```
class ErpEntity {
    String name;
    String beschreibung;
    Double preis;
    //und noch viele viele mehr
}
```


```
class ObjectFromManufacturerA{
    String title;
    String purchasePrice;
    //und noch viele mehr
}
```

Nun bauen wir aus dem ManufacturerObjekt ein ERP-Objekt und speichern es ab. Dann haben wir in unserem System eine einheitliche Datenstruktur welches wir an weitere Systeme weiterleiten können.


```
class Mapper {
    
    mapIt(ObjectFromManufacturerA objectFromManufacturerA){
        ErpEntity ee = new ErpEntity();
        ee.setPrice (objectFromManufacturerA.getPurchasePrice());
        ee.set ....

save(ee);
    }
    
}
```

Hat jemand noch ne bessere Idee wie man aus Objekt A ein ErpEntity bekommt? Das doofe ist halt, dass jeder Hersteller eine komplett andere Datenstruktur hat und da alles manuell angefasst werden muss um das zum ErpEntity zu bekommen


----------



## Robert Zenz (13. Mrz 2021)

Nein, wird nicht besser. Du kannst anfangen dir einen Helfer mit Reflection und Annotations zu schreiben, aber das macht die Sache alles nicht besser. In einem Projekt hatten wir auch einen generischen Mapper welcher Feldangaben aus einer Konfigurationsdatei verwendete um diese direkt zu mappen mit Hilfe von Reflection, hat die Sache auch nicht leichter zu warten gemacht meiner Meinung nach.

Ueberlege dir ob vielleicht die Konvertierungsmethode direkt in "ObjectFromManufacturerA" Sinn macht, anstelle einer eigenen Klasse, also eine "toErpObject" Methode dort. Da diese Klassen nur den Zweck haben ein "Zwischenschritt" auf dem Weg zu sein, wuerde es Sinn machen dort direkt die Methode zu haben anstelle sich noch eine Schicht aufzureissen, insbesondere dann wenn es immer nur einen Weg geben kann um diese Klassen zu konvertieren. Eventuell macht es auch schon Sinn einen Schritt frueher anzusetzen, so dass du schon nicht die spezifischen Klassen hast, sondern nur ErpEntitys rauswirfst aus den Klassen welche die Daten liefern. Also dass der eine Zwischenschritt ueber diese Klasse weggelassen wird (haette auch den Vorteil dass weniger Garbage anfaellt). Kommt natuerlich auf die Schnittstelle an der Stelle an. Damit koenntest du naemlich auch relativ simpel deine Datenlieferanten auf ein Interface reduzieren, und diese kovnertieren intern die Daten und reichen sie dann nach auszen als ErpEntity. Halbwegs sauber strukturiert kannst du da dann auch ganz einfach Unittests fuer die Konvertierung schreiben.


----------



## OnDemand (13. Mrz 2021)

Danke ich hab es befürchtet  die meisten Quellen sind JSON API, noch schlimmer ist es bei txt Datein 🤢


----------



## mrBrown (13. Mrz 2021)

Man kann sich das "manuelle Mapping" _etwas_ vereinfachen, wenn man sowas wie Mapstruct oder Dozer nutzt, mit letzterem kann man die Mapping-Konfiguration dann auch wenn nötig in Konfigurations-Dateien auslagern.


Wie @Robert Zenz schon sagte sollte man die Sichtbarkeit des ganzen aber möglichst beschränken. Das eigentliche System kennt also nur die ErpEntity, und das Abfragen der Daten und das Mappen zu ErpEntity ist gekapselt in einem eigenem Package/Modul.


----------



## Meniskusschaden (13. Mrz 2021)

NicoDeluxe hat gesagt.:


> Hat jemand noch ne bessere Idee wie man aus Objekt A ein ErpEntity bekommt? Das doofe ist halt, dass jeder Hersteller eine komplett andere Datenstruktur hat und da alles manuell angefasst werden muss um das zum ErpEntity zu bekommen


Ich weiß nicht, ob es wirklich besser ist, aber für den gesamten Weg von den Hersteller-APIs bis in das eigene ERP-System würde ich komplett auf Programmierung verzichten und einfach ein ETL-Tool verwenden. Das Mapping der Hersteller-Informationen auf die eigene Datenstruktur kann doch bestimmt recht vielfältig werden und beschränkt sich vermutlich nicht nur auf einfache "Quellfeld-A nach Zielfeld-B"-Zuordnungen, sondern könnte auch komplexere Transformationen erfordern. Da hätte ich gerne die Macht eines solchen Tools zur Verfügung.
Damit würde ich die im ERP-System benötigten und direkt vorgesehenen Felder befüllen und alles wofür es im ERP keine Felder gibt, würde ich in Form von Sachmerkmalen bzw. Key-Value-Paaren als Zusatzinformationen bereit stellen. Dann hat man eben je eine hersteller-spezifische ETL-Transformation aber keine Hersteller-Spezifika in Anwendungscode oder Datenbank.


----------



## OnDemand (13. Mrz 2021)

Genau, ist nicht nur von A nach B sondern bedarf noch einiger Anpassungen. Zum Beispiel liefert ein Hersteller Bruttopreise, die müssen in netto gewandelt werden. Andere liefern keine sauberen EAN Nummern da müssen wir über ein wiederum anderes Tool erst passende ran holen usw


----------



## mihe7 (14. Mrz 2021)

NicoDeluxe hat gesagt.:


> Hat jemand noch ne bessere Idee wie man aus Objekt A ein ErpEntity bekommt? Das doofe ist halt, dass jeder Hersteller eine komplett andere Datenstruktur hat und da alles manuell angefasst werden muss um das zum ErpEntity zu bekommen


Was ich manchmal bei solchen Dingen mache: erstmal in eine DB importieren und dann per SQL arbeiten, um mch dem gewünschten Ergebnis anzunähern, z. B. in Form einer View. Dann muss ich mich um lästige Dinge nicht im Programm kümmern


----------



## Dukel (14. Mrz 2021)

NicoDeluxe hat gesagt.:


> Genau, ist nicht nur von A nach B sondern bedarf noch einiger Anpassungen. Zum Beispiel liefert ein Hersteller Bruttopreise, die müssen in netto gewandelt werden. Andere liefern keine sauberen EAN Nummern da müssen wir über ein wiederum anderes Tool erst passende ran holen usw


Genau das machen ETL Tools auch. Das T steht dabei für _transform_.


----------



## OnDemand (14. Mrz 2021)

Was ist ein ETL Tool oO noch nie gehört. Was Wikipedia schreibt liest sich ja genau nach dem, was ich brauche
_Extraktion_der relevanten Daten aus verschiedenen Quellen_Transformation_der Daten in das Schema und Format der Zieldatenbank_Laden_der Daten in die Zieldatenbank

So wie ich das verstehe ich das ein externes Tool, welchem ich sage wie die Daten aufgebaut sind und es das in meine DB schiebt?! Ist ja quasi das selbe wie ich es mache in meinen Beispielklassen oben. Hatte auch schon die Idee, eine Art template für jede Quelle anzulegen in welcher Steht in der Spalte A steht der Preis, Spalte B der Name usw.  Wird dann aber schnell sehr komplex, wenn es Artikel gibt welche Eigenschaften haben (kennt man zb beim shoppen wenn es eine Hose in verschiedenen Größen gibt, mit einem Dropdown)

Hat jemand zufällig ein Beispiel? Hab mir grad Penthao angesehen, versteh ich spontan erstmal nicht


----------



## temi (14. Mrz 2021)

Hier gibt es eine Übersicht https://github.com/pawl/awesome-etl


----------



## OnDemand (14. Mrz 2021)

Danke, hab mir mal Penthao installiert, ok Prinzip kapiert. Aber das ist ja eine Standalone App. 
Ich brauch die Funktion quasi in meinem Programm. In deinem Link springt mich sofort spring Batch an. Ich nutze Spring Boot. Das schau ich mir direkt ma an


----------



## temi (14. Mrz 2021)

NicoDeluxe hat gesagt.:


> Aber das ist ja eine Standalone App.
> Ich brauch die Funktion quasi in meinem Programm.


Ist das wirklich so? Ich kenne ja dein Programm nicht, aber es ist ja durchaus denkbar, dass der Import als separater Prozess (auch mit einer separaten Software) läuft, der die DB immer up-to-date hält. Dein Programm nutzt anschließend nur die DB.


----------



## OnDemand (14. Mrz 2021)

Dann müsste man es pro Kunden nochmal konfigurieren.
Angenommen User A meiner Software will, dass das Programm Daten von Hersteller A holt.
Der User A hat bei Hersteller A aber andere Logindaten, als User B um an die Daten zu kommen.


----------



## Meniskusschaden (14. Mrz 2021)

NicoDeluxe hat gesagt.:


> Dann müsste man es pro Kunden nochmal konfigurieren.
> Angenommen User A meiner Software will, dass das Programm Daten von Hersteller A holt.
> Der User A hat bei Hersteller A aber andere Logindaten, als User B um an die Daten zu kommen.


Bedeutet das, du bekommst abhängig vom Kunden bei demselben Hersteller zwar gleich strukturierte Daten aber jeweils unterschiedliche Inhalte? Dann müsstest du die Zugangsdaten ja schon irgendwo in deiner DB haben. Die sollte sich das ETL-Tool ja von dort holen können, um dieselbe Transformation mehrmals mit unterschiedlichen Parametern aufzurufen. Dann müsste eine Konfiguration pro Hersteller ausreichen.

Ich würde mir die Transformation auch als getrennten Prozess vorstellen, so wie @temi es vorgeschlagen hat. Dadurch hat man aber natürlich eine Pufferung. Wenn die nicht akzeptabel ist, sondern die Kunden über eure Software in Echtzeit auf die Herstellerinformationen zugreifen müssen, wird es mit dem Ansatz schwierig.


----------



## OnDemand (14. Mrz 2021)

Ja stimmt, die Zugangsdaten haben wir abgespichert, da könnte das ETL Tool ran kommen. In Echtzeit greift keiner zu. Geht eher darum immer aktuelle Daten bei uns in der DB zu haben. Hab leider kein tool gefunden welches auch im Browser läuft (da unsere VMs keine GUI haben, sind reine Debianserver - da wird es schwierig).


----------



## Meniskusschaden (14. Mrz 2021)

NicoDeluxe hat gesagt.:


> Hab leider kein tool gefunden welches auch im Browser läuft


Ich weiß nicht, ob es das gibt, aber ich sehe auch die Notwendigkeit nicht. Normalerweise sollte die Konfiguration zentral in irgendeiner Form von Repository liegen, z.B. als eigene Datenbank. Die Pflege erfolgt remote über eine Clientsoftware. Für die Ausführung der Transformationen sollte keine GUI erforderlich sein.


----------



## OnDemand (14. Mrz 2021)

Ahha verstehe. Welches ETL Tool wäre denn am einfachsten zu nutzen? Der Prozess sollte dann als Service auf dem Debian laufen, richtig?
In Penthao Kettle kann man sein "Template" exportieren, das sollte dann von allesn Clients benutzt werden um Hersteller A zu importieren. Wenn man das Template updated, kann man das sicherlich irgendwie an die Clients verteilen. Das klingt erstmal hervorragend, aber die Umsetzung uiuiui sieht sehr komplex aus so ein ETL Tool


----------



## OnDemand (14. Mrz 2021)

Könnte man mit dem ETL auch folgendes umsetzen: Wenn Produkt XY schon existiert, nur den Namen updaten oder nur den Preis usw? Dann müsste das ETL erstmal wissen ob das Produkt schon existiert.


----------



## Meniskusschaden (14. Mrz 2021)

NicoDeluxe hat gesagt.:


> Welches ETL Tool wäre denn am einfachsten zu nutzen?


Ich habe da leider keinen Marktüberblick. Uns genügt die Community-Edition von Pentaho Data Integration (PDI), also die ETL-Komponente der Pentaho Suite.


NicoDeluxe hat gesagt.:


> Der Prozess sollte dann als Service auf dem Debian laufen, richtig?


Wir starten dazu einfach auf unserem "Integrationsserver" zeitgesteuert per Job-Scheduler die CLI-Befehle von PDI (pan bzw. kitchen). Also ziemlich banal. Dort liegt auch das Repository. In eurem Fall wäre das wohl der Debian-Server. Prinzipiell könnte man das bestimmt auch gut auf mehrere Server verteilen, falls man Lastprobleme hat.


NicoDeluxe hat gesagt.:


> In Penthao Kettle kann man sein "Template" exportieren, das sollte dann von allesn Clients benutzt werden um Hersteller A zu importieren. Wenn man das Template updated, kann man das sicherlich irgendwie an die Clients verteilen.


Ich bin nicht sicher, was du hier mit den Clients meinst. Das Konfigurationstool? Zur Definition der Transformationen benutzen wir das GUI-Tool von PDI (spoon). Das kann man prinzipiell von jedem Desktop aus starten, benötigt aber Zugriff auf das Repository (bei uns auf dem Integrationsserver). Wir arbeiten dann auch direkt auf dem Repository und exportieren da nichts mehr. Bei höheren Qualitätssicherungsanforderungen würde man sich vermutlich noch ein Test-Repository anlegen und müsste seine Transformationen dann irgendwie in die Produktionsumgebung übertragen. Vielleicht funktioniert es auch, statt eines DB-Repositories ein Dateisystem-basiertes Repository zu verwenden und unter Versionskontrolle zu stellen. Das habe ich aber noch nie ausprobiert.


NicoDeluxe hat gesagt.:


> Könnte man mit dem ETL auch folgendes umsetzen: Wenn Produkt XY schon existiert, nur den Namen updaten oder nur den Preis usw? Dann müsste das ETL erstmal wissen ob das Produkt schon existiert.


So eine Transformation kann natürlich beliebig komplex werden. Im einfachsten Fall würde hier wohl ein einfacher Insert-/Update-Schritt am Ende der Transformation ausreichen. Hier ist mal ein einfaches Beispiel. Falls der EAN-Code noch nicht im ERP existiert, wird er mit Name und Preis erstellt, andernfalls erfolgt ein Update auf den Preis, aber nicht auf den Namen.


----------



## OnDemand (15. Mrz 2021)

Das klingt zu gut um wahr zu sein!

Manche Hersteller liefern Bilder per Link, diese müssen wir herunterladen. Ginge das?

Könnte man auch folgendes abbilden:
Wir haben eine CSV Datei. Es gibt Artikel die gibt es in verschiedenen Größen. Jede Zeile ist dabei eine Variante. Das ist natürlich wieder bei jedem Hersteller anders.

Ein Beispiel

SKU; VATER; NAME; Farbe
123; AAA; Herrenhose; rot
456; AAA; Herrenhose; blau

Das ist quasi eine Herrenhose mit der Haupt-SKU AAA welche es in 2 Farben gibt.

Unser Objekt sieht in etwa so aus:

[CODE lang="java" title="Product.java"]class Product (){
    String mainSku;
    List<Combinations> combinations;
}

class Combinations (){
    String sku;
    String farbe;
} [/CODE]


----------



## OnDemand (15. Mrz 2021)

Hab mir mal einen Udemy Kurs gekauft, wenn das funktioniert wie ich mir das vorstelle wäre das genial!

Ziel ist es eine zentrale zu haben, wo die "templates" von uns vorgefertigt liegen auf welches alle Clients zugreifen können. Sodass wir die nur an einer Stelle bearbeiten müssen falls sich was ändert


----------



## Meniskusschaden (15. Mrz 2021)

NicoDeluxe hat gesagt.:


> Manche Hersteller liefern Bilder per Link, diese müssen wir herunterladen. Ginge das?


Ja, das sollte funktionieren. Für den Anwendungsfall würde man sich einen http(s)-Download in der Transformation wünschen. PDI bietet das derzeit zwar nur im Job an, aber man kann Jobs aus Transformationen heraus aufrufen (der Normalfall ist anders herum), so dass das keine Einschränkung ist (eigentlich sind Jobs eher dazu gedacht, den ETL-Prozess zu koordinieren und die Transformationen machen die Arbeit).


NicoDeluxe hat gesagt.:


> Könnte man auch folgendes abbilden:
> Wir haben eine CSV Datei. Es gibt Artikel die gibt es in verschiedenen Größen. Jede Zeile ist dabei eine Variante. Das ist natürlich wieder bei jedem Hersteller anders.


Das sieht auch nicht so schwierig aus. Allerdings sind aus ETL-Sicht eher die DB-Tabellen interessant, nicht so sehr die Java-Ḱlassen.


----------

