Parquetエクスポート
効率的な大規模データ処理のために、アノテーションをApache Parquet形式にエクスポートします。
Parquetエクスポート
v2.3.0の新機能
Apache Parquetは分析ワークロードに最適化されたカラムナーストレージ形式です。大規模なアノテーションデータセットにおいて、JSONやCSVに比べて大きな利点を提供します:より小さなファイルサイズ(通常5〜10倍の圧縮)、カラムサブセットクエリでの高速読み取り、そして事実上すべてのデータサイエンスツール(pandas、DuckDB、PyArrow、Spark、Polars、Hugging Face Datasets)でのネイティブサポートです。
Potatoはアノテーションを直接Parquet形式にエクスポートでき、すべてのアノテーションタイプをカバーする3つの構造化ファイルを生成します。
Parquetエクスポートの有効化
プライマリ出力形式として
output_annotation_dir: "output/"
output_annotation_format: "parquet"セカンダリエクスポートとして(JSONをプライマリに維持)
output_annotation_dir: "output/"
output_annotation_format: "jsonl"
parquet_export:
enabled: true
output_dir: "output/parquet/"
auto_export: true # export after each annotation sessionCLIによるオンデマンド
python -m potato.export parquet --config config.yaml --output ./parquet_output/出力ファイル
Parquetエクスポートは3つのファイルを生成し、それぞれアノテーションデータの異なるレベルを表します。
1. annotations.parquet
プライマリ出力ファイル。(インスタンス、アノテーター、スキーマ)の組み合わせごとに1行。
| カラム | 型 | 説明 |
|---|---|---|
instance_id | string | インスタンス識別子 |
annotator | string | アノテーターのユーザー名 |
schema_name | string | アノテーションスキーマ名 |
value | string | アノテーション値(複合型の場合はJSONエンコード) |
timestamp | timestamp | アノテーション作成日時 |
duration_ms | int64 | このインスタンスに費やした時間(ミリ秒) |
session_id | string | アノテーションセッション識別子 |
シンプルなアノテーションタイプ(radio、likert、text)の場合、valueには生の値が含まれます。複合型(multiselect、spans、events)の場合、valueにはJSON文字列が含まれます。
2. spans.parquet
スパンベースのアノテーションタイプ(span、span_link、event_annotation、coreference)用。アノテーション済みスパンごとに1行。
| カラム | 型 | 説明 |
|---|---|---|
instance_id | string | インスタンス識別子 |
annotator | string | アノテーターのユーザー名 |
schema_name | string | アノテーションスキーマ名 |
span_id | string | 一意のスパン識別子 |
text | string | スパンテキスト内容 |
start_offset | int32 | 文字開始オフセット |
end_offset | int32 | 文字終了オフセット |
label | string | スパンラベル |
field | string | ソースフィールド(マルチフィールドスパンアノテーション用) |
links | string | JSONエンコードされたリンクデータ(span_link用) |
attributes | string | JSONエンコードされた追加属性 |
3. items.parquet
データセット内の各インスタンスのメタデータ。インスタンスごとに1行。
| カラム | 型 | 説明 |
|---|---|---|
instance_id | string | インスタンス識別子 |
text | string | プライマリテキスト内容 |
annotation_count | int32 | 受信したアノテーション数 |
annotators | string | アノテーターユーザー名のJSONリスト |
status | string | インスタンスステータス(pending、in_progress、complete) |
metadata | string | JSONエンコードされたインスタンスメタデータ |
圧縮オプション
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圧縮の比較
| アルゴリズム | 圧縮率 | 書き込み速度 | 読み取り速度 | 最適な用途 |
|---|---|---|---|---|
snappy | 中程度 | 高速 | 高速 | 一般的な使用(デフォルト) |
gzip | 高い | 低速 | 中程度 | アーカイブ、小さなファイル |
zstd | 高い | 高速 | 高速 | サイズと速度の最適なバランス |
lz4 | 低い | 非常に高速 | 非常に高速 | 速度重視のワークロード |
brotli | 非常に高い | 非常に低速 | 中程度 | 最大圧縮 |
none | なし | 最速 | 最速 | デバッグ |
ほとんどのアノテーションプロジェクトでは、デフォルトのsnappy圧縮が良い選択です。ファイルサイズが重要な大規模データセットにはzstdを使用してください。
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)増分エクスポート
長期間のアノテーションプロジェクトの場合、毎回データセット全体を再エクスポートすることを避けるために増分エクスポートを有効にしてください:
parquet_export:
enabled: true
output_dir: "output/parquet/"
incremental: true
partition_by: date # date, annotator, or nonepartition_by: dateを使用すると、Parquetファイルは日付パーティションされたディレクトリに整理されます:
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
パーティション化されたデータセットは、すべての主要ツールで1つの論理テーブルとして読み取れます:
# pandas reads partitioned directories automatically
df = pd.read_parquet("output/parquet/annotations/")
# DuckDB handles partitions natively
# SELECT * FROM 'output/parquet/annotations/**/*.parquet'設定リファレンス
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完全な例
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アノテーション後、読み込んで分析:
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())参考資料
- エクスポート形式 -- COCO、YOLO、CoNLL、その他のエクスポート形式
- リモートデータソース -- クラウドストレージからのデータ読み込み
- 管理ダッシュボード -- エクスポートステータスのモニタリング
実装の詳細については、ソースドキュメントを参照してください。