Cookies für Statistik und Werbung
Wir setzen Cookies für Statistik und Werbung ein, beides geht an Google. Wenn du ablehnst, ändert sich für dich sichtbar nichts.Zur Datenschutzseite
NDJSON kannst du hier kostenlos und ohne Konto in Parquet umwandeln: Datei oben ablegen, und ein, zwei Sekunden später steht das Ergebnis zum Herunterladen bereit. Die Umwandlung läuft in deinem eigenen Browser, die Datei wird also nie hochgeladen — das klappt unter Windows, macOS und Linux ebenso wie auf iPhone und Android, und es funktioniert selbst dann noch, wenn du das Netz abschaltest.
Bis zu 100 Dateien auf einmal. Gemischte Formate sind kein Problem.
Sie werden nacheinander umgewandelt und kommen zusammen als ZIP zurück.
NDJSON in Parquet
Eine NDJSON-Datei aus einem Ereignis- oder Telemetriesystem enthält in aller Regel mehr als nur Klickpfade: IP-Adressen, Nutzerkennungen, Anfragepfade — alles, was eine Anwendung im laufenden Betrieb ohnehin protokolliert. Genau dieser Datentyp fällt unter die DSGVO, und ein Onlinedienst, der solche Rohdaten zur reinen Formatumwandlung an einen dritten Server schickt, hat damit unabhängig vom eigentlichen Analysezweck bereits eine zusätzliche Verarbeitung geschaffen, die begründet werden müsste.
Diese Umwandlung braucht keinen Server. Der Parquet-Schreiber ist JavaScript, das diese Seite bei Bedarf lädt, sodass die Ereignisse auf dem eigenen Rechner transponiert und geschrieben werden — die Frage, ob personenbezogene Rohdaten die eigene Infrastruktur verlassen, stellt sich für diesen Schritt gar nicht erst.
Genau das macht dieses Format-Paar interessant. Jede Zeile einer NDJSON-Datei steht für sich, und das ist der ganze Grund, warum Systeme an eine solche Datei anhängen: Ein neues Feld lässt sich am Dienstag im Schreiber ergänzen, ohne eine einzige vorhandene Zeile anzufassen. Über ein paar Monate Deployments hinweg sammelt eine einzelne Datei so mehrere Generationen von Datensatzform an.
Parquet duldet das nicht. Der Dateifuß legt eine feste Spaltenmenge mit je einem Typ fest, an die sich jede Zeile hält — genau das erlaubt einer Abfrage-Engine, eine zwei Gigabyte große Datei zu beschreiben, ohne eine einzige Zeile zu lesen. Die Umwandlung muss die verschiedenen Generationen also zu einem Schema zusammenführen, und alles Weitere ist eine Folge davon, wie sie das tut.
Ein Feld, das erst nach dreihunderttausend Zeilen zum ersten Mal auftaucht, wird trotzdem zu einer eigenen Spalte, und die Zeilen davor erhalten dafür Nullwerte. Das ist die einzige Zusammenführung, bei der garantiert nichts verloren geht, und der Grund, warum die gesamte Datei einmal vollständig gelesen wird, bevor überhaupt etwas geschrieben wird.
Viele Werkzeuge arbeiten stattdessen mit einer Stichprobe — den ersten tausend Zeilen, dem ersten Megabyte —, und genau das erklärt, warum ein Import, der auf einem Testausschnitt funktioniert hat, im Produktivbetrieb scheitert. Der Ausfall ist dabei schlimmer als eine Fehlermeldung: Ein aus einer Stichprobe abgeleitetes Schema verwirft jedes Feld, das es nicht gesehen hat, ohne eine Warnung.
Die andere Hälfte des Problems ist ein Feld, das seinen Namen behält, aber den Typ wechselt. Eine Kennung, die früher eine Zahl war und jetzt in Anführungszeichen steht, ein Status, der von einem Wahrheitswert zu einem Text wurde, eine Versionsnummer, die von 3 zu „3.1" wechselte — all das kommt in langlebigen Ereignisdateien vor, meist ohne dass es jemandem im Moment auffällt.
Der Typ jeder Spalte wird über sämtliche darin enthaltenen Werte bestimmt: lauter Wahrheitswerte ergeben BOOLEAN, lauter ganze Zahlen im 32-Bit-Bereich ergeben INT32, andere Zahlen ergeben DOUBLE, und alles Gemischte ergibt eine Textspalte, in der auch die numerischen Werte als Text erscheinen. Eine Textspalte ist sichtbar, lässt sich mit einem einzigen Ausdruck umwandeln und verwirft nie stillschweigend eine Zeile — anders als die Alternative, den ersten Typ zu übernehmen und den Rest zu Null zu machen.
Strukturierte Ereignisse verschachteln nach Konvention: ein request-Block, ein user-Block, ein context-Objekt mit einer Trace-Kennung. Parquet hat keinen Platz für ein Objekt innerhalb einer Zelle, also wird jeder Datensatz zuerst auf seine Blätter heruntergebrochen und der Pfad wird zum Spaltennamen — request.method, user.id, context.trace_id. Die Typen überstehen das, weil sie aus dem JSON selbst stammen und nicht neu aus Text geraten werden.
Arrays lohnen einen genaueren Blick vor der Umwandlung. Sie werden nach Position aufgefächert, ein tags-Array mit a und b wird also zu tags.0 und tags.1, und die Spaltenmenge ist die Vereinigung über die gesamte Datei — eine einzige sehr lange Liste irgendwo in einem Monat an Ereignissen weitet das Schema für den ganzen Monat auf. Wo ein Feld genuin variable Länge hat, ist es besser, es vorher in jq zu einem einzigen Text zusammenzufassen, als ein Schema hinzunehmen, das sich hinterher schwer erklären lässt.
Parquet kennt einen 64-Bit-Ganzzahltyp, den diese Umwandlung nie schreibt. Werte laufen durch JavaScript-Zahlen, die 53 Bit Ganzzahlgenauigkeit tragen, weshalb alles außerhalb des 32-Bit-Bereichs als DOUBLE geschrieben wird, statt eine Genauigkeit vorzutäuschen, die nicht mehr vorhanden ist.
Ereignisdateien sind voll von Werten, die das betrifft: Millisekunden-Zeitstempel, Snowflake-artige Kennungen, Byte-Zähler. Für einen Zeitstempel ist DOUBLE unbedenklich, die Genauigkeit reicht dafür bei Weitem. Für eine Kennung ist es das nicht, und die eigentliche Lösung liegt beim System, das die Ereignisse erzeugt: Kennungen als JSON-Text zu schreiben hält sie durch jeden Schritt dieser Pipeline exakt und lässt sie hier als Textspalte ankommen, was für eine Kennung ohnehin der richtige Typ ist.
Fünfzigtausend generierte Bestelldatensätze mit sechs Feldern kamen als Parquet auf 207 KB gegenüber 4,8 MB als NDJSON — besser als zwanzig zu eins bei diesen Daten. Die Form der Ersparnis zählt dabei mehr als die konkrete Ziffer, denn das Verhältnis hängt vollständig von den Daten ab.
Zwei Effekte wirken zusammen. Jede Zeile im NDJSON wiederholt jeden Feldnamen, bei sechs Feldern machen diese Namen also einen erheblichen Anteil der Bytes aus; in einer Spaltendatei steht jeder Name genau einmal im Dateifuß. Und gleichartige Werte, die beieinanderstehen, lassen sich weit stärker komprimieren als dieselben Werte, verteilt über einzelne Zeilen — eine Spalte mit Städtenamen oder Ereignistypen kostet dadurch fast nichts, während eine Spalte mit lauter individuellem Fließtext vergleichsweise wenig einspart.
Darin liegt eine gewisse Ironie. NDJSON existiert, damit ein Verarbeiter niemals die ganze Datei im Speicher halten muss, und diese Umwandlung hält doch die ganze Datei — weil erst die letzte Zeile eine Spalte hinzufügen oder deren Typ ändern kann und der Dateifuß erst geschrieben werden kann, wenn das feststeht.
Die Grenze ist also der Arbeitsspeicher, nicht ein Kontingent. Die freie Stufe akzeptiert bis zu 100 MB; einige Dutzend Megabyte laufen ohne Weiteres durch, mehrere hundert bringen einen Browser-Tab spürbar ins Schwitzen. Darüber hilft das Quellformat selbst: `split -l 500000` erzeugt gültige Teildateien, jede lässt sich einzeln umwandeln, und eine Abfrage-Engine liest ein Verzeichnis voller Parquet-Dateien als eine einzige Tabelle — genau dafür sind diese Werkzeuge gebaut.
DuckDB liest die Datei direkt in einer FROM-Klausel, pandas in einem Aufruf. Die erste Prüfung gilt der Spaltenliste und ihren Typen, nicht den ersten zehn Zeilen — mit drei konkreten Fragen: welche Spalten fast nur Nullwerte enthalten, welche als Text ankamen, obwohl sie Zahlen sein sollten, und wie viele Spalten es insgesamt gibt.
Jede Antwort ist eine Tatsache über die Quelle. Fast leere Spalten markieren, wo sich die Datensatzform geändert hat; unerwartete Textspalten markieren, wo ein Feld den Typ wechselte; mehr Spalten als erwartete Felder markieren einen verschachtelten Block oder ein Array, das breiter aufgefächert wurde als gedacht. Zwanzig Sekunden am Schema sparen die Stunde, die es kostet, einen dieser Punkte erst zu bemerken, nachdem die Datei bereits mit etwas anderem verknüpft wurde.
Die natürliche Einheit für diese Umwandlung ist ein Zeitraum, keine ganze Historie: ein Tag an Ereignissen, ein Monat, eine rotierte Logdatei. Jede wird für sich umgewandelt, und DuckDB, Spark und jedes Lakehouse-Tabellenformat lesen ein Verzeichnis solcher Dateien als eine einzige Tabelle mit beim Lesen zusammengeführten Schemas.
Das behandelt auch Drift besser als eine einzelne Datei: Ändert sich die Datensatzform, tragen die neuen Dateien die neuen Spalten, die alten nicht, und die Abfrage-Engine gleicht das beim Lesen aus statt der Konverter beim Schreiben. Nach Tag zu partitionieren und jeden Tag einmal umzuwandeln passt zu dieser Datenform und bedeutet, dass niemals die ganze Historie neu umgewandelt werden muss, nur weil ein Feld hinzukam.
| NDJSON | Parquet | |
|---|---|---|
| Vollständiger Name | Newline-Delimited JSON | Apache Parquet |
| Dateiendung | .ndjson, .jsonl | .parquet |
| Medientyp | application/x-ndjson | application/vnd.apache.parquet |
| Kompression | — | Verlustfrei — es wird nichts verworfen |
| Erstmals veröffentlicht | 2013 | 2013 |
| Herausgegeben von | — | Apache Software Foundation |
| Lizenzlage | Offener Standard | Offener Standard |
| Heutiger Stand | Aktuell | Aktuell |
| Öffnet im Browser | Kein Browser | Kein Browser |
| Stattdessen erwogen | JSON, CSV | CSV, JSON |
pandas liest sowohl NDJSON als auch Parquet — du kannst das Ergebnis also gegen das Original prüfen, ohne ein zweites Programm zu brauchen.
Parquet kommt von Apache Software Foundation und stammt aus 2013. pandas, Apache Spark und DuckDB lesen das Format.
Nein. Diese Umwandlung läuft vollständig in deinem Browser, die Datei verlässt dein Gerät also nicht. Du kannst das selbst nachprüfen: Öffne den Netzwerk-Tab der Entwicklerwerkzeuge und wandle etwas um. Zu sehen sind die Seite selbst und die Statistik- und Werbeanfragen, mit denen dieser Dienst bezahlt wird — und keine einzige, die deine Datei trägt. Hinter genau diesem Paar steckt parquet-wasm, eine WebAssembly-Fassung des Apache-Arrow-Lesers; dein Browser lädt das einmal und behält es dann.
Ja. Kein Konto, kein Wasserzeichen und kein Tageskontingent, das sich verbraucht — es läuft auf deinem eigenen Rechner, du darfst also so oft wiederkommen, wie du willst. Dateien bis 100 MB verarbeitet der Browser, 100 auf einmal. parquet-wasm wird auf deinen Rechner geladen und läuft dort — deshalb gibt es dafür keine Zählung.
NDJSON und Parquet beschreiben Inhalte auf grundverschiedene Weise. Die Umwandlung ist deshalb ein Nachbau und keine Kopie: originalgetreu, aber nicht Byte für Byte dasselbe. Verschachtelte Objekte werden zu Spalten flachgeklopft. Tief verschachtelte Daten verlieren dabei ihre Struktur.
Für die Umwandlung selbst nicht — sie läuft in dem Browser, den du ohnehin offen hast. Zum Öffnen brauchst du danach das Programm, das auf deinem Gerät üblicherweise Apache Parquet anzeigt.