为了存AI向量,Parquet也要改:数据湖格式遇到新的结构问题

摘要:AI向量让Parquet遇到新的结构问题:固定长度数组、低重复浮点数、相似度查询和向量索引,都超出了传统结构化列式表的常见假设。

一家企业把产品资料、设备手册、维修记录和工艺文件切分成数千万个文本片段,再为每个片段生成一条向量。

每条向量有1536个浮点数。按照32位浮点格式计算,一条向量约占6KB。一亿条向量仅原始数值便超过600GB,还没有计算文本、文档元数据、索引和历史版本。

这些数据需要长期保存,也要被Spark、Python、数据仓库、训练平台和检索系统共同读取。

很多企业会把它们写入Parquet。

Parquet已经是数据湖中使用最广泛的列式文件格式之一。它擅长保存大规模结构化数据,支持压缩、列裁剪、分区和跨引擎读取。但向量与普通数字列存在明显差异:每一行都包含几百到几千个浮点数,同一列中的向量维度固定,数值重复率很低,查询方式也从条件过滤扩展到相似度搜索。

2026年,Apache Parquet社区开始集中处理这些问题。

截至2026年7月15日,Parquet官网列出的最新parquet-format版本为2.13.0,发布时间为6月13日。一个名为FIXED_SIZE_LIST的新逻辑类型仍处于Open、Unresolved状态。7月6日,社区还发起了格式版本机制投票,用于组织可能导致旧读取器无法识别的新变化。

这些工作涉及一个基础问题:

数据湖怎样保存数量越来越大的AI向量,同时保持Parquet长期以来的跨系统兼容性?

一、Parquet原来怎样组织数据

Parquet采用列式存储。

一个文件被分成若干Row Group,每个Row Group包含各列对应的Column Chunk,Column Chunk内部继续分成多个Page。读取某几列时,查询引擎可以跳过其他列;过滤条件足够明确时,还可以利用统计信息、页索引和布隆过滤器减少数据读取量。

例如,一张设备表包含:

1
设备编号 设备类型 工厂 安装日期 当前状态 累计运行小时

查询某个工厂的异常设备时,系统只需读取工厂、设备编号和状态相关的数据页。

这种设计适合:

  • 数值统计;
  • 条件筛选;
  • 聚合分析;
  • 批量扫描;
  • 按列读取;
  • 大规模离线计算。

向量列长这样:

1
embedding = [ 0.0127, -0.0831, 0.1142, ... 0.0274 ]

一行不再是单个数值,而是一组固定长度的数值。

问题由此出现。

二、向量为什么通常是固定长度

嵌入模型会把文本、图片、声音或设备状态转换成一组数字。

同一个模型输出的向量维度通常保持一致。例如,一个模型可能输出384维,另一个模型输出768维、1024维或1536维。

同一张表中的一列向量通常具有以下结构:

1
2
3
4
第1行:1536个float32
第2行:1536个float32
第3行:1536个float32
……

每一行的长度已经由模型决定,不需要为每条记录单独保存长度。

Apache Arrow已经提供FixedSizeList类型。它把每行数据表示为固定数量的子元素。因为每行长度一致,内存中不需要额外的Offset Buffer,某行向量的起始位置可以直接通过“行号×维度”计算。

假设向量维度为768:

1
2
3
第0行起点:0 × 768
第1行起点:1 × 768
第2行起点:2 × 768

读取器不必先查询每一行从哪里开始、在哪里结束。

这种结构也更接近NumPy矩阵、GPU张量和向量检索引擎使用的数据布局。

三、Parquet目前怎样保存FixedSizeList

Parquet格式目前没有原生的FIXED_SIZE_LIST逻辑类型。

Apache Arrow在写入Parquet时,会把Arrow的FixedSizedList映射成普通Parquet LIST。如果文件同时保存了Arrow Schema,Arrow读取器可以在读取时恢复原来的固定长度类型。

这条路径能够工作,但存在几个问题。

1. 文件结构表达的是可变长度列表

Parquet LIST允许每一行包含不同数量的元素。

例如:

1
2
3
第1行:[1, 2]
第2行:[3, 4, 5]
第3行:[6]

固定长度向量不会使用这种灵活性。

读取器仍要按照普通嵌套列表处理定义级别、重复级别和行边界,再把它重建为固定形状的数组。

2. 固定维度依赖附加元数据

没有Arrow Schema时,其他读取器看到的可能只是一列普通列表,无法确认它代表768维向量、图像张量还是其他数组。

维度信息可能存在于:

  • Arrow Schema;
  • 文件级Key-Value Metadata;
  • 表结构;
  • 应用程序配置;
  • 外部数据目录。

不同工具使用不同信息来源,容易出现解释差异。

3. 转换增加额外处理

Apache Parquet的相关Jira说明,当前将FixedSizeList存成List会给读写过程带来明显转换开销,因此提出增加FIXED_SIZE_LIST逻辑类型。该提案还面向Arrow的固定形状张量、机器学习和科学计算数据。

4. 兼容情况依赖具体实现

Parquet是开放格式,Spark、Arrow、DuckDB、ClickHouse、Trino和其他系统都有自己的读取器。

某个实现能够根据附加Schema恢复FixedSizeList,不代表其他实现也会采用相同方式。此前已有查询引擎报告无法识别由Arrow Schema推断出的fixed_size_list类型。

企业需要验证完整的数据链路,不能只测试写入工具和同一套工具的读取结果。

四、FIXED_SIZE_LIST准备解决什么问题

提议中的FIXED_SIZE_LIST会在Parquet Schema里明确表达:

1
embedding: FIXED_SIZE_LIST<FLOAT, 768>

读取器打开文件后,可以直接知道:

  • 这一列是固定长度数组;
  • 每行包含768个元素;
  • 元素类型为32位浮点数;
  • 行边界可以按固定规则计算;
  • 数据适合转换成矩阵或张量。

与普通LIST相比,它减少了语义猜测。

对于向量数据,固定长度还可以帮助系统完成以下检查:

  • 写入时拒绝错误维度;
  • 合并文件时发现Schema不一致;
  • 模型切换后识别维度变化;
  • 直接映射到Arrow FixedSizeList;
  • 更高效地转换到NumPy、PyTorch或GPU缓冲区;
  • 为后续向量索引提供稳定的数据布局。

截至2026年7月15日,这一类型仍是提案,尚未进入已发布的Parquet格式。企业当前不能把它当作所有工具均支持的标准能力。

五、为什么增加一个类型还要讨论格式版本

Parquet长期强调兼容性。

一个旧读取器打开新文件时,即使不认识某项扩展,也应尽量读取能够理解的部分。

FIXED_SIZE_LIST涉及前向兼容问题。

假设新版本文件使用了旧读取器完全不认识的逻辑类型,旧读取器可能出现几种行为:

  • 拒绝打开文件;
  • 把它降级成底层物理类型;
  • 按普通列表读取;
  • 忽略维度信息;
  • 产生与写入端不同的Schema;
  • 读取成功但无法保持原有语义。

Parquet社区在2026年讨论采用版本化发布方式,把一组可能造成前向不兼容的变化放入明确的新格式版本。7月6日发起的投票提出,利用版本号发布这类变化,思路与Apache Iceberg管理格式版本的方式相近。

这不意味着旧Parquet文件会失效。

主要目的是让写入器、读取器和数据平台明确知道:

  • 文件使用哪个格式版本;
  • 某个版本包含哪些能力;
  • 当前引擎是否支持这些能力;
  • 不支持时应拒绝、降级还是忽略;
  • 企业何时可以启用新格式。

对数据湖而言,这种信息比“文件扩展名仍然是.parquet”更重要。

六、向量对Parquet的挑战不只在数据类型

增加FIXED_SIZE_LIST只能解决部分问题。

向量数据还有四个明显特点。

1. 单列体积很大

一条1536维float32向量约6KB。

一百万条约6GB,一亿条约600GB。

如果一张表同时保存文本、图片特征、标题向量和多个模型版本,向量列可能占据绝大部分存储空间。

普通分析表经常有几十列,但每个单元格很小。向量表可能只有几列,其中一列便包含数千个数字。

Row Group、Page Size、文件大小和内存批次都需要重新测试。

Parquet官方配置文档建议大Row Group有利于顺序I/O,但更大的Row Group也需要更多写入缓冲区;Page越小,读取粒度越细,同时会增加页头开销。向量工作负载不能机械套用传统宽表参数。

2. 浮点数重复率低

字典编码适合大量重复值。

嵌入向量中的浮点数通常具有高基数,相同数值重复出现的比例有限。普通文本列和枚举列常用的编码方式,未必能给向量列带来同样效果。

2026年Parquet格式仓库中的向量存储问题也专门提出了编码、压缩、统计信息、Row Group和Page Size如何配置的问题。提问中给出的典型向量规模为700至1500维,每条约3KB至6KB。

企业需要用自己的模型和数据实测:

  • 不压缩;
  • Snappy;
  • Zstd;
  • 不同浮点编码;
  • float32;
  • float16;
  • int8量化。

压缩率、读取速度、精度损失和跨工具支持需要一起评估。

3. Min/Max统计对相似度查询帮助有限

普通数值查询可以写成:

1
WHERE temperature > 80

Parquet可以利用Min/Max统计跳过不符合条件的数据页。

向量查询通常是:

1
找出与查询向量距离最近的100条记录

判断结果需要计算整条向量的余弦距离、点积或欧氏距离。

某一维的最小值和最大值,通常无法直接判断整条向量是否接近查询向量。

Parquet Page Index的官方设计目标包括范围扫描和点查优化,同时明确把“为非排序数据提供类似二级索引的结构”列为非目标。

因此,向量以合适格式写入Parquet后,还需要索引层处理最近邻搜索。

4. 随机读取模式不同

Parquet擅长按列、按Row Group和按Page读取。

向量搜索可能先通过索引找到一批候选ID,再从文件中读取这些ID对应的向量、文本和元数据。

候选记录可能分散在多个文件和Row Group中。

数据布局不合理时,一次查询为了取回几百条记录,可能触发大量对象存储请求和数据页解码。

文件组织、聚类、索引位置和缓存方式会直接影响在线检索延迟。

七、Parquet不能单独承担完整的向量检索

Parquet可以承担向量的长期存储和跨引擎交换。

相似度搜索还需要一套索引结构,例如:

  • HNSW;
  • IVF;
  • IVF-PQ;
  • 倒排分区;
  • 标量量化;
  • 产品量化;
  • GPU向量索引。

索引可以保存在:

  • 独立文件;
  • 数据库;
  • 内存服务;
  • 对象存储;
  • Parquet文件附加区域;
  • 表格式管理的元数据中。

Apache DataFusion已经展示过把自定义索引数据附加到Parquet文件中,再通过Footer Metadata记录索引位置的方法。不了解这种索引的普通读取器可以忽略附加数据,支持它的查询引擎则可以利用索引跳过无关数据。

这种设计给向量索引提供了一个方向,但也带来管理问题:

  • 数据更新时索引如何同步;
  • 多个文件的索引如何合并;
  • 索引使用哪个距离函数;
  • 索引由哪个模型版本生成;
  • 文件替换后旧索引何时失效;
  • 不同查询引擎能否共享索引。

企业更常见的架构可以分成三层。

第一层:Parquet数据层

保存原始数据、文本片段、向量和业务元数据。

第二层:向量索引层

保存用于快速定位候选记录的ANN索引。

第三层:查询服务层

负责权限过滤、混合检索、重排序、缓存和结果返回。

Parquet提供可移植的数据底座,索引负责速度,服务层负责业务逻辑。

八、向量表应该保存哪些字段

很多项目只保存两列:

1
id embedding

这种设计很快会遇到维护问题。

一张可治理的向量表至少应考虑以下字段:

1
record_id document_id chunk_id content content_hash source_uri embedding embedding_dimension embedding_data_type embedding_model embedding_model_version normalization_method created_at updated_at tenant_id project_id security_level is_deleted

每个字段解决一个具体问题。

embedding_model

说明向量由哪个模型生成。

不同模型的向量不能直接混合计算距离。

embedding_model_version

同一模型升级后,输出分布可能发生变化。

名称相同也不能默认兼容。

embedding_dimension

用于检查向量长度。

即使未来使用FIXED_SIZE_LIST,表级元数据中保留维度仍有利于治理和检查。

content_hash

判断原始内容是否发生变化。

文档内容更新后,旧向量需要重新生成。

security_level

向量不能脱离原始数据权限。

一条向量看似是数字,仍可能泄露原文特征,也可能帮助用户检索到无权访问的内容。

is_deleted

原始文档删除后,向量、索引和缓存也需要同步删除。

仅删除文本,不删除对应向量,检索系统仍可能返回旧记录。

九、模型升级会造成数据湖中的“向量断层”

企业更换嵌入模型时,常见变化包括:

  • 维度从768变成1024;
  • float32改为float16;
  • 归一化方式变化;
  • 中文效果提升;
  • 图片与文本使用统一空间;
  • 相似度函数发生变化。

新旧向量不能随意写入同一列。

即使维度相同,向量空间也可能完全不同。

例如:

1
2
model-A生成的768维向量
model-B生成的768维向量

两个模型都输出768个数字,不代表它们可以互相比较。

企业可以采用三种管理方式。

方式一:按模型拆表

1
2
document_embedding_model_a
document_embedding_model_b

结构清楚,切换时需要同时维护多张表。

方式二:按模型拆列

1
2
embedding_model_a
embedding_model_b

适合模型数量少、需要对比效果的阶段。

方式三:统一长表

1
document_id model_id model_version embedding

适合管理多个模型版本,查询时必须明确过滤模型。

无论采用哪种方式,都需要禁止不同模型向量进入同一个索引。

十、工业数据中也会出现大量向量

向量数据不只用于文本知识库。

工业应用会产生更多固定形状数组。

1. 设备状态向量

将一段时间内的振动、温度、电流、压力和声音转成特征向量,用于异常检测和设备相似性分析。

2. 视觉质检向量

将产品图片转换成向量,用于缺陷聚类、相似案例查找和样本去重。

3. 工艺过程向量

把一个批次的工艺曲线、参数组合和质量结果编码成向量,寻找相似生产过程。

4. CAD与三维模型向量

将零部件形状、拓扑和结构特征转换成向量,用于相似件检索、标准件匹配和设计复用。

5. 维修案例向量

把故障描述、报警序列、维修措施和结果编码,帮助工程师查找相似问题。

6. 智能体运行向量

对Prompt、工具轨迹、错误类型和处理结果生成向量,用于任务聚类、异常识别和经验检索。

这些数据往往还需要和设备ID、产线、批次、时间、工况和人员权限关联。

Parquet适合保存向量与业务字段的对应关系,后续可以交给不同计算引擎分析。

十一、企业现在怎样保存向量更稳妥

FIXED_SIZE_LIST仍未成为已发布标准时,企业可以采用兼容优先的方案。

第一,继续使用成熟的LIST结构

当前可以使用:

1
LIST<FLOAT>

同时确保每条向量长度一致。

写入前增加维度校验,发现异常记录立即拒绝或隔离。

第二,在Schema和元数据中记录维度

至少保存:

1
2
3
4
embedding_dimension = 1024
embedding_model = model-x
embedding_version = 2026-07
embedding_dtype = float32

避免读取端只看到一列没有说明的浮点列表。

第三,保存Arrow Schema时仍要测试其他引擎

Arrow可以通过文件元数据恢复FixedSizeList,但企业需要分别测试:

  • PyArrow;
  • Spark;
  • DuckDB;
  • Trino;
  • ClickHouse;
  • 自研读取程序;
  • 云数据仓库;
  • 向量索引构建工具。

测试内容包括:

  • Schema是否一致;
  • Null能否正确读取;
  • 维度是否保留;
  • 列裁剪是否有效;
  • 批量转换是否产生额外复制;
  • 大文件是否出现内存峰值。

第四,把向量列与高频业务列合理拆分

用户经常查询文档标题、权限和更新时间,却不一定每次都读取向量。

可以把元数据和大体积向量分开组织,通过稳定ID关联,减少普通查询读取向量页的机会。

拆分也会增加文件和关联管理成本,需要结合查询模式决定。

第五,单独测试文件大小和Row Group

向量表不能直接沿用普通业务表参数。

需要测试:

  • 单文件包含多少条向量;
  • 一个Row Group多大;
  • 构建索引时的顺序读取速度;
  • 根据ID回查时的随机读取量;
  • 对象存储请求次数;
  • 并发读取时的内存占用。

第六,保留重新生成能力

向量属于派生数据。

企业应保存原始内容、切分规则、模型版本和生成参数,使向量能够重新构建。

把向量当成唯一数据副本,会让模型升级和数据修复变得困难。

十二、格式升级需要经过中试验证

未来Parquet发布支持FIXED_SIZE_LIST的新版本后,企业也不适合立即全面切换。

可以先建立一套兼容性测试。

写入测试

使用不同工具生成相同Schema的文件。

读取测试

验证各个数据引擎能否识别新类型。

降级测试

旧读取器遇到新文件时,是拒绝、忽略还是错误解释。

性能测试

比较:

  • 普通LIST;
  • FIXED_SIZE_LIST;
  • 不同压缩格式;
  • 不同Row Group;
  • 不同Page Size;
  • 不同批次大小。

数据一致性测试

确认向量维度、顺序、Null和浮点精度没有变化。

索引测试

检查向量索引能否从新格式直接构建,查询结果是否和旧格式一致。

回滚测试

新读取器或新文件格式出现问题时,能否恢复到旧版本数据。

Parquet文件经常需要保存多年。

一次格式升级的影响范围可能覆盖数据湖、查询引擎、机器学习平台、备份系统和下游客户,兼容性验证需要先于批量迁移。

十三、Parquet的变化说明AI数据进入了通用数据基础设施

早期向量数据常被放在单独的实验文件、NumPy数组或专用数据库中。

企业应用扩大后,向量需要和订单、设备、文档、图片、权限和审计记录一起管理。

它们需要具备普通企业数据已有的能力:

  • 明确Schema;
  • 版本控制;
  • 跨工具读取;
  • 权限管理;
  • 生命周期管理;
  • 数据质量检查;
  • 删除与更新;
  • 成本控制;
  • 长期归档。

Parquet增加固定长度数组支持的讨论,反映的是数据类型发生了变化。

数据湖以前主要保存标量、文本、时间和嵌套业务记录。

现在还要保存:

  • 向量;
  • 张量;
  • 多模态特征;
  • 模型输出;
  • 智能体轨迹;
  • 科学计算数组。

FIXED_SIZE_LIST不会替代向量数据库,也不会单独解决相似度检索性能。

它能够让向量在开放文件格式中拥有更准确的结构表达,减少读写转换,并为数据湖、计算引擎和索引系统之间的数据交换提供统一基础。

企业需要同时建设四项能力:

  • Parquet或湖仓格式负责长期存储;
  • 向量索引负责候选检索;
  • 元数据系统负责模型与数据版本;
  • 权限和审计系统负责控制数据使用。

向量生成并不困难。

大量向量保存几年后仍然可读、可查、可删除、可迁移、可验证,才是数据基础设施要处理的问题。

分享到