Parquet-Export
Annotationen für effiziente Großdatenverarbeitung in das Apache-Parquet-Format exportieren.
Parquet-Export
Neu in v2.3.0
Apache Parquet ist ein spaltenorientiertes Speicherformat, das für analytische Arbeitslasten optimiert ist. Es bietet gegenüber JSON und CSV bei großen Annotationsdatensätzen erhebliche Vorteile: kleinere Dateigrößen (typischerweise 5–10-fache Kompression), schnellere Lesevorgänge für Spaltenteilmengen-Abfragen und native Unterstützung in nahezu allen Data-Science-Tools (pandas, DuckDB, PyArrow, Spark, Polars, Hugging Face Datasets).
Potato kann Annotationen direkt in das Parquet-Format exportieren und dabei drei strukturierte Dateien erzeugen, die alle Annotationstypen abdecken.
Parquet-Export aktivieren
Als primäres Ausgabeformat
output_annotation_dir: "output/"
output_annotation_format: "parquet"Als sekundärer Export (JSON als primäres Format beibehalten)
output_annotation_dir: "output/"
output_annotation_format: "jsonl"
parquet_export:
enabled: true
output_dir: "output/parquet/"
auto_export: true # export after each annotation sessionOn-Demand über CLI
python -m potato.export parquet --config config.yaml --output ./parquet_output/Ausgabedateien
Parquet-Export erzeugt drei Dateien, die jeweils eine andere Ebene der Annotationsdaten repräsentieren.
1. annotations.parquet
Die primäre Ausgabedatei. Eine Zeile pro (Instanz, Annotator, Schema)-Kombination.
| Spalte | Typ | Beschreibung |
|---|---|---|
instance_id | string | Instanzkennung |
annotator | string | Annotator-Benutzername |
schema_name | string | Name des Annotationsschemas |
value | string | Annotationswert (JSON-kodiert für komplexe Typen) |
timestamp | timestamp | Zeitpunkt der Annotationserstellung |
duration_ms | int64 | Auf dieser Instanz verbrachte Zeit (Millisekunden) |
session_id | string | Annotationssitzungskennung |
Für einfache Annotationstypen (radio, likert, text) enthält value den Rohwert. Für komplexe Typen (multiselect, spans, events) enthält value einen JSON-String.
2. spans.parquet
Für span-basierte Annotationstypen (span, span_link, event_annotation, coreference). Eine Zeile pro annotiertem Span.
| Spalte | Typ | Beschreibung |
|---|---|---|
instance_id | string | Instanzkennung |
annotator | string | Annotator-Benutzername |
schema_name | string | Name des Annotationsschemas |
span_id | string | Eindeutige Span-Kennung |
text | string | Span-Textinhalt |
start_offset | int32 | Zeichenstart-Offset |
end_offset | int32 | Zeichenend-Offset |
label | string | Span-Label |
field | string | Quellfeld (für Multi-Feld-Span-Annotation) |
links | string | JSON-kodierte Link-Daten (für span_link) |
attributes | string | JSON-kodierte zusätzliche Attribute |
3. items.parquet
Metadaten zu jeder Instanz im Datensatz. Eine Zeile pro Instanz.
| Spalte | Typ | Beschreibung |
|---|---|---|
instance_id | string | Instanzkennung |
text | string | Primärer Textinhalt |
annotation_count | int32 | Anzahl erhaltener Annotationen |
annotators | string | JSON-Liste der Annotator-Benutzernamen |
status | string | Instanzstatus (pending, in_progress, complete) |
metadata | string | JSON-kodierte Instanz-Metadaten |
Kompressionsoptionen
parquet_export:
enabled: true
output_dir: "output/parquet/"
compression: snappy # snappy (default), gzip, zstd, lz4, brotli, none
row_group_size: 50000 # rows per row group (affects read performance)
use_dictionary: true # dictionary encoding for string columns
write_statistics: true # column statistics for query optimizationKompressionsvergleich
| Algorithmus | Kompressionsrate | Schreibgeschwindigkeit | Lesegeschwindigkeit | Geeignet für |
|---|---|---|---|---|
snappy | Mittel | Schnell | Schnell | Allgemeine Nutzung (Standard) |
gzip | Hoch | Langsam | Mittel | Archivierung, kleine Dateien |
zstd | Hoch | Schnell | Schnell | Bestes Gleichgewicht aus Größe und Geschwindigkeit |
lz4 | Niedrig | Sehr schnell | Sehr schnell | Geschwindigkeitskritische Arbeitslasten |
brotli | Sehr hoch | Sehr langsam | Mittel | Maximale Kompression |
none | Keine | Schnellste | Schnellste | Debugging |
Für die meisten Annotationsprojekte ist die Standard-snappy-Kompression eine gute Wahl. Bei großen Datensätzen, bei denen die Dateigröße wichtig ist, verwenden Sie zstd.
Parquet-Daten laden
pandas
import pandas as pd
annotations = pd.read_parquet("output/parquet/annotations.parquet")
spans = pd.read_parquet("output/parquet/spans.parquet")
items = pd.read_parquet("output/parquet/items.parquet")
# Filter to a specific schema
sentiment = annotations[annotations["schema_name"] == "sentiment"]
# Compute inter-annotator agreement
from sklearn.metrics import cohen_kappa_score
pivot = sentiment.pivot(index="instance_id", columns="annotator", values="value")
kappa = cohen_kappa_score(pivot.iloc[:, 0], pivot.iloc[:, 1])DuckDB
-- Direct query without loading into memory
SELECT instance_id, value, COUNT(*) as annotator_count
FROM 'output/parquet/annotations.parquet'
WHERE schema_name = 'sentiment'
GROUP BY instance_id, value
ORDER BY annotator_count DESC;
-- Join annotations with items
SELECT a.instance_id, i.text, a.value, a.annotator
FROM 'output/parquet/annotations.parquet' a
JOIN 'output/parquet/items.parquet' i
ON a.instance_id = i.instance_id
WHERE a.schema_name = 'sentiment';PyArrow
import pyarrow.parquet as pq
# Read specific columns only (fast for wide tables)
table = pq.read_table(
"output/parquet/annotations.parquet",
columns=["instance_id", "value", "annotator"]
)
# Convert to pandas
df = table.to_pandas()
# Read with row group filtering
parquet_file = pq.ParquetFile("output/parquet/annotations.parquet")
print(f"Row groups: {parquet_file.metadata.num_row_groups}")
print(f"Total rows: {parquet_file.metadata.num_rows}")Hugging Face Datasets
from datasets import load_dataset
# Load directly from Parquet files
dataset = load_dataset("parquet", data_files={
"annotations": "output/parquet/annotations.parquet",
"spans": "output/parquet/spans.parquet",
"items": "output/parquet/items.parquet",
})
# Access as a regular HF dataset
print(dataset["annotations"][0])
# Push to Hugging Face Hub
dataset["annotations"].push_to_hub("my-org/my-annotations", split="train")Polars
import polars as pl
annotations = pl.read_parquet("output/parquet/annotations.parquet")
# Fast aggregation
label_counts = (
annotations
.filter(pl.col("schema_name") == "sentiment")
.group_by("value")
.agg(pl.count().alias("count"))
.sort("count", descending=True)
)
print(label_counts)Inkrementeller Export
Für langfristige Annotationsprojekte aktivieren Sie den inkrementellen Export, um nicht jedes Mal den gesamten Datensatz neu exportieren zu müssen:
parquet_export:
enabled: true
output_dir: "output/parquet/"
incremental: true
partition_by: date # date, annotator, or noneMit partition_by: date werden Parquet-Dateien in datumpartitionierte Verzeichnisse organisiert:
output/parquet/
annotations/
date=2026-03-01/part-0.parquet
date=2026-03-02/part-0.parquet
date=2026-03-03/part-0.parquet
spans/
date=2026-03-01/part-0.parquet
items/
part-0.parquet
Partitionierte Datensätze können von allen gängigen Tools als einzelne logische Tabelle gelesen werden:
# pandas reads partitioned directories automatically
df = pd.read_parquet("output/parquet/annotations/")
# DuckDB handles partitions natively
# SELECT * FROM 'output/parquet/annotations/**/*.parquet'Konfigurationsreferenz
parquet_export:
enabled: true
output_dir: "output/parquet/"
# When to export
auto_export: true # export after each session (default: false)
export_on_shutdown: true # export when server stops (default: true)
# File settings
compression: snappy
row_group_size: 50000
use_dictionary: true
write_statistics: true
# Incremental settings
incremental: false
partition_by: none # none, date, annotator
# Schema-specific options
flatten_complex_types: false # flatten JSON values into columns
include_raw_json: true # include raw JSON alongside flattened columns
# Span export
export_spans: true # generate spans.parquet
export_items: true # generate items.parquetVollständiges Beispiel
task_name: "NER Annotation Project"
task_dir: "."
data_files:
- "data/documents.jsonl"
item_properties:
id_key: doc_id
text_key: text
annotation_schemes:
- annotation_type: span
name: entities
labels:
- name: PERSON
color: "#3b82f6"
- name: ORGANIZATION
color: "#22c55e"
- name: LOCATION
color: "#f59e0b"
output_annotation_dir: "output/"
output_annotation_format: "jsonl"
parquet_export:
enabled: true
output_dir: "output/parquet/"
compression: zstd
auto_export: true
export_spans: true
export_items: trueNach der Annotation laden und analysieren:
import pandas as pd
spans = pd.read_parquet("output/parquet/spans.parquet")
# Entity type distribution
print(spans["label"].value_counts())
# Average span length by type
spans["length"] = spans["end_offset"] - spans["start_offset"]
print(spans.groupby("label")["length"].mean())Weiterführende Informationen
- Exportformate – COCO, YOLO, CoNLL und andere Exportformate
- Remote-Datenquellen – Daten aus Cloud-Speicher laden
- Admin-Dashboard – Exportstatus überwachen
Implementierungsdetails finden Sie in der Quelldokumentation.