我在 postgres 中有一个如下表:
create table posts (
id bigserial,
tags text[],
content text,
content_embedding vector(512)
);
create index on posts using GIN(tags);
-- from pgvector
create index ON posts USING hnsw(content_embedding vector_cosine_ops) WITH (m = 24, ef_construction = 100);
每行基本上都是博客中的一篇文章content
,存储其文本,标签是标签数组(例如'{"database","coding"}'
),content_embedding
是我存储content
用某些人工智能模型生成的向量表示的位置,我希望将其用于语义搜索。
我想运行如下查询来获取tags
包含database
or的帖子hobby
,并根据它们与给定向量的“相似程度”对它们进行排序('[...]'
为了简洁起见,如下):
select id, (content_embedding <=> '[...]') as cosine_similarity from posts where tags && '{"database","hobby"}' ORDER BY cosine_distance ASC
但是,查询计划似乎没有像explain analyze
我希望的那样使用向量索引
Sort (cost=8081.77..8089.15 rows=2952 width=16) (actual time=10.444..10.445 rows=20 loops=1)
Sort Key: ((content_embedding <=> '[...]'::vector))
Sort Method: quicksort Memory: 26kB
-> Bitmap Heap Scan on posts (cost=1698.88..7911.62 rows=2952 width=16) (actual time=9.966..10.424 rows=20 loops=1)
Recheck Cond: (tags && '{database,hobby}'::text[])
Heap Blocks: exact=19
-> Bitmap Index Scan on posts_tags_idx (cost=0.00..1698.14 rows=2952 width=0) (actual time=9.842..9.842 rows=20 loops=1)
Index Cond: (tags && '{database,hobby}'::text[])
Planning Time: 0.536 ms
Execution Time: 10.496 ms
当我删除该where
子句时,我确实看到索引扫描用于排序
Index Scan using posts_content_embedding_idx on posts (cost=164.90..41510.78 rows=301590 width=16)
Order By: (content_embedding <=> '[...]'::vector)
我有大约 300000 行posts
。这是一个因素吗?postgres 有没有办法同时使用 gin 和 hnsw 索引?如果不能,那么在我的查询花费太长时间(>100ms)之前限制有多少行?
我知道有针对这种搜索用例构建的解决方案,例如 Elasticsearch 或矢量数据库,但我已经有了一个 postgres 数据库,我希望能够尽可能地扩展它。
PostgreSQL 没有机制来组合这些类型的索引使用。多列 GiST 索引可以在内部完成,但我不知道是否
hnsw
可以支持类似的东西,我对此表示怀疑。(当 GiST 这样做时,它似乎效率不高)当然,您比我们更有资格回答这个问题。您已经拥有数据和系统,只需选择最常见的标签,看看会发生什么。