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

来源:这里教程网 时间:2026-03-14 21:46:35 作者:

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

  • 相关推荐