DiskANN 是一种可扩展的最近的邻域搜索算法,可给出近似的结果,适用于任意规模的高效矢量搜索。 这一算法能够做到高召回率、每秒高查询和低查询延迟,甚至适用于包含数十亿项目的数据集。 这些特征使其成为处理大量数据的强大工具。
若要了解有关 DiskANN 的详细信息,请参阅 DiskANN:针对 Web 规模搜索和建议的矢量搜索。
该 pg_diskann
扩展增加了对使用 DiskANN 进行高效矢量索引和搜索的支持。
启用pg_diskann
若要在 pg_diskann
Azure Database for PostgreSQL 灵活服务器实例上使用扩展,需要在实例级别 允许该扩展 。 然后,需要在要使用扩展提供的功能的每个数据库 上创建扩展 。
重要
此预览功能仅适用于新部署的 Azure Database for PostgreSQL 灵活服务器实例。
由于pg_diskann
依赖于vector
扩展,您可以在同一数据库中允许并创建vector
扩展,然后运行以下命令:
CREATE EXTENSION IF NOT EXISTS pg_diskann;
或者可以跳过显式允许和创建 vector
扩展,并运行之前的命令,附加 CASCADE
子句。 该子句使 PostgreSQL 在它所依赖的扩展上隐式执行 CREATE EXTENSION。 为此,请运行以下命令:
CREATE EXTENSION IF NOT EXISTS pg_diskann CASCADE;
若要从当前连接的数据库中删除扩展,请运行以下命令:
DROP EXTENSION IF EXISTS pg_diskann;
使用 diskann 索引访问方法
安装扩展后,可以在包含矢量数据的表列上创建 diskann
索引。 例如,若要在 embedding
表的 demo
列上创建索引,请使用以下命令:
CREATE TABLE demo (
id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
embedding public.vector(3)
-- other columns
);
-- insert dummy data
INSERT INTO demo (embedding) VALUES
('[1.0, 2.0, 3.0]'),
('[4.0, 5.0, 6.0]'),
('[7.0, 8.0, 9.0]');
-- create a diskann index by using Cosine distance operator
CREATE INDEX demo_embedding_diskann_idx ON demo USING diskann (embedding vector_cosine_ops)
创建索引后,可以运行查询来查找最近的邻居。
以下查询查找向量 [2.0, 3.0, 4.0]
最近的 5 个邻居:
SELECT id, embedding
FROM demo
ORDER BY embedding <=> '[2.0, 3.0, 4.0]'
LIMIT 5;
Postgres 会自动决定何时使用 DiskANN 索引。 如果它选择不在你希望使用索引的情况下使用索引,请执行以下命令:
-- Explicit Transcation block to force use for DiskANN index.
BEGIN;
SET LOCAL enable_seqscan TO OFF;
-- Similarity search queries
COMMIT;
重要
将 enable_seqscan
设置为关闭,如果还有其他方法可用,则它不鼓励规划器使用查询规划器的顺序扫描计划。 由于该命令已禁用 SET LOCAL
,因此该设置仅对当前事务生效。 COMMIT 或 ROLLBACK 之后,会话级别设置将再次生效。 请注意,如果查询涉及其他表,该设置也会阻止在所有表中使用顺序扫描。
使用量化高效缩放(预览版)
DiskANN 使用产品量化(PQ)大幅减少矢量的内存占用。 与其他量化技术不同,PQ 算法可以更有效地压缩矢量,显著提高性能。 使用 PQ 的 DiskANN 可以保留更多内存中的数据,减少访问速度较慢的存储的需求,以及在比较压缩矢量时使用更少的计算。 使用大量数据> (100 万行)时,这会产生更好的性能和显著的成本节省
若要获取产品量化(PQ)功能的访问权限, 请注册预览版
加快索引生成
建议通过几种方法来改进索引生成时间。
使用更多内存
若要加快索引的创建速度,可以增加在 Postgres 实例上为索引生成分配的内存。 可以通过参数指定 maintenance_work_mem
内存使用情况。
-- Set the parameters
SET maintenance_work_mem = '8GB'; -- Depending on your resources
然后, CREATE INDEX
命令根据可用资源使用指定的工作内存来生成索引。
CREATE INDEX demo_embedding_diskann_idx ON demo USING diskann (embedding vector_cosine_ops)
小提示
可以在索引生成期间纵向扩展内存资源以提高索引编制速度,然后在索引完成时缩减。
使用并行化
若要加快索引的创建速度,可以使用并行工作线程。 创建表时,可以通过 parallel_workers
语句的 CREATE TABLE
存储参数指定工作器的数量。 稍后可以使用 SET
语句的 ALTER TABLE
子句对其进行调整。
CREATE TABLE demo (
id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
embedding public.vector(3)
) WITH (parallel_workers = 4);
ALTER TABLE demo SET (parallel_workers = 8);
然后, CREATE INDEX
命令使用指定的并行辅助角色数(具体取决于可用资源)来生成索引。
CREATE INDEX demo_embedding_diskann_idx ON demo USING diskann (embedding vector_cosine_ops)
重要
领导进程不能参与并行索引生成。
如果要使用并行辅助角色创建索引,则还需要相应地设置max_parallel_workers
和max_worker_processes
max_parallel_maintenance_workers
参数。 有关这些参数的详细信息,请参阅 控制资源使用情况和异步行为的参数。
可以在不同的粒度级别设置这些参数。 例如,若要在会话级别设置它们,可以运行以下语句:
-- Set the parameters
SET max_parallel_workers = 8;
SET max_worker_processes = 8; -- Note: Requires server restart
SET max_parallel_maintenance_workers = 4;
若要了解在 Azure Database for PostgreSQL 灵活服务器中配置这些参数的其他选项,请参阅 “配置服务器参数”。
注意
max_worker_processes参数要求服务器重启才能生效。
如果这些参数的配置和服务器上的可用资源不允许启动并行工作器,PostgreSQL 会自动回退以在非parallel 模式下创建索引。
配置参数
创建 diskann
索引时,可以指定各种参数来控制其行为。
索引参数
max_neighbors
:图形中每个节点的最大边缘数(默认值为 32)。 较高的值可以提高召回率,达到特定点。l_value_ib
:索引生成期间搜索列表的大小(默认值为 100)。 较高的值会使生成速度变慢,但索引质量会更高。product_quantized
:启用产品量化(默认值为 true)。pq_param_num_chunks
:产品量化的区块数(默认值为 0)。 0 表示它根据嵌入维度自动确定。 建议使用原始嵌入维度的 1/3。pq_param_training_samples
:用于训练 PQ 中心表的矢量数(默认值为 0)。 0 表示它根据表大小自动确定。
CREATE INDEX demo_embedding_diskann_custom_idx ON demo USING diskann (embedding vector_cosine_ops)
WITH (
max_neighbors = 48,
l_value_ib = 100
product_quantized=true,
pq_param_num_chunks = 0,
pq_param_training_samples = 0
);
扩展参数
diskann.iterative_search
:控制搜索行为。diskann.iterative_search
的配置:relaxed_order
(默认值):让 diskann 以迭代方式按批diskann.l_value_is
搜索图形,直到生成所需的元组数(可能受LIMIT
子句限制)。 可能导致结果无序。strict_order
:类似于relaxed_order
,让 diskann 以迭代方式搜索图形,直到生成所需的元组数。 但是,它可确保按距离排序的严格顺序返回结果。off
:使用非迭代搜索功能,这意味着它在一个步骤中尝试提取diskann.l_value_is
元组。 无论与查询匹配的diskann.l_value_is
子句或元组数如何,非迭代搜索只能为查询返回最多LIMIT
个矢量。
若要将搜索行为
strict_order
更改为当前会话中执行的所有查询,请运行以下语句:SET diskann.iterative_search TO 'strict_order';
若要更改它,使其仅影响当前事务中执行的所有查询,请运行以下语句:
BEGIN; SET LOCAL diskann.iterative_search TO 'strict_order'; -- All your queries COMMIT;
diskann.l_value_is
:用于索引扫描的 L 值(默认值为 100)。 增加该值可提高召回率,但可能会降低查询速度。若要将索引扫描的 L 值更改为 20,对于当前会话中执行的所有查询,请运行以下语句:
SET diskann.l_value_is TO 20;
若要更改它,使其仅影响当前事务中执行的所有查询,请运行以下语句:
BEGIN; SET LOCAL diskann.l_value_is TO 20; -- All your queries COMMIT;
建议的参数配置
数据集大小(行) | 参数类型 | 名字 | 建议的值 |
---|---|---|---|
<1百万 | 索引生成 | l_value_ib |
100 |
<1百万 | 索引生成 | max_neighbors |
32 |
<1百万 | 查询时间 | diskann.l_value_is |
100 |
1M-50M | 索引生成 | l_value_ib |
100 |
1M-50M | 索引生成 | max_neighbors |
64 |
1M-50M | 索引生成 | product_quantized |
是 |
1M-50M | 查询时间 | diskann.l_value_is |
100 |
>50M | 索引生成 | l_value_ib |
100 |
>50M | 索引生成 | max_neighbors |
96 |
>50M | 索引生成 | product_quantized |
是 |
>50M | 查询时间 | diskann.l_value_is |
100 |
注意
这些参数可能因特定数据集和用例而异。 用户可能必须尝试不同的参数值,才能找到其特定方案的最佳设置。
CREATE INDEX 和 REINDEX 进度
使用 PostgreSQL 12 及更高版本,您可以利用 pg_stat_progress_create_index
来检查 CREATE INDEX 或 REINDEX 操作的进度。
SELECT phase, round(100.0 * blocks_done / nullif(blocks_total, 0), 1) AS "%" FROM pg_stat_progress_create_index;
若要详细了解 CREATE INDEX 或 REINDEX 作业可能涉及的阶段,请参阅 CREATE INDEX 阶段。
选择索引访问函数
矢量类型允许对存储的向量执行三种类型的搜索。 需要为索引选择正确的访问函数,以便数据库在执行查询时可以考虑索引。
pg_diskann
支持以下距离运算符
vector_l2_ops
:<->
欧几里得距离vector_cosine_ops
:<=>
余弦距离vector_ip_ops
:<#>
内部产品
故障排除
错误: : diskann index needs to be upgraded to version 2...
遇到此错误时,可以通过以下方法解决:
在索引上执行
REINDEX
或REDINDEX CONCURRENTLY
语句。由于
REINDEX
可能需要很长时间,因此该扩展还提供一upgrade_diskann_index()
个名为的用户定义函数,该函数可尽可能更快地升级索引。若要升级索引,请运行以下语句:
SELECT upgrade_diskann_index('demo_embedding_diskann_custom_idx');
若要将数据库中的所有 diskann 索引升级到当前版本,请运行以下语句:
SELECT upgrade_diskann_index(pg_class.oid) FROM pg_class JOIN pg_am ON (pg_class.relam = pg_am.oid) WHERE pg_am.amname = 'diskann';