Exportação para Parquet
Exporte anotações do Potato para o Apache Parquet — um formato colunar otimizado para pipelines de ML em larga escala, com integração para Spark, DuckDB, Pandas e HuggingFace Datasets.
Novidade na v2.3.0
O Apache Parquet é um formato de armazenamento colunar otimizado para cargas de trabalho analíticas. Ele oferece vantagens consideráveis sobre JSON e CSV para grandes conjuntos de anotações: arquivos menores (compressão típica de 5 a 10x), leituras mais rápidas para consultas a um subconjunto de colunas e suporte nativo em praticamente todas as ferramentas de ciência de dados (pandas, DuckDB, PyArrow, Spark, Polars, Hugging Face Datasets).
O Potato pode exportar anotações diretamente para o formato Parquet, gerando três arquivos estruturados que cobrem todos os tipos de anotação.
Habilitando a exportação para Parquet
Como formato de saída principal
output_annotation_dir: "output/"
output_annotation_format: "parquet"Como exportação secundária (mantendo o JSON como principal)
output_annotation_dir: "output/"
output_annotation_format: "jsonl"
parquet_export:
enabled: true
output_dir: "output/parquet/"
auto_export: true # export after each annotation sessionSob demanda via CLI
python -m potato.export parquet --config config.yaml --output ./parquet_output/Arquivos de saída
A exportação para Parquet gera três arquivos, cada um representando um nível diferente dos dados de anotação.
1. annotations.parquet
O arquivo de saída principal. Uma linha por combinação (instância, anotador, esquema).
| Coluna | Tipo | Descrição |
|---|---|---|
instance_id | string | Identificador da instância |
annotator | string | Nome de usuário do anotador |
schema_name | string | Nome do esquema de anotação |
value | string | Valor da anotação (codificado em JSON para tipos complexos) |
timestamp | timestamp | Quando a anotação foi criada |
duration_ms | int64 | Tempo gasto nesta instância (milissegundos) |
session_id | string | Identificador da sessão de anotação |
Para tipos de anotação simples (radio, likert, text), value contém o valor bruto. Para tipos complexos (multiselect, spans, events), value contém uma string JSON.
2. spans.parquet
Para tipos de anotação baseados em spans (span, span_link, event_annotation, coreference). Uma linha por span anotado.
| Coluna | Tipo | Descrição |
|---|---|---|
instance_id | string | Identificador da instância |
annotator | string | Nome de usuário do anotador |
schema_name | string | Nome do esquema de anotação |
span_id | string | Identificador único do span |
text | string | Conteúdo textual do span |
start_offset | int32 | Deslocamento inicial em caracteres |
end_offset | int32 | Deslocamento final em caracteres |
label | string | Rótulo do span |
field | string | Campo de origem (para anotação de spans em múltiplos campos) |
links | string | Dados de vínculo codificados em JSON (para span_link) |
attributes | string | Atributos adicionais codificados em JSON |
3. items.parquet
Metadados sobre cada instância no conjunto de dados. Uma linha por instância.
| Coluna | Tipo | Descrição |
|---|---|---|
instance_id | string | Identificador da instância |
text | string | Conteúdo textual principal |
annotation_count | int32 | Número de anotações recebidas |
annotators | string | Lista JSON dos nomes de usuário dos anotadores |
status | string | Status da instância (pending, in_progress, complete) |
metadata | string | Metadados da instância codificados em JSON |
Opções de compressão
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 optimizationComparação de compressão
| Algoritmo | Taxa de compressão | Velocidade de escrita | Velocidade de leitura | Indicado para |
|---|---|---|---|---|
snappy | Moderada | Rápida | Rápida | Uso geral (padrão) |
gzip | Alta | Lenta | Moderada | Arquivamento, arquivos pequenos |
zstd | Alta | Rápida | Rápida | Melhor equilíbrio entre tamanho e velocidade |
lz4 | Baixa | Muito rápida | Muito rápida | Cargas de trabalho críticas em velocidade |
brotli | Muito alta | Muito lenta | Moderada | Compressão máxima |
none | Nenhuma | A mais rápida | A mais rápida | Depuração |
Para a maioria dos projetos de anotação, a compressão snappy padrão é uma boa escolha. Para conjuntos de dados grandes em que o tamanho do arquivo importa, use zstd.
Carregando dados em Parquet
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)Exportação incremental
Para projetos de anotação de longa duração, habilite a exportação incremental para evitar reexportar todo o conjunto de dados a cada vez:
parquet_export:
enabled: true
output_dir: "output/parquet/"
incremental: true
partition_by: date # date, annotator, or noneCom partition_by: date, os arquivos Parquet são organizados em diretórios particionados por data:
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
Conjuntos de dados particionados podem ser lidos como uma única tabela lógica por todas as principais ferramentas:
# pandas reads partitioned directories automatically
df = pd.read_parquet("output/parquet/annotations/")
# DuckDB handles partitions natively
# SELECT * FROM 'output/parquet/annotations/**/*.parquet'Referência de configuração
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.parquetExemplo completo
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: trueApós a anotação, carregue e analise:
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())Leitura adicional
- Formatos de exportação -- COCO, YOLO, CoNLL e outros formatos de exportação
- Fontes de dados remotas -- carregamento de dados a partir de armazenamento em nuvem
- Painel administrativo -- monitoramento do status de exportação
Para detalhes de implementação, consulte a documentação de origem.