Frictionless-zu-Parquet-Typmapping¶
Beim CSV-Upload erzeugt das odi-staging-backend aus der validierten CSV-Datei
mehrere Repräsentationen, darunter eine Apache-Parquet-Datei. Damit die
Parquet-Spalten exakt den im Frictionless-Schema deklarierten Typen entsprechen
und nicht von der automatischen Typ-Inferenz von Apache Arrow abhängen, wird ein
explizites Mapping verwendet.
Wo wird das Mapping genutzt?¶
Die zentrale Typ-Map liegt im odi-staging-backend unter
src/upload/parquet/frictionless-to-parquet-type.map.ts.
Vor der Parquet-Erzeugung werden die CSV-Zeilen vom
CsvJsonService
in die passenden JavaScript-Werte konvertiert. Anschließend baut der
ParquetService
daraus ein Arrow-Schema mit expliziten Datentypen und schreibt es über
parquet-wasm als Parquet.
Logische und physische Parquet-Typen¶
Parquet unterscheidet zwischen zwei Ebenen:
- Physischer Typ: Beschreibt, wie die Rohbytes in der Datei abgelegt werden
(z. B.
BYTE_ARRAY,INT32,INT64,DOUBLE). Er ist werkzeugunabhängig und Teil des Parquet-Formats. - Logischer Typ: Gibt die semantische Bedeutung der physischen Daten an
(z. B.
UTF8,DATE,TIMESTAMP). Viele Werkzeuge zeigen den logischen Typ an, verwenden aber eigene Namen dafür.
Darum kann ein und dieselbe Spalte je nach Betrachter unterschiedlich
beschriftet sein: Parquet selbst und Apache Arrow sprechen von UTF8,
während Datenbank-Werkzeuge und einige Parquet-Viewer den logischen Typ
häufig als VARCHAR oder STRING anzeigen. UTF8, VARCHAR und STRING
bedeuten hier dasselbe: eine variable Zeichenkette.
Mapping-Tabelle¶
| Frictionless-Typ | Parquet-Typ (logisch) | Parquet-Typ (physisch) | Beschreibung |
|---|---|---|---|
string |
UTF8 (VARCHAR) |
BYTE_ARRAY |
Beliebiger Text. |
number |
DOUBLE |
DOUBLE |
Gleitkommazahlen (IEEE 754 doppelte Genauigkeit). |
integer |
INT64 (BIGINT) |
INT64 |
Ganze Zahlen mit Vorzeichen (64 Bit). |
boolean |
BOOLEAN |
BOOLEAN |
Wahrheitswerte. |
date |
DATE |
INT32 |
Kalenderdatum ohne Uhrzeit. |
datetime |
TIMESTAMP(MILLIS, UTC) (TIMESTAMP) |
INT64 |
Zeitstempel mit Millisekundengenauigkeit. |
time |
TIME(MILLIS) (TIME) |
INT32 |
Tageszeit in Millisekunden seit Mitternacht. |
year |
INT64 (BIGINT) |
INT64 |
Jahreszahl als Ganzzahl. |
yearmonth |
UTF8 (VARCHAR) |
BYTE_ARRAY |
Jahr-Monat-Kombination, als ISO-Text belassen. |
duration |
UTF8 (VARCHAR) |
BYTE_ARRAY |
Dauer als ISO-8601-Text belassen. |
geopoint |
UTF8 (VARCHAR) |
BYTE_ARRAY |
Geografischer Punkt als Text belassen. |
geojson |
UTF8 (VARCHAR) |
BYTE_ARRAY |
GeoJSON-Geometrie als Text belassen. |
any |
UTF8 (VARCHAR) |
BYTE_ARRAY |
Fallback auf UTF8 für den generischen Typ any. |
Werte-Konvertierung nach Schema¶
Der Typ allein reicht nicht: Wie eine CSV-Zelle gelesen wird, bestimmen die
Feld-Eigenschaften des Frictionless-Schemas. Die Konvertierung
(frictionless-value-parser.ts)
folgt dabei denselben Regeln wie die vorgelagerte Validierung mit
frictionless-py, damit die Parquet-Datei genau die Werte enthält, die als gültig
geprüft wurden.
| Eigenschaft | Typen | Verhalten |
|---|---|---|
format |
date, datetime, time |
default = ISO 8601, any = ISO bzw. freie Erkennung, sonst Python-strptime-Muster (z. B. %d.%m.%Y). Das alte Präfix fmt: wird unterstützt. |
decimalChar, groupChar |
number (groupChar auch integer) |
Dezimal- und Tausendertrennzeichen, z. B. 1.234,56 mit decimalChar: "," und groupChar: ".". |
bareNumber: false |
number, integer |
Entfernt Zeichen vor und nach der Zahl, z. B. € 12,50 oder 50 %. |
trueValues, falseValues |
boolean |
Eigene Wahrheitswerte, z. B. ja/nein. Standard: true/True/TRUE/1 bzw. false/False/FALSE/0. |
missingValues |
alle | Werte wie NA oder - werden als null geschrieben (Schema- oder Feld-Ebene, Standard: leerer String). |
Datumswerte werden immer in UTC interpretiert. date-Werte liegen dadurch
unabhängig von der Zeitzone des Servers auf dem richtigen Kalendertag;
datetime-Werte ohne Zeitzonenangabe gelten als UTC, Werte mit Offset
(z. B. +02:00) werden nach UTC umgerechnet.
Kann eine Zelle in einer typisierten Spalte nicht gelesen werden, wird null
geschrieben, statt einen Wert zu raten.
Hintergrund
Früher wurden Datumswerte ohne Beachtung von format mit JavaScript
new Date(...) gelesen. Dabei wurde 01.08.2026 als 8. Januar
interpretiert (Tag und Monat vertauscht), Tage größer 12 wurden null.
Besondere Verhaltensweisen¶
Leere Zellen¶
Leere CSV-Zellen werden für typisierte Spalten als null geschrieben. Alle
Spalten werden daher im Arrow-Schema als nullable deklariert.
Unbekannte Frictionless-Typen¶
Ist ein Feld im Schema mit einem noch nicht unterstützten Typ deklariert, fällt
das Mapping auf string (UTF8) zurück. Dadurch bleibt die Parquet-Erzeugung
stabil, auch wenn Schemas neue Typen enthalten, bevor die Map erweitert wird.
Boolean-Spalten mit ausschließlich null¶
In Apache Arrow erzeugt ein Bool-Vektor, der nur null-Werte enthält, kein
Validity-Bitmap. Das führt beim Schreiben durch parquet-wasm zu einem
Fehler. In diesem Edge-Case fällt das Staging-Backend daher für diese Spalte
auf UTF8 zurück, sodass die Werte weiterhin als null erhalten bleiben.