Dieses Repository enthält die Spezifikation für Apache Parquet- und Apache Thrift-Definitionen zum Lesen und Schreiben von Parquet-Metadaten.
Apache Parquet ist ein spaltenorientiertes Open-Source-Datendateiformat, das für eine effiziente Datenspeicherung und -abfrage entwickelt wurde. Es bietet hochleistungsfähige Komprimierungs- und Kodierungsschemata für die Massenverarbeitung komplexer Daten und wird von vielen Programmiersprachen und Analysetools unterstützt.
Wir haben Parquet entwickelt, um die Vorteile einer komprimierten, effizienten spaltenbasierten Datendarstellung für jedes Projekt im Hadoop-Ökosystem verfügbar zu machen.
Parquet wurde von Grund auf mit Blick auf komplexe verschachtelte Datenstrukturen entwickelt und verwendet den im Dremel-Artikel beschriebenen Datensatzschredder- und Zusammenstellungsalgorithmus. Wir glauben, dass dieser Ansatz der einfachen Reduzierung verschachtelter Namensräume überlegen ist.
Parquet unterstützt sehr effiziente Komprimierungs- und Kodierungsschemata. Mehrere Projekte haben gezeigt, welche Auswirkungen die Anwendung des richtigen Komprimierungs- und Kodierungsschemas auf die Daten auf die Leistung hat. Parquet ermöglicht die Angabe von Komprimierungsschemata auf Spaltenebene und ist zukunftssicher, um das Hinzufügen weiterer Kodierungen zu ermöglichen, sobald diese erfunden und implementiert werden.
Parkett ist so gebaut, dass es von jedermann genutzt werden kann. Das Hadoop-Ökosystem ist reich an Datenverarbeitungs-Frameworks, und wir sind nicht daran interessiert, Favoriten zu spielen. Wir glauben, dass ein effizientes, gut implementiertes säulenförmiges Speichersubstrat für alle Frameworks nützlich sein sollte, ohne dass die Kosten für umfangreiche und schwierig einzurichtende Abhängigkeiten anfallen.
Das parquet-format
Projekt enthält Formatspezifikationen und Thrift-Definitionen von Metadaten, die zum ordnungsgemäßen Lesen von Parquet-Dateien erforderlich sind.
Das parquet-java
Projekt enthält mehrere Untermodule, die die Kernkomponenten des Lesens und Schreibens eines verschachtelten, spaltenorientierten Datenstroms implementieren, diesen Kern auf das Parkettformat abbilden und Hadoop-Eingabe-/Ausgabeformate, Pig-Loader und andere bereitstellen Java-basierte Dienstprogramme für die Interaktion mit Parquet.
Das Projekt parquet-compatibility
enthält Kompatibilitätstests, mit denen überprüft werden kann, ob Implementierungen in verschiedenen Sprachen die Dateien anderer Sprachen lesen und schreiben können.
Java-Ressourcen können mit mvn package
erstellt werden. Die aktuelle stabile Version sollte immer bei Maven Central verfügbar sein.
C++-Sparsamkeitsressourcen können über make generiert werden.
Thrift kann auch in jede andere von Thrift unterstützte Sprache codegeneriert werden.
Block (HDFS-Block): Dies bedeutet einen Block in HDFS und die Bedeutung für die Beschreibung dieses Dateiformats bleibt unverändert. Das Dateiformat ist so konzipiert, dass es gut auf HDFS funktioniert.
Datei: Eine HDFS-Datei, die die Metadaten für die Datei enthalten muss. Es muss nicht unbedingt die Daten enthalten.
Zeilengruppe: Eine logische horizontale Aufteilung der Daten in Zeilen. Für eine Zeilengruppe gibt es keine garantierte physikalische Struktur. Eine Zeilengruppe besteht aus einem Spaltenblock für jede Spalte im Datensatz.
Spaltenblock: Ein Teil der Daten für eine bestimmte Spalte. Sie befinden sich in einer bestimmten Zeilengruppe und sind in der Datei garantiert zusammenhängend.
Seite: Spaltenblöcke werden in Seiten unterteilt. Eine Seite ist konzeptionell eine unteilbare Einheit (in Bezug auf Komprimierung und Kodierung). Es können mehrere Seitentypen vorhanden sein, die in einem Spaltenblock verschachtelt sind.
Hierarchisch gesehen besteht eine Datei aus einer oder mehreren Zeilengruppen. Eine Zeilengruppe enthält genau einen Spaltenblock pro Spalte. Spaltenblöcke enthalten eine oder mehrere Seiten.
Diese Datei und die Thrift-Definition sollten zusammen gelesen werden, um das Format zu verstehen.
4-byte magic number "PAR1"
<Column 1 Chunk 1>
<Column 2 Chunk 1>
...
<Column N Chunk 1>
<Column 1 Chunk 2>
<Column 2 Chunk 2>
...
<Column N Chunk 2>
...
<Column 1 Chunk M>
<Column 2 Chunk M>
...
<Column N Chunk M>
File Metadata
4-byte length in bytes of file metadata (little endian)
4-byte magic number "PAR1"
Im obigen Beispiel gibt es in dieser Tabelle N Spalten, die in M Zeilengruppen aufgeteilt sind. Die Dateimetadaten enthalten die Speicherorte aller Startpositionen der Spaltenblöcke. Weitere Details zum Inhalt der Metadaten finden Sie in der Thrift-Definition.
Dateimetadaten werden nach den Daten geschrieben, um das Schreiben in einem Durchgang zu ermöglichen.
Von den Lesern wird erwartet, dass sie zunächst die Dateimetadaten lesen, um alle für sie interessanten Spaltenblöcke zu finden. Die Spaltenblöcke sollten dann nacheinander gelesen werden.
Es gibt zwei Arten von Metadaten: Dateimetadaten und Seitenkopf-Metadaten. Alle Sparsamkeitsstrukturen werden mithilfe des TCompactProtocol serialisiert.
Die vom Dateiformat unterstützten Typen sollen so minimal wie möglich sein, wobei der Schwerpunkt auf der Auswirkung der Typen auf den Festplattenspeicher liegt. Beispielsweise werden 16-Bit-Ints im Speicherformat nicht explizit unterstützt, da sie durch 32-Bit-Ints mit einer effizienten Codierung abgedeckt werden. Dies reduziert die Komplexität der Implementierung von Readern und Writern für das Format. Die Typen sind:
Logische Typen werden verwendet, um die Typen zu erweitern, die zum Speichern von Parkett verwendet werden können, indem sie angeben, wie die primitiven Typen interpretiert werden sollen. Dadurch wird der Satz primitiver Typen auf ein Minimum reduziert und die effizienten Codierungen von Parquet wiederverwendet. Beispielsweise werden Zeichenfolgen mit dem primitiven Typ BYTE_ARRAY mit einer STRING-Annotation gespeichert. Diese Anmerkungen definieren, wie die Daten weiter dekodiert und interpretiert werden. Anmerkungen werden als LogicalType
Felder in den Dateimetadaten gespeichert und in LogicalTypes.md dokumentiert.
Parquet speichert Min/Max-Statistiken auf mehreren Ebenen (z. B. Column Chunk, Column Index und Data Page). Der Vergleich von Werten eines Typs folgt den folgenden Regeln:
Jeder logische Typ hat eine bestimmte Vergleichsreihenfolge. Wenn eine Spalte mit einem unbekannten logischen Typ versehen ist, können Statistiken möglicherweise nicht zum Bereinigen von Daten verwendet werden. Die Sortierreihenfolge für logische Typen ist auf der Seite LogicalTypes.md dokumentiert.
Für primitive Typen gelten die folgenden Regeln:
BOOLEAN – falsch, wahr
INT32, INT64 – Vergleich mit Vorzeichen.
FLOAT, DOUBLE – Vorzeichenbehafteter Vergleich mit spezieller Behandlung von NaNs und vorzeichenbehafteten Nullen. Die Details sind in der Thrift-Definition in der ColumnOrder
-Union dokumentiert. Sie sind hier zusammengefasst, die Thrift-Definition gilt jedoch als maßgeblich:
+0.0
in das Max-Statistikfeld geschrieben werden.-0.0
in das Min-Statistikfeld geschrieben werden.Für Abwärtskompatibilität beim Lesen von Dateien:
BYTE_ARRAY und FIXED_LEN_BYTE_ARRAY – Lexikografischer vorzeichenloser byteweiser Vergleich.
Um verschachtelte Spalten zu kodieren, verwendet Parquet die Dremel-Kodierung mit Definitions- und Wiederholungsstufen. Definitionsebenen geben an, wie viele optionale Felder im Pfad für die Spalte definiert sind. Wiederholungsstufen geben an, in welchem wiederholten Feld im Pfad der Wert wiederholt wird. Die maximalen Definitions- und Wiederholungsstufen können aus dem Schema berechnet werden (dh wie viel Verschachtelung vorhanden ist). Dies definiert die maximale Anzahl von Bits, die zum Speichern der Ebenen erforderlich sind (Ebenen werden für alle Werte in der Spalte definiert).
Es werden zwei Kodierungen für die Ebenen unterstützt: BIT_PACKED und RLE. Jetzt wird nur RLE verwendet, da es BIT_PACKED ersetzt.
Nullität wird in den Definitionsebenen kodiert (die lauflängenkodiert sind). NULL-Werte werden in den Daten nicht kodiert. Beispielsweise würde in einem nicht verschachtelten Schema eine Spalte mit 1000 NULL-Werten mit der Lauflängenkodierung (0, 1000 Mal) für die Definitionsebenen und sonst nichts kodiert werden.
Bei Datenseiten werden die drei Informationen hintereinander nach dem Seitenkopf codiert. Auf der Datenseite ist kein Auffüllen zulässig. In der Reihenfolge haben wir:
Der im Header angegebene Wert von uncompressed_page_size
gilt für alle drei Teile zusammen.
Die codierten Werte für die Datenseite sind immer erforderlich. Die Definitions- und Wiederholungsebenen sind optional und basieren auf der Schemadefinition. Wenn die Spalte nicht verschachtelt ist (dh der Pfad zur Spalte hat die Länge 1), kodieren wir die Wiederholungsebenen nicht (sie hätten immer den Wert 1). Für erforderliche Daten werden die Definitionsebenen übersprungen (falls codiert, haben sie immer den Wert der maximalen Definitionsebene).
Wenn die Spalte beispielsweise nicht verschachtelt und erforderlich ist, handelt es sich bei den Daten auf der Seite nur um die codierten Werte.
Die unterstützten Kodierungen werden in Encodings.md beschrieben
Die unterstützten Komprimierungscodecs werden in „Compression.md“ beschrieben
Spaltenblöcke bestehen aus Seiten, die hintereinander geschrieben werden. Die Seiten haben einen gemeinsamen Header und Leser können Seiten überspringen, die sie nicht interessieren. Die Daten für die Seite folgen dem Header und können komprimiert und/oder codiert werden. Die Komprimierung und Kodierung wird in den Seitenmetadaten angegeben.
Ein Spaltenblock kann teilweise oder vollständig wörterbuchcodiert sein. Das bedeutet, dass Wörterbuchindizes anstelle der tatsächlichen Werte auf den Datenseiten gespeichert werden. Die tatsächlichen Werte werden auf der Wörterbuchseite gespeichert. Weitere Informationen finden Sie in Encodings.md. Die Wörterbuchseite muss an der ersten Position des Spaltenblocks platziert werden. In einem Spaltenblock kann höchstens eine Wörterbuchseite platziert werden.
Darüber hinaus können Dateien einen optionalen Spaltenindex enthalten, damit Leser Seiten effizienter überspringen können. Einzelheiten und die Gründe für das Hinzufügen dieser Elemente zum Format finden Sie unter PageIndex.md.
Seiten aller Art können einzeln mit einer Prüfsumme versehen werden. Dadurch können Prüfsummen auf HDFS-Dateiebene deaktiviert werden, um die Suche nach einzelnen Zeilen besser zu unterstützen. Prüfsummen werden mithilfe des Standard-CRC32-Algorithmus – wie er beispielsweise in GZip verwendet wird – für die serialisierte Binärdarstellung einer Seite berechnet (ohne den Seitenkopf selbst).
Wenn die Dateimetadaten beschädigt sind, geht die Datei verloren. Wenn die Spaltenmetadaten beschädigt sind, geht dieser Spaltenblock verloren (Spaltenblöcke für diese Spalte in anderen Zeilengruppen sind jedoch in Ordnung). Wenn ein Seitenkopf beschädigt ist, gehen die verbleibenden Seiten in diesem Block verloren. Wenn die Daten auf einer Seite beschädigt sind, geht diese Seite verloren. Bei kleineren Zeilengruppen ist die Datei widerstandsfähiger gegen Beschädigungen.
Mögliche Erweiterung: Bei kleineren Zeilengruppen besteht das größte Problem darin, die Dateimetadaten am Ende zu platzieren. Wenn beim Schreiben der Dateimetadaten ein Fehler auftritt, sind alle geschriebenen Daten nicht lesbar. Dies kann behoben werden, indem die Dateimetadaten in jede N-te Zeilengruppe geschrieben werden. Die Metadaten jeder Datei wären kumulativ und umfassen alle bisher geschriebenen Zeilengruppen. Kombiniert man dies mit der für RC- oder Avro-Dateien verwendeten Strategie mithilfe von Synchronisierungsmarkierungen, könnte ein Leser teilweise geschriebene Dateien wiederherstellen.
Das Format ist explizit darauf ausgelegt, die Metadaten von den Daten zu trennen. Dies ermöglicht die Aufteilung von Spalten in mehrere Dateien sowie die Referenzierung einer einzelnen Metadatendatei auf mehrere Parquet-Dateien.
Es gibt viele Stellen im Format für kompatible Erweiterungen:
Parquet Thrift IDL reserviert die Feld-ID 32767
jeder Thrift-Struktur für Erweiterungen. Der (Thrift)-Typ dieses Feldes ist immer binary
.
Das Apache/Parquet-Testing enthält eine Reihe von Parquet-Dateien zu Testzwecken.
Kommentieren Sie das Problem und/oder wenden Sie sich mit Ihren Fragen und Ideen an die Mailingliste parquet-dev. Änderungen an dieser Kernformatdefinition werden auf der Mailingliste vorgeschlagen und ausführlich diskutiert. Möglicherweise sind Sie auch daran interessiert, zum Teilprojekt Parquet-Java beizutragen, das alle Java-seitigen Implementierungen und APIs enthält. Weitere Informationen finden Sie im Abschnitt „Mitwirken“ des Parquet-Java-Projekts
Wir verpflichten uns und die Parquet-Entwicklergemeinschaft zu einem Verhaltenskodex, wie er von Twitter OSS beschrieben wird: https://github.com/twitter/code-of-conduct/blob/master/code-of-conduct.md.
Copyright 2013 Twitter, Cloudera und andere Mitwirkende.
Lizenziert unter der Apache-Lizenz, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0