drizzle-kit 0.31.4 修复解析:halfvec、bit、sparsevec类型生成 bug 与 pgvector 向量列支持详解
【免费下载链接】drizzle-ormORM项目地址: https://gitcode.com/gh_mirrors/dr/drizzle-orm
drizzle-kit 0.31.4 是一个聚焦性的修复版本,其核心变更只有一条:修复了halfvec、bit、sparsevec三种 PostgreSQL 类型在 drizzle-kit 中的类型生成 bug。本文以该变更说明(changelogs/drizzle-kit/0.31.4.md)为骨架,结合 drizzle-orm、drizzle-kit 仓库源码,说明这几种类型在 schema 定义、introspect 逆向生成与 SQL 生成中的实际行为,以及升级 0.31.4 后如何在项目里正确使用它们。
变更概览:一条修复背后的三个类型
0.31.4 的 changelog 全文如下:
Fixed
halfvec,bitandsparsevectype generation bug in drizzle-kit
这句话描述的是三类来自 pgvector 及 PostgreSQL 内置位串类型的列类型:
halfvec:pgvector 提供的半精度浮点向量类型,使用 16 位浮点存储每个维度,用于在保证召回率的前提下大幅压缩向量占用的磁盘与内存空间;sparsevec:pgvector 提供的稀疏向量类型,只存储非零维度及其值,适合高维但大多数维度为零的向量(例如 TF-IDF、词袋类特征);bit:PostgreSQL 内置的定长位串类型,配合 pgvector 的bit_hamming_ops、bit_jaccard_ops操作符类可做二进制向量的汉明距离、Jaccard 距离检索。
这三类类型都属于"非内建、依赖用户安装扩展才能使用"的类型,而 drizzle-kit 的 introspect(数据库结构逆向)流程此前在处理这类用户自定义类型时存在生成错误,0.31.4 正是针对这一问题的修复。
修复的核心:introspect 中对 USER-DEFINED 类型的判定
要理解这个 bug 的根因,需要看 drizzle-kit 逆向数据库结构时对列类型的分流逻辑。在 drizzle-kit/src/serializer/pgSerializer.ts 中,表列(第 1491-1498 行)与视图列(第 1786-1793 行)的类型归属使用了同一套判定:
type: // filter vectors, but in future we should filter any extension that was installed by user columnAdditionalDT === 'USER-DEFINED' && !['vector', 'geometry', 'halfvec', 'sparsevec', 'bit'].includes(enumType) ? enumType : columnTypeMapped,从源码结构可以推断出 bug 的成因:当数据库中的列被 PostgreSQL 元数据标记为USER-DEFINED类型时,drizzle-kit 会优先把它当作用户自定义枚举类型(走enumType分支)写入生成的 schema;但对于halfvec、sparsevec、bit这类同样以自定义类型形态存在、实则是 pgvector 扩展类型或内置位串类型的列,这种误判会把它们错误地当作 enum 处理,导致 introspect 生成的 schema 类型不正确。代码注释也明确写着 "filter vectors, but in future we should filter any extension that was installed by user",说明该修复策略是:先对已知的扩展类型(vector、geometry、halfvec、sparsevec、bit)做白名单排除,使其回落到columnTypeMapped分支,按原生类型名生成。
同时,drizzle-kit/src/sqlgenerator.ts 第 137-141 行将vector、geometry、halfvec、sparsevec、bit一并收录进 PostgreSQL 原生类型白名单pgNativeTypes:
'vector', 'geometry', 'halfvec', 'sparsevec', 'bit',该白名单的用途在于:生成 SQL(push / generate / migrate)时,只有命中白名单的类型才不会被强制加 schema 前缀和双引号包裹。也就是说,halfvec、sparsevec、bit只有被识别为原生类型,才会以halfvec(768)、bit(64)这种干净的形式出现在生成的 SQL 中,而不是被错误地引用为带引号的用户自定义类型。
三种类型在 drizzle-orm 中的 schema 定义方式
修复的前提是 drizzle-orm 早已为这三种类型提供了完整的一等公民 API,均位于 drizzle-orm/src/pg-core/columns/vector_extension/ 目录下,并在 drizzle-orm/src/pg-core/columns/index.ts 中统一导出。
halfvec:半精度向量列
halfvec的构造函数定义在 halfvec.ts,其列的数据类型为PgHalfVector,数据映射为number[],driver 参数为字符串。在 schema 中使用方式与vector完全一致:
import { pgTable, halfvec } from 'drizzle-orm/pg-core'; export const embeddings = pgTable('embeddings', { id: integer('id').primaryKey(), embedding: halfvec('embedding', { dimensions: 768 }), });参数说明:
dimensions:必填,声明向量的维度数。pgvector 对halfvec的维度上限较vector更宽松(可到数千维),但 schema 声明时仍应明确给出,方便 drizzle-kit 生成准确的halfvec(768)DDL。
sparsevec:稀疏向量列
sparsevec的构造函数定义在 sparsevec.ts,存在重载签名以兼容"名称 + 维度配置"与"仅名称(使用默认维度 0)"两种调用形式。其数据映射同样为number[]:
import { pgTable, sparsevec } from 'drizzle-orm/pg-core'; export const docs = pgTable('docs', { id: integer('id').primaryKey(), features: sparsevec('features', { dimensions: 4096 }), });参数说明:
dimensions:声明稀疏向量的最大维度数。注意 pgvector 对sparsevec的维度限制取决于所用版本(早期版本限制为 1600,新版放宽),声明时应以实际安装的 pgvector 版本为准;- 稀疏向量的实际存储只会记录非零维度,因此即使维度声明很大,只要数据稀疏,存储成本依然可控。
bit:定长位串列
bit的构造函数定义在 bit.ts,同样支持带维度配置或不带的调用形式,数据映射为字符串位串:
import { pgTable, bit } from 'drizzle-orm/pg-core'; export const binaryVecs = pgTable('binary_vecs', { id: integer('id').primaryKey(), code: bit('code', { dimensions: 64 }), });参数说明:
dimensions:位串长度,声明后生成的 DDL 为bit(64);若不声明,则为无约束的bit;- 位串类型常配合 pgvector 的
bit_hamming_ops(汉明距离)与bit_jaccard_ops(Jaccard 距离)操作符类建立索引,用于二进制哈希向量的近邻检索。
三类类型可用的操作符类
drizzle-kit/src/extensions/vector.ts 中集中维护了 drizzle-kit 认可的向量扩展操作符类:
export const vectorOps = [ 'vector_l2_ops', 'vector_ip_ops', 'vector_cosine_ops', 'vector_l1_ops', 'bit_hamming_ops', 'bit_jaccard_ops', 'halfvec_l2_ops', 'sparsevec_l2_ops', ];从中可以确认:
halfvec支持halfvec_l2_ops(L2 距离索引);sparsevec支持sparsevec_l2_ops(L2 距离索引);bit支持bit_hamming_ops与bit_jaccard_ops。
也就是说,在 drizzle-kit 0.31.4 中,这三类列不仅能被正确 introspect 和生成类型,还能在 drizzle-orm/src/pg-core/indexes.ts 对应的索引语法中被正确识别,例如:
import { pgTable, halfvec, index } from 'drizzle-orm/pg-core'; export const embeddings = pgTable('embeddings', { id: integer('id').primaryKey(), embedding: halfvec('embedding', { dimensions: 768 }), }, (t) => [ index('embedding_idx').using('hnsw', t.embedding.op('halfvec_l2_ops')), ]);该修复覆盖的完整工作流
结合源码可以确认,0.31.4 的修复贯穿 drizzle-kit 的三条主链路:
- introspect 逆向:
drizzle-kit introspect读取数据库元数据时,halfvec、sparsevec、bit不再被误判为自定义枚举类型,而是生成正确的列类型(见 pgSerializer.ts 表列与视图列两处分流); - SQL 生成:push / generate / migrate 生成 DDL 时,这三类类型命中
pgNativeTypes白名单(sqlgenerator.ts),以无引号、无 schema 前缀的原生类型形式输出; - schema 定义:配合 drizzle-orm 侧
halfvec、sparsevec、bit列构造器(vector_extension),开发者手写 schema 与数据库结构保持一致。
升级到 drizzle-kit 0.31.4 后,建议回归验证一次针对 pgvector 相关表的 introspect 与 generate 流程,确认生成的列类型与索引操作符类符合预期。需要说明的是:这三类类型均依赖 PostgreSQL 侧安装对应扩展(pgvector 提供halfvec、sparsevec及bit的操作符类,bit本身是 PostgreSQL 内置类型),drizzle-kit 只负责在 ORM 与迁移层正确表达它们,扩展的安装仍需在数据库层面完成。
【免费下载链接】drizzle-ormORM项目地址: https://gitcode.com/gh_mirrors/dr/drizzle-orm
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考