Skip to content
Esta página aún no está disponible en su idioma. Se muestra la versión en inglés.

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

yaml
output_annotation_dir: "output/"
output_annotation_format: "parquet"

Als sekundärer Export (JSON als primäres Format beibehalten)

yaml
output_annotation_dir: "output/"
output_annotation_format: "jsonl"
 
parquet_export:
  enabled: true
  output_dir: "output/parquet/"
  auto_export: true              # export after each annotation session

On-Demand über CLI

bash
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.

SpalteTypBeschreibung
instance_idstringInstanzkennung
annotatorstringAnnotator-Benutzername
schema_namestringName des Annotationsschemas
valuestringAnnotationswert (JSON-kodiert für komplexe Typen)
timestamptimestampZeitpunkt der Annotationserstellung
duration_msint64Auf dieser Instanz verbrachte Zeit (Millisekunden)
session_idstringAnnotationssitzungskennung

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.

SpalteTypBeschreibung
instance_idstringInstanzkennung
annotatorstringAnnotator-Benutzername
schema_namestringName des Annotationsschemas
span_idstringEindeutige Span-Kennung
textstringSpan-Textinhalt
start_offsetint32Zeichenstart-Offset
end_offsetint32Zeichenend-Offset
labelstringSpan-Label
fieldstringQuellfeld (für Multi-Feld-Span-Annotation)
linksstringJSON-kodierte Link-Daten (für span_link)
attributesstringJSON-kodierte zusätzliche Attribute

3. items.parquet

Metadaten zu jeder Instanz im Datensatz. Eine Zeile pro Instanz.

SpalteTypBeschreibung
instance_idstringInstanzkennung
textstringPrimärer Textinhalt
annotation_countint32Anzahl erhaltener Annotationen
annotatorsstringJSON-Liste der Annotator-Benutzernamen
statusstringInstanzstatus (pending, in_progress, complete)
metadatastringJSON-kodierte Instanz-Metadaten

Kompressionsoptionen

yaml
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 optimization

Kompressionsvergleich

AlgorithmusKompressionsrateSchreibgeschwindigkeitLesegeschwindigkeitGeeignet für
snappyMittelSchnellSchnellAllgemeine Nutzung (Standard)
gzipHochLangsamMittelArchivierung, kleine Dateien
zstdHochSchnellSchnellBestes Gleichgewicht aus Größe und Geschwindigkeit
lz4NiedrigSehr schnellSehr schnellGeschwindigkeitskritische Arbeitslasten
brotliSehr hochSehr langsamMittelMaximale Kompression
noneKeineSchnellsteSchnellsteDebugging

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

python
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

sql
-- 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

python
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

python
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

python
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:

yaml
parquet_export:
  enabled: true
  output_dir: "output/parquet/"
  incremental: true
  partition_by: date             # date, annotator, or none

Mit partition_by: date werden Parquet-Dateien in datumpartitionierte Verzeichnisse organisiert:

text
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:

python
# pandas reads partitioned directories automatically
df = pd.read_parquet("output/parquet/annotations/")
 
# DuckDB handles partitions natively
# SELECT * FROM 'output/parquet/annotations/**/*.parquet'

Konfigurationsreferenz

yaml
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.parquet

Vollständiges Beispiel

yaml
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: true

Nach der Annotation laden und analysieren:

python
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

Implementierungsdetails finden Sie in der Quelldokumentation.