向量检索
功能介绍
人工智能算法可以对物理世界的人/物/场景所产生各种非结构化数据(如语音、图片、视频,语言文字、行为等)进行抽象,变成多维的向量。
这些向量如同数学空间中的坐标,标识着各个实体和实体关系。我们一般将非结构化数据变成向量的过程称为 Embedding,而非结构化检索则是对这些生成的向量进行检索,从而找到相应实体的过程。

传统的关键词搜索主要依赖于对关键词的匹配,而忽略了查询的含义和语境。但语义搜索的优点在于它可以更好地满足用户的意图,尤其是对于复杂的查询和问题。
语义搜索能够:
- 理解查询的上下文
- 处理模糊或不完整的查询
- 提供更相关和有用的搜索结果
目前在业务上对向量检索能力进行支持,业界的使用上通常有如下几种:
-
基于开源的向量检索内核(比如faiss/scann/proxima/nmslib等)自己来做服务化,包成一个Restful API形式的在线向量检索服务
-
选用专门的向量检索数据库来支持向量检索的场景
-
选用一个数据库/数仓产品,包含向量检索功能的支持
在绝大多数情况下,使用专用向量数据库的弊都要远远大于利:
- 数据冗余
- 大量不必要的数据搬运工作
- 分布式组件之间缺乏一致性
- 额外的专业技能带来的复杂度成本、学习成本、以及人力成本
- 额外的软件许可费用
- 极其有限的查询语言能力、可编程性、可扩展性
- 有限的工具链
- 与真正数据库相比更差的数据完整性和可用性
而且在一个分布式的数据库产品里支持向量检索有个好处,可以利用其分布式的能力,可以轻松应对海量向量数据的场景。在支持分布式事务的产品里,对向量的写入、更新和删除同样天然满足分布式事务的强一致性。
ProtonBase 提供向量检索的能力,支持两种索引类型IVFFlat(Inverted File with Flat Quantization)和HNSW(Hierarchical Navigable Small World),实现了高效的向量检索的召回。支持数据的批量导入,实时更新/删除,并且支持条件过滤和向量检索的联合查询。
-
IVFFlat是一种基于倒排索引的近似最近邻搜索算法,用于高效地查询向量之间的相似度。它将向量空间分为若干个划分区域,每个区域都包含一些向量,并创建倒排索引,用于快速地查找与给定向量相似的向量。IVFFlat构建索引速度更快,消耗内存更少,但查询性能略慢。更适合在处理超大数据集时,可以显著减少搜索空间,提高查询效率。 -
HNSW是一种基于图的索引结构,构建了一个多层次的导航图。HNSW使用了随机跳跃的方式进行邻近搜索,通过在不同层的图结构中搜索,快速找到相似向量。它消耗内存更多,构建索引更慢,但查询性能更好。在高维数据中表现出更好的查询性能和准确性。
| 聚类索引 (IVFFlat) | 图索引(HNSW) | |
|---|---|---|
| 数据集大小 | [100K, ~] | [~, 100M] |
| 召回精度 | 中 | 高 |
| 查询性能 | 中 | 高 |
| 构建速度 | 快 | 慢 |
| 内存消耗 | 少 | 多 |
索引类型选择指南
在选择索引类型时,需要根据具体的使用场景和需求来决定。以下是选择 HNSW 和 IVFFlat 索引的建议:
何时选择 HNSW
HNSW 索引是大多数场景下的推荐选择,特别是当:
-
对查询精度要求高:HNSW 在高维数据中表现出更好的查询性能和准确性,适合对搜索结果质量要求较高的场景。
-
数据集规模适中:HNSW 适合处理百万级到千万级的向量数据集。
-
查询延迟敏感:HNSW 的查询性能优于 IVFFlat,适合对响应时间有严格要求的应用。
-
有足够的内存资源:HNSW 消耗更多内存,但能提供更好的查询性能。
何时选择 IVFFlat
IVFFlat 索引适合以下场景:
-
超大数据集:当数据量超过一亿条时,IVFFlat 能显著减少搜索空间,提高查询效率。
-
内存资源有限:IVFFlat 消耗内存较少,适合资源受限的环境。
-
可以接受中等精度:如果对查询精度要求不是特别高,IVFFlat 是一个经济高效的选择。
-
索引构建时间敏感:IVFFlat 构建索引速度更快,适合需要频繁重建索引的场景。
推荐选择
我们建议用户首先选择 HNSW 索引,因为它在大多数情况下能提供更好的查询性能和准确性。只有在内存资源非常有限或数据集特别庞大(超过一亿条记录)时,才考虑使用 IVFFlat 索引。
ProtonBase 通过实现PostgreSQL生态的pgvector插件进行扩展来支持向量检索的能力,pgvector 有着优雅简单易用的接口,更是继承了PostgreSQL生态的超能力集合。
建表语句
向量数据类型为vector,最高支持16000维,在声明向量字段的时候需要同时显示标识出其维度信息,内部是个Float类型的数组,这些数组被组成成紧凑的二进制格式以便高效的存储和检索。
CREATE TABLE items
(
id bigserial PRIMARY KEY,
embedding vector(3) -- 定义维度
)
USING columnar;向量索引
目前距离的度量方式支持三种:
-
<->- 欧式距离(L2 Distance),索引参数vector_l2_ops -
<#>- 内积距离(Inner Product),索引参数vector_ip_ops -
<=>- 余弦距离(Cosine Distance),索引参数vector_cosine_ops
根据向量索引类型的不同,在构建的时候可以支持不同的向量索引。
离线批量导入与索引优化实践
在实际业务中,常见的场景是需要离线批量导入大量向量数据。此时,推荐采用如下流程以显著提升数据导入和索引构建的效率:
- 先删除已有索引(DROP INDEX):避免每条数据写入时都实时维护索引,提升导入速度。
- 批量导入数据:使用
COPY或批量INSERT等方式高效导入。 - 执行 VACUUM:导入完成后,执行
VACUUM,整理表空间,提升后续索引构建效率。 - 重建索引(CREATE INDEX):最后统一创建向量索引,此时索引构建速度远高于逐条维护。
这种流程不仅能大幅提升批量导入的速度,还能让索引的构建和后续检索效率更高。适用于数据初始导入、离线数据迁移、周期性全量刷新等场景。
示例流程:
-- 1. 删除已有索引(如有)
DROP INDEX IF EXISTS idx_items_embedding;
-- 2. 批量导入数据
COPY items (embedding) FROM '/path/to/data.csv' WITH (FORMAT csv);
-- 3. 整理表空间
VACUUM items;
-- 4. 创建索引
CREATE INDEX idx_items_embedding ON items USING split_ivfflat (embedding vector_l2_ops) WITH (lists = 100);建议:对于实时写入或小批量数据导入场景,则无需此优化流程,直接维护索引即可。
创建 IVFFlat 聚类索引
参数说明:
- lists: 聚类的中心点个数。lists数值的选择一般规则为:小于100万行时,lists = rows/1000,大于100万行时,lists = sqrt(rows),能获得比较好的聚类效果。
-- 创建欧式距离索引
CREATE INDEX ON items USING split_ivfflat (embedding vector_l2_ops) WITH (lists = 100);
-- 创建内聚距离索引
CREATE INDEX ON items USING split_ivfflat (embedding vector_ip_ops) WITH (lists = 100);
-- 创建余弦距离索引
CREATE INDEX ON items USING split_ivfflat (embedding vector_cosine_ops) WITH (lists = 100);
--导入向量数据
INSERT INTO items (embedding) VALUES ('[1.0,0.0,-1.0]');创建 HNSW 图索引
参数说明(参数之间可以灵活组合):
-
m:节点最大邻居(出度)数量。该参数影响图的召回精度和性能,邻居上限越多,图的连通性会更好,但会影响写入和查询性能,默认值 16。
-
ef_construction:节点候选邻居数量,基于其选择最终的 m 个邻居。该参数影响图的召回精度和性能,候选邻居越多,裁边算法得到合法的邻居数量越多,主要是影响构图性能,默认值 64。
-
quantizer: 用于向量量化的参数,有两个选项,int8 和 fp16,通过将原始浮点向量转换为更紧凑的类型表示,减少类型占用位数来压缩数据,可以显著影响索引的性能和内存使用。使用量化参数适合内存受限的环境,或者数据集太大无法放入内存,或者对精度要求不严格的场景。量化会引入一定的精度损失,量化后的索引查询速度可能比非量化版本稍慢(因为需要解量化)。
-- 创建欧式距离索引
CREATE INDEX ON items USING split_hnsw (embedding vector_l2_ops) WITH (m=16, ef_construction = 64);
-- 创建内聚距离索引
CREATE INDEX ON items USING split_hnsw (embedding vector_ip_ops) WITH (m=16, ef_construction = 64);
-- 创建余弦距离索引
CREATE INDEX ON items USING split_hnsw (embedding vector_cosine_ops) WITH (m=16, ef_construction = 64);
-- 使用 int8 量化参数压缩
CREATE INDEX ON items USING split_hnsw (embedding vector_l2_ops) WITH (quantizer = 'int8');
-- 使用 fp16 量化参数压缩
CREATE INDEX ON items USING split_hnsw (embedding vector_l2_ops) WITH (quantizer = "fp16");
--导入向量数据
INSERT INTO items (embedding) VALUES ('[1.0,0.0,-1.0]');注:如果不配置索引,会使用暴力检索的方式进行向量检索。
向量量化方式的选择
HNSW 索引支持两种向量量化方式,int8 和 fp16。通过以下表格选择合适的方式。
| 特性 | int8 | fp16 |
|---|---|---|
| 原理 | 将原始 float32 向量转换为 8-bit 整数表示 | 将原始 float32 向量转换为 16-bit 浮点表示 |
| 内存减少 | 75% (32→8 bit) | 50% (32→16 bit) |
| 精度损失 | 较大 | 较小 |
| 计算复杂度 | 较高(需量化/反量化) | 低(直接类型转换) |
| 适用场景 | 内存敏感型,可以接受一定精度的损失,大规模数据集 | 精度敏感型,需要较好平衡内存和精度,GPU 支持 fp16 优化 |
查询方式
参数说明:
- ivfflat.probes:设置考察聚类中心点的个数。该值越大,召回率越高,检索性能越差。当该值等于构建index时指定的lists个数是,退化为暴力检索
基于 IVFFlat 索引的查询
-- 全局生效配置
alter system set ivfflat.probes=10;
-- 当前session生效配置,优先级高于全局配置
SET ivfflat.probes = 10;
SELECT *
FROM items
ORDER BY embedding <-> '[3,1,2]'
LIMIT 5;基于 HNSW 索引的查询
参数说明:
- hnsw.ef_search: 控制候选队列的长度。该参数可以控制搜索精度,ef_search 越大,查询过程越难收敛,考察的节点越多,召回精度通常越高。
SET hnsw.ef_search = 100;
SELECT *
FROM items
ORDER BY embedding <-> '[3,1,2]'
LIMIT 5;量化索引查询方式
当使用量化索引(int8 或 fp16)时,查询方式需要使用专门的函数来计算距离,而不是使用操作符:
- l2_distance(vector, vector) - 计算两个向量之间的欧氏距离(L2 Distance)
- inner_product(vector, vector) - 计算两个向量之间的内积距离(Inner Product)
- cosine_distance(vector, vector) - 计算两个向量之间的余弦距离(Cosine Distance)
使用示例:
-- 使用 l2_distance 查询量化索引
SET hnsw.ef_search = 100;
SELECT *
FROM items
ORDER BY l2_distance(embedding, '[3,1,2]')
LIMIT 5;
-- 使用 inner_product 查询量化索引
SELECT *
FROM items
ORDER BY inner_product(embedding, '[3,1,2]')
LIMIT 5;
-- 使用 cosine_distance 查询量化索引
SELECT *
FROM items
ORDER BY cosine_distance(embedding, '[3,1,2]')
LIMIT 5;半径过滤
通过距离阈值过滤向量,支持 L2、内积、余弦三种距离的圆域条件,可直接在 WHERE 子句中使用距离操作符。
-- L2 距离过滤:距离 < 3.0
SELECT *, ROUND((emb <-> '[1,1,1,2]')::numeric, 3)
FROM t
WHERE emb <-> '[1,1,1,2]'::vector < 3.0
ORDER BY emb <-> '[1,1,1,2]' LIMIT 10;
-- 内积过滤:内积 > 30(<#> 返回负内积,所以用 < -30)
SELECT *, emb <#> '[1,1,1,2]' AS dist
FROM t
WHERE emb <#> '[1,1,1,2]'::vector < -30
ORDER BY dist LIMIT 10;
-- 多条件叠加(标量条件 + 距离阈值)
SELECT *, ROUND((emb <-> '[1,1,1,2]')::numeric, 3)
FROM t
WHERE a < 8 AND b > 1
AND emb <-> '[1,1,1,2]'::vector < 7.0
AND emb <-> '[1,1,1,2]'::vector < 3.0
ORDER BY emb <-> '[1,1,1,2]' LIMIT 10;推荐查询(Recommend Query)
通过正例和负例向量定义推荐意图,无需手动构造查询向量。支持三种融合策略。
| 策略 | 原理 |
|---|---|
avg_dist | 正例均值 vs 负例均值的距离(默认) |
best_dist | 最近正例距离与最远负例距离的综合 |
sum_dist | 所有正例距离之和 - 所有负例距离之和 |
基本用法
-- avg_dist 策略(默认):查询向量与正/负例均值的距离
SELECT id, ROUND((emb <#>
'{"positives":[[2,3,4,5],[3,4,5,6]], "negatives":[[5,6,7,8],[6,7,8,9]]}'
::recommend_query)::numeric, 3)
FROM t
ORDER BY emb <#> '{"positives":[[2,3,4,5],[3,4,5,6]], "negatives":[[5,6,7,8],[6,7,8,9]]}'::recommend_query
LIMIT 10;
-- 等价写法(省略 strategy 字段,默认为 avg_dist)
SELECT id, ROUND((emb <=>
'{"positives":[[2,3,4,5],[3,4,5,6]], "negatives":[[5,6,7,8],[6,7,8,9]]}'
::recommend_query)::numeric, 3)
FROM t
ORDER BY emb <=> '{"positives":[[2,3,4,5],[3,4,5,6]], "negatives":[[5,6,7,8],[6,7,8,9]]}'::recommend_query
LIMIT 10;best_dist 策略
取查询向量到最近正例的距离与到最远负例的距离综合评分。
SELECT id, ROUND((emb <#>
'{"positives":[[2,3,4,5],[3,4,5,6]], "negatives":[[5,6,7,8],[6,7,8,9]], "strategy":"best_dist"}'
::recommend_query)::numeric, 3)
FROM t
ORDER BY emb <#> '{"positives":[[2,3,4,5],[3,4,5,6]], "negatives":[[5,6,7,8],[6,7,8,9]], "strategy":"best_dist"}'::recommend_query
LIMIT 10;sum_dist 策略
计算查询向量到所有正例距离之和与到所有负例距离之和的差值。
SELECT id, ROUND((emb <#>
'{"positives":[[2,3,4,5],[3,4,5,6]], "negatives":[[5,6,7,8],[6,7,8,9]], "strategy":"sum_dist"}'
::recommend_query)::numeric, 3)
FROM t
ORDER BY emb <#> '{"positives":[[2,3,4,5],[3,4,5,6]], "negatives":[[5,6,7,8],[6,7,8,9]], "strategy":"sum_dist"}'::recommend_query
LIMIT 10;与标量函数配合
-- inner_product 函数 + recommend_query
SELECT inner_product(
'[1,2,3,4]'::vector,
'{"positives":[[1,2,3,4],[2,3,4,5]], "negatives":[[5,6,7,8],[7,8,9,10]], "strategy":"best_dist"}'
::recommend_query
);
-- cosine_distance 函数 + recommend_query
SELECT cosine_distance(
'[1,2,3,4]'::vector,
'{"positives":[[1,2,3,4],[2,3,4,5]], "negatives":[[5,6,7,8],[7,8,9,10]]}'
::recommend_query
);
-- l2_distance 函数 + recommend_query
SELECT l2_distance(
'[1,2,3,4]'::vector,
'{"positives":[[1,2,3,4],[2,3,4,5]], "negatives":[[5,6,7,8],[7,8,9,10]], "strategy":"best_dist"}'
::recommend_query
);配合 split_hnsw 索引 + 量化器
CREATE TABLE t (id int, emb vector(4)) USING columnar;
INSERT INTO t VALUES (1, '[1,1,1,2]'), (2, '[2,2,2,3]'), (3, '[3,3,3,4]'), (4, '[4,4,4,5]');
CREATE INDEX ON t USING split_hnsw(emb vector_l2_ops) WITH (quantizer='int8');
CREATE INDEX ON t USING split_hnsw(emb vector_cosine_ops) WITH (quantizer='int8');
CREATE INDEX ON t USING split_hnsw(emb vector_ip_ops) WITH (quantizer='int8');
-- 带 quantizer 的推荐查询
SELECT id, ROUND(l2_distance(emb,
'{"positives":[[2,3,4,5],[1,2,3,4]], "negatives":[[1,2,3,4],[1,2,4,3]], "strategy":"best_dist"}'
::recommend_query)::numeric, 3)
FROM t
ORDER BY emb <-> '{"positives":[[2,3,4,5],[1,2,3,4]], "negatives":[[1,2,3,4],[1,2,4,3]], "strategy":"best_dist"}'::recommend_query
LIMIT 10;混合检索(多路召回融合)
对同一行数据的多个向量列分别召回,通过 FULL OUTER JOIN 合并后用融合函数重新排序,适用于语义检索召回质量优化等场景。
表结构和索引
CREATE TABLE t (id int, emb1 vector(4), emb2 vector(4)) USING columnar;
-- emb1 用 L2,emb2 用余弦
CREATE INDEX ON t USING split_hnsw(emb1 vector_l2_ops);
CREATE INDEX ON t USING split_hnsw(emb2 vector_cosine_ops);加权 RRF 融合
WITH
recall1 AS (
SELECT id, emb1 <-> '[0.44, 0.554, 0.34, 0.62]' AS dist1
FROM t ORDER BY dist1 LIMIT 4
),
recall2 AS (
SELECT id, emb2 <=> '[0.44, 0.554, 0.34, 0.62]' AS dist2
FROM t ORDER BY dist2 LIMIT 4
),
rank1 AS (
SELECT *, ROW_NUMBER() OVER (ORDER BY dist1) AS rank1
FROM recall1
),
rank2 AS (
SELECT *, ROW_NUMBER() OVER (ORDER BY dist2) AS rank2
FROM recall2
)
SELECT
COALESCE(rank1.id, rank2.id) AS id,
ROUND(rank1.dist1::numeric, 3),
ROUND(rank2.dist2::numeric, 3),
ROUND((0.7 * rank_score(rank1.rank1) + 0.3 * rank_score(rank2.rank2))::numeric, 3) AS score
FROM rank1 FULL OUTER JOIN rank2 ON rank1.id = rank2.id
ORDER BY score DESC LIMIT 8;距离归一化融合
WITH
recall1 AS (
SELECT id, emb1 <-> '[...]' AS dist1 FROM t ORDER BY dist1 LIMIT 8
),
recall2 AS (
SELECT id, emb2 <=> '[...]' AS dist2 FROM t ORDER BY dist2 LIMIT 8
),
rank1 AS (
SELECT *, ROW_NUMBER() OVER (ORDER BY dist1) AS rank1,
MIN(dist1) OVER () AS min1, MAX(dist1) OVER () AS max1
FROM recall1
),
rank2 AS (
SELECT *, ROW_NUMBER() OVER (ORDER BY dist2) AS rank2,
MIN(dist2) OVER () AS min2, MAX(dist2) OVER () AS max2
FROM recall2
)
SELECT
COALESCE(rank1.id, rank2.id) AS id,
ROUND(rank1.dist1::numeric, 3),
ROUND(rank2.dist2::numeric, 3),
ROUND((
norm_dist_score(rank1.dist1, rank1.min1, rank1.max1) +
norm_dist_score(rank2.dist2, rank2.min2, rank2.max2)
)::numeric, 3) AS score
FROM rank1 FULL OUTER JOIN rank2 ON rank1.id = rank2.id
ORDER BY score DESC LIMIT 8;融合辅助函数
| 函数 | 公式 | 说明 |
|---|---|---|
rank_score(r) | 1 / (r + 60) | RRF 分数,r 为排名 |
norm_score(v, min, max) | (v - min) / (max - min) | 正向归一化 |
norm_dist_score(d, min, max) | (max - d) / (max - min) | 距离反向归一化 |
PQ 量化器
Product Quantization(乘积量化)将向量空间分解为多个子空间分别量化,大幅压缩索引内存占用(可压缩 10-30x),适合大规模数据集。
基本用法
CREATE TABLE t (a int PRIMARY KEY, tag text, embedding vector(4)) USING columnar;
INSERT INTO t VALUES
(1, 'a', '[1.1,1.1,1.1,1.1]'),
(2, 'a', '[1.2,1.2,1.2,1.2]'),
(3, 'b', '[1.3,1.3,1.3,1.3]'),
(4, 'b', '[1.4,1.4,1.4,1.4]'),
(5, 'b', '[1.5,1.5,1.5,1.5]'),
(6, 'c', '[1.6,1.6,1.6,1.6]'),
(7, 'd', '[1.7,1.7,1.7,1.7]'),
(8, 'd', '[1.8,1.8,1.8,1.8]');
-- PQ 量化:pq_num_segments 必须整除向量维度
CREATE INDEX ON t USING split_hnsw(embedding vector_l2_ops)
WITH (quantizer='pq', pq_num_segments=4);
-- 查询照常使用
SELECT * FROM t ORDER BY embedding <-> '[2,2,2,2]' LIMIT 10;pq_num_segments 校验
-- 4 维向量,7 不整除 4 → 报错
CREATE INDEX ON t USING split_hnsw(embedding vector_l2_ops)
WITH (quantizer='pq', pq_num_segments=7);
-- ERROR: invalid value for parameter "pq_num_segments": "7"
-- 4 维向量,segments 可取 1, 2, 4
CREATE INDEX ON t USING split_hnsw(embedding vector_l2_ops)
WITH (quantizer='pq', pq_num_segments=4); -- OK与其他量化器对比
-- fp16:半精度浮点,内存减半,精度损失最小
CREATE INDEX ON t USING split_hnsw(emb vector_l2_ops) WITH (quantizer='fp16');
-- int8:8-bit 标量量化,需 k-means 全局训练
CREATE INDEX ON t USING split_hnsw(emb vector_l2_ops) WITH (quantizer='int8');
-- PQ:乘积量化,压缩率最高,适合高维向量
CREATE INDEX ON t USING split_hnsw(emb vector_l2_ops)
WITH (quantizer='pq', pq_num_segments=4);向量数组(Vector Array)
vector(N)[] 类型支持每行存储多个向量,并提供专用的数组级距离操作符和索引。
建表和插入
CREATE TABLE t (id int PRIMARY KEY, emb vector(4)[]) USING columnar;
INSERT INTO t VALUES
(1, ARRAY['[1, 1, 1, 1]'::vector, '[2, 12, 22, 32]'::vector]),
(2, ARRAY['[3, 3, 3, 3]'::vector, '[4, 14, 24, 34]'::vector]),
(3, ARRAY['[5, 5, 5, 5]'::vector, '[6, 16, 26, 36]'::vector]),
(4, ARRAY['[7, 7, 7, 7]'::vector, '[8, 18, 28, 38]'::vector]),
(5, ARRAY['[9, 9, 9, 9]'::vector, '[10, 10, 20, 30]'::vector]);创建索引
-- 支持三种操作类(不支持 int8 量化器)
CREATE INDEX ON t USING split_hnsw(emb vector_array_l2_ops);
CREATE INDEX ON t USING split_hnsw(emb vector_array_ip_ops);
CREATE INDEX ON t USING split_hnsw(emb vector_array_cosine_ops);数组距离操作符
-- array_l2_distance:数组间 L2 距离
SELECT id, ROUND((emb <->> ARRAY['[1,1,1,1]','[2,2,2,2]'])::numeric, 3)
FROM t ORDER BY emb <->> ARRAY['[1,1,1,1]','[2,2,2,2]'] LIMIT 5;
-- array_cosine_distance:数组间余弦距离
SELECT id, ROUND((emb <=>> ARRAY['[1,1,1,1]','[2,2,2,2]'])::numeric, 3)
FROM t ORDER BY emb <=>> ARRAY['[1,1,1,1]','[2,2,2,2]'] LIMIT 5;
-- array_inner_product:数组间内积(返回负值)
SELECT id, ROUND((emb <#>> ARRAY['[1,1,1,1]','[2,2,2,2]'])::numeric, 3)
FROM t ORDER BY emb <#>> ARRAY['[1,1,1,1]','[2,2,2,2]'] LIMIT 5;标量函数查询
-- 自定义数组顺序计算距离(不使用操作符)
SELECT id, ROUND(array_l2_distance(
ARRAY['[1,2,3,5]','[2,3,4,6]'], emb)::numeric, 3) AS dist
FROM t ORDER BY ARRAY['[1,2,3,5]','[2,3,4,6]'] <->> emb LIMIT 10;
SELECT id, ROUND(array_cosine_distance(
ARRAY['[1,2,3,4]','[2,3,4,5]'], emb)::numeric, 3) AS dist
FROM t ORDER BY ARRAY['[1,2,3,4]','[2,3,4,5]'] <=>> emb LIMIT 10;
SELECT id, ROUND(array_inner_product(
ARRAY['[1,1,1,1]','[2,2,2,2]'], emb)::numeric, 3) AS dist
FROM t ORDER BY ARRAY['[1,1,1,1]','[2,2,2,2]'] <#>> emb LIMIT 10;距离阈值过滤 + 操作符可交换
-- emb <#>> literal 形式
SELECT id, emb <#>> ARRAY['[1,1,1,1]','[2,2,2,2]'] AS dist
FROM t
WHERE emb <#>> ARRAY['[1,1,1,1]','[2,2,2,2]'] < -210
ORDER BY emb <#>> ARRAY['[1,1,1,1]','[2,2,2,2]'] LIMIT 10;
-- literal <#>> emb 形式(等价,操作符可交换)
SELECT id, ARRAY['[1,1,1,1]','[2,2,2,2]'] <#>> emb AS dist
FROM t
WHERE ARRAY['[1,1,1,1]','[2,2,2,2]'] <#>> emb < -210
ORDER BY ARRAY['[1,1,1,1]','[2,2,2,2]'] <#>> emb LIMIT 10;操作符速查
| 操作符 | 函数 | 索引操作类 |
|---|---|---|
<->> | array_l2_distance | vector_array_l2_ops |
<=>> | array_cosine_distance | vector_array_cosine_ops |
<#>> | array_inner_product | vector_array_ip_ops |
注意:当使用量化索引时,必须使用对应的函数进行查询,不能使用 <->、<#>、<=> 操作符。