JSONL vs Parquet:最適なデータフォーマットの選び方
JSONL(JSON Lines)と Apache Parquet の包括的な比較。圧縮率、クエリパフォーマンス、スキーマ強制、エコシステムサポートのトレードオフを理解し、データワークロードに最適なフォーマットを選びましょう。
最終更新:2026年2月
JSONL とは?
JSONL(JSON Lines)は、各行が改行文字で区切られた単一の自己完結型 JSON オブジェクトを含むテキストベースのデータフォーマットです。広く普及した JSON フォーマットの自然な拡張であり、ストリーミングやログ形式のデータ向けに特別に設計されています。各行が独立した JSON ドキュメントであるため、既存データを書き換えずにファイルに追記でき、最小限のメモリオーバーヘッドで行単位で処理できます。
JSONL は、機械学習トレーニングデータ(OpenAI ファインチューニング、Hugging Face データセット)、アプリケーションログ、イベントストリーム、データが段階的に到着するあらゆるシナリオにおいて標準的な交換フォーマットとなっています。人間が読めるため、テキストエディタや grep、head、jq などのコマンドラインツールで簡単に内容を確認できます。
{"id": 1, "name": "Alice", "role": "engineer", "salary": 95000}{"id": 2, "name": "Bob", "role": "designer", "salary": 88000}{"id": 3, "name": "Charlie", "role": "manager", "salary": 105000}
Parquet とは?
Apache Parquet は、大規模データセットに対する効率的な分析クエリのために設計されたカラム型バイナリストレージフォーマットです。JSONL のように行単位でデータを格納する代わりに、Parquet は列単位で値を整理します。つまり、数百万行にわたる単一フィールドの読み取りに、すべてのレコード全体をスキャンするのではなく、関連する列のみのスキャンで済みます。このカラム型レイアウトにより、列内の値は型と分布が類似する傾向があるため、積極的な圧縮が可能になります。
Parquet は Apache Hadoop エコシステム内で作成され、現在は AWS S3、Google Cloud Storage、Azure Blob Storage 上に構築されたデータレイクのデファクト ストレージフォーマットです。Apache Spark、Apache Hive、Presto、DuckDB、Snowflake、BigQuery、およびほぼすべての最新の分析エンジンと深く統合されています。Parquet ファイルはメタデータに厳密なスキーマを埋め込むため、コンシューマーは外部ドキュメントなしでデータの正確な型と構造を常に把握できます。
import pyarrow.parquet as pqimport pandas as pd# Write a DataFrame to Parquetdf = pd.DataFrame({'id': [1, 2, 3],'name': ['Alice', 'Bob', 'Charlie'],'role': ['engineer', 'designer', 'manager'],'salary': [95000, 88000, 105000]})df.to_parquet('employees.parquet')# Read specific columns (columnar advantage)df = pq.read_table('employees.parquet', columns=['name', 'salary']).to_pandas()
JSONL vs Parquet:並列比較
以下の表は、プロジェクトのデータフォーマットを選択する際に最も重要な次元で JSONL と Parquet の主な違いをまとめています。
| 特徴 | JSONL | Parquet |
|---|---|---|
| データレイアウト | 行指向、テキストベース。各行が完全な JSON オブジェクト。 | 列指向、バイナリ。値は行グループ単位で列ごとに格納。 |
| エンコーディング | UTF-8 プレーンテキスト。人間が読める、テキストエディタで編集可能。 | 辞書エンコーディング、RLE、ビットパッキングを使用したバイナリ。人間には読めない。 |
| 圧縮 | 外部圧縮(gzip、zstd)がオプション。フィールド名が毎行繰り返される。 | 組み込みのカラム圧縮(Snappy、Zstd、Gzip)。2〜10 倍小さいファイル。 |
| クエリパフォーマンス | すべてのクエリでファイル全体をスキャンする必要がある。列の剪定やプレディケートプッシュダウンなし。 | 列の剪定とプレディケートプッシュダウンで不要なデータをスキップ。分析クエリでは桁違いに高速。 |
| スキーマ | スキーマフリー。各行で異なるフィールドと型を持てる。柔軟だがエラーが起きやすい。 | ファイルメタデータに埋め込まれた厳密な型付きスキーマ。読み取りと書き込み時に強制。 |
| ストリーミング/追記 | 優秀。ファイルの末尾に新しい行を追加するだけ。リアルタイム取り込みに最適。 | 不向き。データ追加にはファイルの書き換えまたは新しいパーティションの作成が必要。 |
| 人間が読める | はい。cat、head、grep、jq、またはテキストエディタで確認可能。 | いいえ。確認には専用ツール(parquet-tools、PyArrow、DuckDB)が必要。 |
| エコシステム | ユニバーサル。JSON パーサーを持つすべてのプログラミング言語でサポート。 | 分析に特化。Spark、Hive、Presto、DuckDB、Snowflake、BigQuery と深く統合。 |
パフォーマンスベンチマーク
JSONL と Parquet のパフォーマンス差はスケールアップするほど顕著になります。以下は、1,000 万行、20 列(文字列、整数、浮動小数点数、タイムスタンプの混合)のデータセットの代表的なベンチマークです。
ファイルサイズ(圧縮)
フルテーブルスキャン
書き込み速度
単一列クエリ
ベンチマークは M2 MacBook Pro(16 GB RAM)上で Python(pandas + PyArrow)を使用して測定。実際の結果はハードウェア、データ分布、圧縮コーデックによって異なります。
JSONL vs Parquet の使い分け
- リアルタイムログ収集とイベントストリーミング
- OpenAI、Anthropic、Hugging Face 向け ML トレーニングデータ
- マイクロサービスと API 間のデータ交換
- レコードごとにスキーマが異なる半構造化データ
- 人間が読めることが重要な迅速なプロトタイピングとデバッグ
- レコードが継続的に到着する追記専用データ
- 分析クエリが不要な小〜中規模データセット(1 GB 未満)
- S3、GCS、Azure Blob 上のデータレイクストレージ
- Spark、Presto、DuckDB、Snowflake を使用した分析クエリ
- 数十億行にわたるカラム型集計(SUM、AVG、COUNT)
- 厳格なスキーマ強制とデータガバナンス要件
- ストレージコストが重要な長期アーカイブ(2〜10 倍小さいファイル)
- 特定の列を読み取るフィーチャーストアと ML フィーチャーパイプライン
- クエリパフォーマンスが重要な 1 GB 以上のデータセット
ハイブリッドアーキテクチャ:JSONL で取り込み、Parquet で保存
本番データプラットフォームでは、JSONL と Parquet は相互排他的ではありません。一般的で効果的なパターンは、データ取り込みに JSONL を使用し、長期保存と分析に Parquet を使用することです。このハイブリッドアプローチは、両方のフォーマットの強みを組み合わせます:リアルタイムデータキャプチャのための JSONL のシンプルさと、下流クエリのための Parquet の効率性。
パイプラインは3つのステージで動作します。まず、JSONL がロックフリーの高速追記をサポートするため、生のイベントやレコードが到着次第 JSONL ファイルに追記されます。次に、定期的なバッチジョブ(毎時、毎日、またはファイルサイズ契機)が蓄積された JSONL ファイルを読み取り、データを検証・変換して Parquet 形式に変換します。最後に、生成された Parquet ファイルは、効率的なクエリのために日付、リージョン、その他の次元でパーティションされたデータレイクに保存されます。
1. JSONL として取り込み
生のイベント、ログ、API レスポンスを JSONL ファイルとして収集。高速な追記、スキーマ不要、リアルタイムでのデバッグが容易。
2. 変換と検証
定期的に JSONL バッチを読み取り、スキーマ検証を適用し、データをクリーニング・正規化し、不正なレコードを処理。
3. Parquet として保存
検証済みデータをパーティション化された Parquet ファイルとしてデータレイクに書き込み。Spark、DuckDB、または他の分析エンジンでクエリ。
import jsonimport pandas as pdimport pyarrow as paimport pyarrow.parquet as pqfrom pathlib import Pathfrom datetime import datetimedef jsonl_to_parquet(jsonl_dir: str, parquet_dir: str):"""Convert accumulated JSONL files to partitioned Parquet."""records = []for jsonl_file in Path(jsonl_dir).glob('*.jsonl'):with open(jsonl_file, 'r') as f:for line in f:line = line.strip()if line:records.append(json.loads(line))if not records:returndf = pd.DataFrame(records)# Add partition columndf['date'] = datetime.now().strftime('%Y-%m-%d')table = pa.Table.from_pandas(df)pq.write_to_dataset(table,root_path=parquet_dir,partition_cols=['date'],compression='zstd')print(f'Converted {len(records)} records to Parquet')jsonl_to_parquet('raw_events/', 'data_lake/')
無料 JSONL ツールを試す
JSONL ファイルを扱っていますか?無料のブラウザベースツールで JSONL データの表示、検証、変換を即座に行えます。インストールやアップロード不要。