JSONL vs Parquet:选择正确的数据格式
全面比较 JSONL(JSON Lines)和 Apache Parquet。了解在压缩、查询性能、Schema 强制和生态系统支持方面的取舍,为您的数据工作负载选择正确的格式。
最后更新: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 文件在其元数据中嵌入严格的 Schema,因此消费者始终知道数据的确切类型和结构,无需外部文档。
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 倍。 |
| 查询性能 | 任何查询都必须扫描整个文件。不支持列裁剪或谓词下推。 | 列裁剪和谓词下推可跳过无关数据。分析查询快数个数量级。 |
| Schema | 无 Schema。每行可以有不同的字段和类型。灵活但容易出错。 | 严格的类型化 Schema 嵌入文件元数据。在读写时强制执行。 |
| 流式处理 / 追加 | 优秀。在文件末尾追加新行即可。非常适合实时数据摄入。 | 较差。添加数据需要重写或创建新的文件分区。 |
| 人类可读 | 是。可用 cat、head、grep、jq 或任何文本编辑器检查。 | 否。需要专用工具(parquet-tools、PyArrow、DuckDB)来检查。 |
| 生态系统 | 通用。所有具有 JSON 解析器的编程语言都支持。 | 面向分析。与 Spark、Hive、Presto、DuckDB、Snowflake、BigQuery 深度集成。 |
性能基准测试
JSONL 和 Parquet 之间的性能差距在大规模数据下变得非常显著。以下是一个包含 1000 万行、20 列(混合字符串、整数、浮点数和时间戳)的数据集的代表性基准测试。
文件大小(压缩)
全表扫描
写入速度
单列查询
基准测试使用 Python(pandas + PyArrow)在配备 16 GB RAM 的 M2 MacBook Pro 上进行。实际结果因硬件、数据分布和压缩编码而异。
何时使用 JSONL 与 Parquet
- 实时日志摄入和事件流
- 用于 OpenAI、Anthropic 和 Hugging Face 的 ML 训练数据
- 微服务和 API 之间的数据交换
- 每条记录具有不同 Schema 的半结构化数据
- 需要人类可读性的快速原型设计和调试
- 记录持续到达的仅追加数据
- 不需要分析查询的中小型数据集(1 GB 以下)
- 在 S3、GCS 或 Azure Blob 上的数据湖存储
- 使用 Spark、Presto、DuckDB 或 Snowflake 的分析查询
- 跨数十亿行的列式聚合(SUM、AVG、COUNT)
- 严格的 Schema 强制和数据治理要求
- 存储成本重要的长期归档(文件小 2-10 倍)
- 读取特定列的特征存储和 ML 特征管道
- 查询性能至关重要的大于 1 GB 的数据集
混合架构:JSONL 摄入,Parquet 存储
在生产数据平台中,JSONL 和 Parquet 并非互斥。一种常见且有效的模式是使用 JSONL 进行数据摄入,使用 Parquet 进行长期存储和分析。这种混合方式结合了两种格式的优势:JSONL 在实时数据捕获方面的简单性和 Parquet 在下游查询方面的效率。
管道分三个阶段工作。首先,原始事件或记录在到达时追加到 JSONL 文件中,因为 JSONL 支持快速、无锁追加。其次,定期批处理作业(每小时、每天或按文件大小触发)读取累积的 JSONL 文件,验证和转换数据,并将其转换为 Parquet 格式。第三,生成的 Parquet 文件按日期、地区或其他维度分区存储在数据湖中,以实现高效查询。
1. 以 JSONL 格式摄入
将原始事件、日志和 API 响应收集为 JSONL 文件。追加速度快,无需 Schema,便于实时调试。
2. 转换与验证
定期读取 JSONL 批次,应用 Schema 验证,清洗和规范化数据,处理格式错误的记录。
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 数据。无需安装或上传。