跳转到主要内容

向量类型

在前面的索引和搜索章节中,我们接触了 vector 类型。本节将探讨更多向量类型及其在向量搜索领域的应用。

在前面的索引和搜索章节中,我们已经接触了标准的 vector 类型。本节将探讨更多向量数据类型及其在向量搜索领域的应用:

低精度索引

since v0.3.0

为了提升在 vector 列上的查询速度并降低内存占用,可以考虑使用表达式索引,基于 vecf16、veci8 或 bvector 类型创建低精度索引,而非直接对 vector 类型创建全精度索引:

CREATE TABLE t (val vector(3));
INSERT INTO t (val) SELECT ARRAY[random(), random(), random()]::real[] FROM generate_series(1, 1000);

-- 在 vector 列上创建 bvector 二值向量索引
-- 注意:在构建索引时,Float32 向量会被截断为 0 或 1 的整数
CREATE INDEX lp_bin ON t USING vectors ((binarize(val)::bvector(3)) bvector_l2_ops);

-- 在 vector 列上创建 vecf16 半精度向量索引
CREATE INDEX lp_f16 ON t USING vectors ((val::vecf16(3)) vecf16_l2_ops);

-- 在 vector 列上创建 veci8 整数向量索引
-- 注意:在构建索引时,Float32 向量会被截断为 -128 到 127 之间的整数
CREATE INDEX lp_i8 ON t USING vectors ((val::veci8(3)) veci8_l2_ops);

缩短嵌入向量(Shortening Embedding)

since v0.3.0

部分嵌入模型(例如 OpenAI 的 text-embedding-3-small 和 text-embedding-3-large)支持缩短嵌入向量,即直接移除向量序列末尾的部分数值,而不会丢失嵌入向量的核心概念表达能力。

在某些场景下,可能需要在嵌入生成并入库之后再动态调整检索维度。pgvecto.rs 提供了通过数组切片语法直接使用缩短后的嵌入向量进行查询和建索引的方法:

CREATE TABLE t (val vector(3));
INSERT INTO t (val) SELECT ARRAY[random(), random(), random()]::real[] FROM generate_series(1, 1000);
CREATE INDEX ON t USING vectors (val vector_l2_ops);

-- 仅使用前两个维度计算距离
SELECT * from t ORDER BY (val[:2])::vector(2) <-> '[3, 2]'::vector;

自 v0.3.0 版本起,pgvecto.rs 中的所有向量数据类型均支持缩短嵌入向量切片操作。

类型转换

下图展示了不同向量数据类型之间的转换关系,由箭头连接的两个类型可以相互转换(Cast):

其中,ARRAY 是 PostgreSQL 的原生数组类型,其余均为 pgvecto.rs 定义的向量类型。

以下是向量类型转换的几个示例:

-- 合法:字符串 ⇒ vector
SELECT '{1,2,3}'::vector;

-- 合法:vector ⇒ ARRAY
SELECT '{1,2,3}'::vector::real[];

-- 合法:ARRAY ⇒ vector ⇒ bvector
SELECT ARRAY[1.0 ,0 ,0]::real[]::vector::bvector;

-- 报错:无法直接将类型 vecf16 转换为 veci8
SELECT '[3, 2]'::vecf16::veci8;

-- 合法:vecf16 ⇒ vector ⇒ veci8
SELECT '[3, 2]'::vecf16::vector::veci8;

vecf16 以半精度浮点数格式存储,利用 16 位浮点数,与标准 vector 相比仅占用一半的内存和带宽。

Int8 是用于表示有符号整数的数据类型,使用 8 位内存存储范围在 -128 到 127 之间的整数,显著降低向量存储的内存占用。

与稠密向量不同,稀疏向量具有极高的维度,但仅包含少量非零值。

bvector 是 pgvecto.rs 中的二值向量类型,其每个分量仅取 0 或 1 两个可能值,并针对存储和距离计算进行了深度优化。