暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

【PGCCC】pgvector 0.8.0 发布并可在 Nile 上使用

pgvector 社区发布了备受期待的 0.8.0 版本,该版本在性能和功能方面均有显著改进。我们当然迫不及待地想将它提供给 Nile 用户。

发布亮点

根据官方发布说明,pgvector 0.8.0 包括:

  • 增加了对迭代索引扫描的支持
  • 为 sparsevec 添加了数组强制类型转换
  • 改进成本估算,以便在过滤时更好地选择索引
  • 改进了 HNSW 索引扫描的性能
  • 改进了 HNSW 插入和磁盘索引构建的性能
  • 不再支持 Postgres 12

最令人期待的功能是迭代索引扫描,它解决了向量索引长期以来的挑战。以前,过滤器是在索引扫描完成后应用的,这通常会产生比预期更少的结果。根据 pgvector 文档:

对于近似索引,在扫描索引后应用过滤。如果条件匹配 10% 的行,则使用 HNSW 和默认的 hnsw.ef_search 40,平均只有 4 行匹配。

常见的解决方法包括扫描更多行、使用部分索引或分区,但这些方法可能不切实际或不受欢迎。新的迭代扫描功能提供了更直接、更直观的解决方案:

  1. 扫描向量索引
  2. 应用过滤器
  3. 检查是否返回了足够的结果。如果没有,请重复扫描。

让我们用一个很小的例子来看一下它的实际效果。我强烈建议进行一些小实验——即使实际结果不符合你的预期,你也能学到很多东西。请继续学习重要的 pgvector 课程:

首先,我创建一个包含示例数据的表:

CREATE TABLE filtest(id INTEGER, category INTEGER, embedding vector(3));
INSERT INTO filtest VALUES
    (1, 1, '[3, 1, -2]'),
    (2, 1, '[3, 1, -2]'),
    (3, 1, '[3, 1, -2]'),
    (1, 2, '[1.1, 2.2, 3.3]'),
    (2, 2, '[1.1, 2.2, 3.3]'),
    (3, 2, '[1.1, 2.2, 3.3]');
CREATE INDEX ON filtest USING hnsw (embedding vector_cosine_ops);
复制


该表包含六行,分为两类。第 2 类中的向量非常相似[1, 2, 3],而第 1 类中的向量则有很大差异,表示正交(不相关)数据。在实际用例中,类别可以是不同的公司(租户)、同一公司内的不同部门、类型(如果表存储有关电影的信息)等。您可能想要用于过滤的任何内容。

您希望以下查询返回什么?

SELECT id, category, embedding<=>'[1,2,3]'  AS distance
FROM filtest WHERE category=1
ORDER BY distance LIMIT 3;
复制


pgvector 0.7.4 中的索引扫描

我从类别 1 中搜索了最接近的 3 个向量[1,2,3],因此正确的答案是返回类别 1 中的所有向量。但是,这是我期望 pgvector 0.7.4 执行的操作:

  1. 扫描向量索引并找到最接近的3个向量[1,2,3],其中一些应该属于类别2。
  2. 过滤结果并仅保留类别 1 的向量。
  3. 返回部分结果。

然而,在实践中:

SELECT extversion FROM pg_extension WHERE extname = 'vector';
 extversion
------------
 0.7.4
(1 row)

SELECT id, category, embedding<=>'[1,2,3]'  AS distance
FROM filtest WHERE category=1 ORDER BY distance LIMIT 3;
 id | category |      distance
----+----------+--------------------
  3 |        1 | 1.0714285714285714
  1 |        1 | 1.0714285714285714
  2 |        1 | 1.0714285714285714
复制


为什么我们看到正确的结果?因为 pgvector 默认配置的向量索引中要扫描的行数为 40。因此索引扫描返回了整个表,经过筛选后,我们得到了正确的结果。这就是小示例的问题所在……如果我尝试使用 100 个向量,它会像预期的那样错过一些结果。

让我们尝试调整配置:

SET hnsw.ef_search = 3;
SET

SELECT id, category, embedding<=>'[1,2,3]'  AS distance
FROM filtest WHERE category=1 ORDER BY distance LIMIT 3;
 id | category |      distance
----+----------+--------------------
  3 |        1 | 1.0714285714285714
  2 |        1 | 1.0714285714285714
(2 rows)
复制


这是我所期望的部分结果!

pgvector 0.8.0 中的迭代索引扫描

现在让我们看看相同的查询在 pgvector 0.8.0 中的行为:

SELECT extversion FROM pg_extension WHERE extname = 'vector';
 extversion
------------
 0.8.0

SET hnsw.ef_search = 3;
SET

SELECT id, category, embedding<=>'[1,2,3]'  AS distance
FROM filtest WHERE category=1 ORDER BY distance LIMIT 3;
 id | category |      distance
----+----------+--------------------
  1 |        1 | 1.0714285714285714
  2 |        1 | 1.0714285714285714
  3 |        1 | 1.0714285714285714
(3 rows)
复制


太棒了!pgvector 0.8.0 交付了!是的,但不是你想的那样:

SHOW hnsw.iterative_scan;
 hnsw.iterative_scan
---------------------
 off
(1 row)
复制


哎呀!hnsw.iterative_scan已禁用。那么它怎么还能工作呢?使用explain显示未使用索引:

EXPLAIN SELECT id, category, embedding<=>'[1,2,3]' AS distance
FROM filtest WHERE category=1 ORDER BY distance LIMIT 3;
                             QUERY PLAN
---------------------------------------------------------------------
 Limit  (cost=25.09..25.10 rows=3 width=16)
   ->  Sort  (cost=25.09..25.11 rows=6 width=16)
         Sort Key: ((embedding <=> '[1,2,3]'::vector))
         ->  Seq Scan on filtest  (cost=0.00..25.02 rows=6 width=16)
               Filter: (category = 1)
(5 rows)
复制


这是由于 pgvector 0.8.0 中的不同改进造成的:

改进成本估算,以便在过滤时更好地选择索引

在扫描 6 行表时使用向量索引确实很愚蠢。因此,随着成本估算的改进,这种情况不再发生。这是个好消息,但我真的想检查迭代扫描。因此,让我们强制使用索引并重试:

SET enable_seqscan=false; -- force use of index, don't do this in production!
SET

SELECT id, category, embedding<=>'[1,2,3]'  AS distance
FROM filtest WHERE category=1 ORDER BY distance LIMIT 3;
 id | category |      distance
----+----------+--------------------
  2 |        1 | 1.0714285714285714
  3 |        1 | 1.0714285714285714
(2 rows)

SET hnsw.iterative_scan = relaxed_order; -- enable iterative scan
SET

SELECT id, category, embedding<=>'[1,2,3]'  AS distance
FROM filtest WHERE category=1 ORDER BY distance LIMIT 3;
 id | category |      distance
----+----------+--------------------
  2 |        1 | 1.0714285714285714
  3 |        1 | 1.0714285714285714
  1 |        1 | 1.0714285714285714
(3 rows)
复制


我们可以看到 pgvector 0.8.0 和迭代扫描按预期工作。作为额外收获,我们还看到了成本优化的实际应用,并了解了hnsw.ef_search查询配置。最后一条提示:在生产使用中,您可能需要在用于过滤的列上建立索引,而不仅仅是向量索引。

如果您是 Nile 用户,您已经拥有 pgvector 0.8.0,因此我建议您充分利用它。请前往我们的文档, 详细了解 iterative_scan 选项和花哨的优化。

#PG证书#PG考试#postgresql培训#postgresql考试#postgresql认证
原文链接:https://www.thenile.dev/blog/pgvector-080
作者:Gwen Shapira

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论