2025年5月19日·阅读约1分钟

用于语义搜索:pgvector 与托管向量数据库比较

比较 pgvector 与托管向量数据库用于语义搜索:设置工作、扩展问题、过滤支持,以及在典型应用栈中的适配性。

用于语义搜索:pgvector 与托管向量数据库比较

语义搜索在业务应用中解决了什么问题

语义搜索能帮助用户在没用“正确”关键词时仍然找到合适答案。它不是匹配精确词汇,而是匹配含义。用户输入“重置我的登录”时,仍然应该看到标题为“更改密码并重新登录”的文章,因为意图是一致的。

在业务应用里,关键词搜索很容易失效,因为真实用户表达不一致:他们使用缩写、拼写错误、混淆产品名,或用症状来描述而不是官方术语。在常见问题、工单、政策文档和入职指南中,同一问题常常出现很多不同表述。关键词引擎经常返回无用结果,或是一长串需要用户逐个点开的条目。

嵌入向量通常是构建块。你的应用把每条文档(文章、工单、产品说明)转成一个向量——一长串数字,表示了意义。当用户提问时,你也把问题嵌入为向量,然后寻找最接近的向量。所谓“向量数据库”就是存放这些向量并能快速搜索的地方。

在典型的业务栈中,语义搜索触及四个领域:内容存储(知识库、文档、工单系统)、嵌入流水线(导入与内容变更时的更新)、查询体验(搜索框、推荐答案、客服辅助)、以及护栏(权限与元数据,比如团队、客户、计划与区域)。

对大多数团队来说,“够好”胜过“完美”。实际目标是一次就命中相关结果、响应低于一秒、以及随内容增长费用可预测。这个目标比争论工具更重要。

两种常见选项:pgvector 与托管向量数据库

大多数团队在语义搜索时会在两种模式间抉择:把一切放进 PostgreSQL(使用 pgvector),或在主数据库旁边加一个托管向量数据库。正确选择更取决于你愿意把复杂性放到哪里。

pgvector 是一个 PostgreSQL 扩展,增加了向量类型和索引,让你可以在普通表里存储嵌入,并用 SQL 运行相似度搜索。实际上,你的文档表可能包含文本、元数据(customer_id、status、visibility)以及一个 embedding 列。搜索流程就是“把查询嵌入,然后返回嵌入最接近的行”。

托管向量数据库是一个以嵌入为主的托管服务。它通常提供插入向量与按相似度查询的 API,以及一些你自己原本要搭建的运维特性。

两种方案完成的核心工作相同:把嵌入与 ID 和元数据一起存储,找到与查询最接近的邻居,并返回 top 匹配以供你的应用展示相关项。

关键差别在于“记录系统”放在哪儿。即便你使用托管向量数据库,通常还是会把业务数据(账户、权限、计费、工作流状态、审计日志)保留在 PostgreSQL。向量存储更多地担当检索层,而非运行整个应用。

一种常见架构是:把权威数据保留在 Postgres,根据选型把嵌入存到 Postgres(pgvector)或向量服务,运行相似度搜索拿到匹配 ID,再从 Postgres 拉完整行。

如果你在像 AppMaster 这样的平臺上构建应用,PostgreSQL 已是结构化数据与权限的自然落点。问题在于嵌入搜索是否也该放在那里,还是放到专门服务,同时让 Postgres 保持事实来源。

配置工作量:你真正需要做的事

团队常先按特性选型,却被日常工作惊到。真正的决策点是你想把复杂性放在何处:在现有的 Postgres 设置里,还是在独立服务里。

使用 pgvector 时,你是在为已有的数据库加入向量搜索。设置通常直接,但那仍是数据库工作,而不仅仅是应用代码。

典型的 pgvector 设置包括启用扩展、增加 embedding 列、创建与查询模式匹配的索引(并在以后调优)、决定内容变更时如何更新嵌入、以及编写同时应用常规过滤器的相似度查询。

使用托管向量数据库时,你是在主数据库旁创建一个新系统。这样可能减少 SQL 工作,但会带来更多集成粘合工作。

典型托管设置包括创建索引(维度和距离度量)、把 API key 放到密钥管理里、构建推送嵌入与元数据的导入作业、保持应用记录与向量记录之间稳定的 ID 映射、并锁定网络访问以确保只有后端能查询。

CI/CD 与迁移也不同。pgvector 自然融入你现有的迁移与审查流程。托管服务则把变更分散到代码与管理控制项里,因此你需要对配置变更和重建索引有清晰流程。

所有权通常也随选择而定。pgvector 倾向由应用开发与 PostgreSQL 的拥有者(有时是数据库管理员)共同负责。托管服务往往由平台团队持有,应用开发负责摄取与查询逻辑。这也是为什么此决策既涉及团队结构,也关乎技术。

过滤与权限:成败关键

语义搜索只有在尊重用户可见内容时才有价值。在真实业务应用里,每条记录旁边通常都有元数据:org_id、user_id、role、status(open、closed)和 visibility(public、internal、private)。如果你的搜索层不能干净地对这些元数据做过滤,就会出现令人困惑的结果,甚至数据泄露。

最大的实务差异在于是在向量搜索之前还是之后做过滤。之后再过滤听起来简单(先查全部,然后丢弃不允许的行),但会在两方面失败。第一,最好的匹配可能被移除,留下更差的结果。第二,如果管道任何部分记录、缓存或暴露未过滤的结果,会增加安全风险。

在 pgvector 中,向量与元数据与 PostgreSQL 同处,因此你可以在同一条 SQL 查询里应用权限,让 Postgres 来强制执行。

PostgreSQL:权限与关联查询是内建能力

如果你的应用已使用 Postgres,pgvector 在简单性上往往占优:搜索就只是“又一条查询”。你可以在票务、客户与成员关系间做 JOIN,也可以用 Row Level Security(行级安全)让数据库本身阻断未授权行。

一个常见模式是先用 org 与 status 过滤缩小候选集,然后在剩下的记录上运行向量相似度,同时可混入关键词匹配以处理精确标识符。

托管向量数据库:过滤能力不一,权限多由你承担

多数托管向量数据库支持元数据过滤,但过滤语言可能有限,且不支持 JOIN。你通常需要把元数据在每条向量记录中去中心化,并在应用层重新实现权限检查。

对于业务应用中的混合搜索,通常希望这些能一起工作:硬过滤(org、role、status、visibility)、关键词匹配(发票号等精确项)、向量相似度(语义)、以及排序规则(提升最近或未结事项)。

举例:在 AppMaster 构建的支持门户里,你可以把工单和权限保留在 PostgreSQL,使“客服只能看到自己的组织”成为普通的 WHERE 条件,同时还能获得对工单摘要与回复的语义匹配。

搜索质量与性能基础

拥有你的源码
生成生产就绪的源码:Go、Vue3、Kotlin 和 SwiftUI。
生成代码

搜索质量是相关性(结果是否有用)与速度(是否感觉即时)的组合。无论是 pgvector 还是托管向量数据库,通常都会用近似搜索来在低延迟与更高召回间做权衡。只要用真正查询来衡量,这个折衷对业务应用常是可以接受的。

从高层看,你需要调优三件事:嵌入模型(什么构成“含义”)、索引设置(引擎搜索的深入程度)、以及排序层(在加上过滤、时效或热度信号后如何排序结果)。

在 PostgreSQL 与 pgvector 中,你通常选择像 IVFFlat 或 HNSW 之类的索引。IVFFlat 更快且构建成本更低,但需要调优“list”数量,并且通常希望有足够的数据后才表现出色。HNSW 在低延迟下常能提供更好召回,但占用更多内存且构建时间更长。托管系统也会暴露类似选择,只是名称与默认值不同。

有些策略比人们预期更重要:缓存热门查询、批量化工作(例如预取下一页),以及考虑两阶段流程:先做快速向量搜索,再用业务信号(时效性或客户等级)重排序前 20–100 条。也要注意网络跳数:如果搜索在独立服务,每次查询都是一次额外往返。

衡量质量时,从小而具体开始。收集 20 到 50 个真实用户问题,定义什么算“好”答案,跟踪 top-3 和 top-10 命中率、中位与 p95 延迟、无效结果的比例,以及在应用权限与过滤后质量下降多少。

这就是为什么选择不再是理论问题。最优选项是能在用户接受的延迟内达到你的相关性目标,同时需要的调优是在你能长期维护的范围内。

扩展关注点与持续运维

许多团队选择 pgvector 是因为它把一切放在一个地方:应用数据与嵌入。对于很多业务应用来说,单个 PostgreSQL 节点就够用了,尤其当你只有几十万到几百万以下的向量且搜索并非主流流量驱动时。

当语义搜索成为核心用户动作(在大多数页面、每条工单或聊天中都在触发),或当你存储百万级向量并在高峰时段需要严格响应时间时,通常会遇到瓶颈。

判断单个 Postgres 设置吃紧的常见信号包括:在正常写入活动期间 p95 搜索延迟飙升、不得不在快速索引与可接受写入速度之间权衡、维护任务变成“只能安排在夜间”,以及需要为搜索做与数据库其他负载不同的扩展方案。

使用 pgvector 扩展通常意味着添加查询读副本、分区表、调优索引,并围绕索引构建与存储增长做规划。这是可行的,但会成为持续性的工作。你还面临设计选择,例如把嵌入放在与业务数据相同表中还是分离出来以减少膨胀与锁竞争。

托管向量数据库把很多这些工作交给供应商。它们通常支持独立扩展计算与存储、内建分片与更简单的高可用性。代价是你需要运营两个系统(Postgres 与向量存储)并保持元数据与权限同步。

成本往往比性能更让团队惊讶。主要驱动因素是存储(向量与索引增长很快)、峰值查询量(通常决定账单)、更新频率(重嵌入与 upsert)、以及数据移动(当应用需要大量过滤时的额外调用)。

在 pgvector 与托管服务间抉择时,选择你愿意承受的痛:深入的 Postgres 调优与容量规划,或为更容易扩展付出更高的费用并管理另一个依赖。

安全、合规与可靠性需要问的问题

保持向量最新
在发布、编辑或删除时通过拖拽式业务逻辑重新嵌入向量,保持向量新鲜。
自动化更新

安全细节通常比速度基准更快决定路径。提前问清数据会放在哪儿、谁能看到它、以及故障时如何处理。

从数据驻留与访问开始考虑。嵌入仍能泄露含义,很多团队也会存原始片段用于高亮。明确哪个系统保存原始文本(工单、笔记、文档),哪个只保存嵌入。还要决定公司内部谁可以直接查询存储,以及是否需要在生产与分析访问间做严格隔离。

构建前需确认的控制点

无论选哪种方案,都应问:

  • 数据在静态与传输中如何加密,能否自管密钥?
  • 备份策略是什么,恢复测试频率如何,你需要的恢复时间目标(RTO)是多少?
  • 是否提供读写审计日志,是否能对异常查询量设置告警?
  • 多租户隔离如何强制:独立数据库、独立 schema,还是行级规则?
  • 删除内容的保留策略是什么,包括嵌入与缓存?

多租户隔离是最容易绊倒人的点。如果一个客户绝对不能被另一个客户影响,你需要在每条查询里做好强租户范围控制。用 PostgreSQL 时,这可以通过行级安全和慎重的查询模式在数据库层面强制。用托管向量数据库时,你通常依赖命名空间或集合,再配合应用逻辑。

可靠性与故障模式

为搜索中断做规划。如果向量存储不可用,用户会看到什么?一个安全的默认是回退到关键词搜索,或仅展示最近项,而不是让页面失败。

举例:在用 AppMaster 构建的支持门户里,你可以把工单保留在 PostgreSQL,并把语义搜索当作可选功能。如果嵌入加载失败,门户仍能显示工单列表并允许精确关键词搜索,直到向量服务恢复。

逐步试点:如何低风险选择

快速原型语义搜索
在 AppMaster 中基于 PostgreSQL 数据与权限快速构建真实的语义搜索试点。
开始试点

最稳妥的决策方法是运行一个看起来像真实应用的小型试点,而不是笔记本演示。

先把你要搜索的对象和必须的过滤写清楚。“搜索我们的文档”太模糊。更真实的需求是“搜索帮助文章、工单回复和 PDF 手册,但只显示用户有权查看的项”。权限、租户 ID、语言、产品领域和“仅已发布内容”这些过滤常常决定胜负。

接着选嵌入模型与刷新计划。决定要嵌入的粒度(整篇、分块或混合)以及更新频率(每次编辑、按夜或在发布时)。如果内容频繁变化,衡量重嵌入的痛点比只看查询速度更重要。

然后在后端构建一个薄的搜索 API。保持简单:一个端点接收查询与过滤字段,返回 top 结果并记录发生了什么。如果你用 AppMaster,可以把摄取与更新流程实现为后端服务加业务流程,调用你的嵌入提供者、写入向量与元数据,并强制执行访问规则。

用真实用户与真实任务运行为期两周的试点。用一小组常见问题跟踪“找到答案”的比率与首次有用结果时间,每周回顾坏结果,监控重嵌入量与查询负载,并测试像缺失元数据或陈旧向量这类故障情形。

最后基于证据做决定:如果 pgvector 在可接受的运维工作量下满足质量与过滤需求就继续保留;如果扩展性与可靠性成为主导,则迁移到托管;或者在适合你栈的情况下采用混合方案(PostgreSQL 管理元数据与权限、向量服务做检索)。

常见错误

大多数错误在最初演示通过后出现。快速概念验证看起来很棒,但在加入真实用户、真实数据与真实规则后可能崩溃。

常导致返工的问题包括:

  • 假设向量会处理访问控制。相似度搜索并不知道谁有权限看什么。若应用有角色、团队、租户或私人笔记,搜索仍需严格的权限过滤与测试以防泄露。
  • 信任“感觉不错”的演示。几条手选查询不能作为评估。没有一小套标注问题与预期结果,改动 chunking、嵌入或索引时很难发现回归。
  • 把整篇文档作为单向量嵌入。大页面、工单和 PDF 通常需要分块。没有分块时结果易模糊;没有版本记录时无法追踪向量对应的修订。
  • 忽视更新与删除。真实应用会编辑和移除内容。若不在更新时重新嵌入并在删除时清理向量,你会返回指向缺失或过时文本的结果。
  • 在没把 UX 钉牢之前过度调优性能。团队常在索引设置上耗费大量时间,却跳过元数据过滤、良好摘要与在查询很具体时回退到关键词搜索的基础工作。

一个简单的“上线后第二天”测试能提前发现这些问题:加入一个新权限规则,更新 20 项,删除 5 项,然后用相同的 10 个评测问题再测一次。如果你在像 AppMaster 这样的平臺上构建,应该把这些检查与业务逻辑和数据库模型同步计划,而不是事后补救。

示例场景:支持门户中的语义搜索

正确实现过滤
在以 Postgres 为优先的应用设计中,尽早加入租户与角色过滤。
试用 AppMaster

一家中型 SaaS 公司有一个支持门户,主要内容类型是客户工单和帮助中心文章。他们希望搜索框能理解含义:比如输入“换手机后无法登录”能找到正确的文章和类似的历史工单。

不可妥协的点很实际:每位客户只能看到自己的工单,坐席要按状态(open、pending、solved)过滤,且结果要感觉即时,因为用户在输入时会有即时建议。

选项 A:把 pgvector 放在同一个 PostgreSQL

如果门户已经把工单与文章存放在 PostgreSQL(像在包含 Postgres 的栈或 AppMaster 上构建时常见),加入 pgvector 是一个干净的首选。你把嵌入、元数据与权限放在一个地方,所以“仅显示 customer_123 的工单”就是普通的 WHERE 子句。

当数据集适中(几十万条项)、团队能调优 Postgres 索引与查询计划,并且希望减少移动部件与简化访问控制时,这通常工作得很好。

代价是向量搜索可能与事务性工作争用资源。随着使用增长,你可能需要额外容量、细致索引策略或甚至单独的 Postgres 实例来保护工单写入与 SLA。

选项 B:托管向量数据库做嵌入,PostgreSQL 保存元数据

用托管向量数据库时,你通常在那保存嵌入与 ID,而把“事实来源”(工单状态、customer_id、权限)保留在 PostgreSQL。实践中团队要么先在 Postgres 里过滤出候选 ID 再搜索,要么先查向量再在展示前复核权限。

当增长不确定或团队不想花时间维护性能时,这个选项常常胜出。但权限流程需要认真设计,否则可能跨客户泄露结果。

一个实用的做法是:若现在需要严格过滤且运维更简单,就先用 pgvector;若预计会快速增长、查询量大或不能让搜索拖慢主库,则计划迁移到托管向量数据库。

快速清单与下一步

如果犹豫不决,别再争论特性,列出应用在第一天必须完成的事情。真实需求常在一次小型试点里浮现。

以下问题常比基准测试更快决定胜负:

  • 哪些过滤是不可妥协的(租户、角色、区域、状态、时间范围)?
  • 索引在 6 到 12 个月内会有多大(项数与嵌入体积)?
  • 在峰值时,什么延迟会被用户觉得是即时?
  • 谁负责预算与值班响应?
  • 事实来源应在何处:PostgreSQL 表还是外部索引?

还要为变动做计划。嵌入并非“一次完成”。文本会变、模型会更新、相关性会漂移,直到有人抱怨。提前决定如何处理更新、如何检测漂移,以及你会监控哪些指标(查询延迟、错误率、小型测试集的召回率、以及“无结果”查询)。

如果你想快速在搜索周围构建完整业务应用,AppMaster (appmaster.io) 可能是个务实的选择:它把 PostgreSQL 数据建模、后端逻辑与 Web/移动 UI 集成到一个无代码流程里,并且在核心应用与权限就位后可迭代加入语义搜索。

常见问题

语义搜索与关键词搜索相比到底解决了什么问题?

语义搜索能在用户用词与文档不完全匹配时返回有用结果。它在用户出现拼写、缩写、或用描述性语句(而不是官方术语)表达问题时尤其有用,这在支持门户、内部工具和知识库里很常见。

什么时候 pgvector 是更好的选择?

当你希望系统零散移动更少、部件更少,并且需要基于 SQL 的精细过滤时,选择 pgvector 会更好。对于数据量和流量还处于适中水平的场景,pgvector 往往是较快且安全的路径,因为向量与元数据在同一套 PostgreSQL 查询里。

什么时候应该考虑托管向量数据库?

当你预计向量数量或查询量会快速增长,或希望将扩展性和可用性交给第三方处理时,托管向量数据库是合适的选择。你会用更少的基础设施运维换取额外的集成工作和对权限校验的更细致处理。

什么是嵌入,为什么需要向量存储?

嵌入(embedding)是把文本转成表示含义的数值向量的过程。向量数据库(或 PostgreSQL 中的 pgvector)存储这些向量,并能快速找到与用户查询向量最相近的向量,从而返回“语义上相似”的结果。

在多租户应用中,为什么“先搜索后过滤”是坏主意?

在向量搜索之后再过滤常常会把最匹配的结果去掉,导致用户得到更差的结果或是空页面。它也增加了泄露的风险(例如日志、缓存或调试时暴露未过滤的结果),所以在多租户场景中应尽量尽早应用租户与角色过滤。

pgvector 如何处理权限与访问控制?

在 pgvector 中,你可以在做相似度搜索的同一条 SQL 查询里应用权限、做连接,并启用 Row Level Security(行级安全)。这样更容易保证“永远不展示被禁止的行”,因为 PostgreSQL 在数据所在的位置就会强制执行这些规则。

托管向量数据库中的权限如何工作?

大多数托管向量数据库支持元数据过滤,但通常不支持关系型的 JOIN,过滤语言也可能受限。你常常需要把权限相关的元数据去中心化地放到每条向量记录里,并在应用层做最后的授权检查。

我需要对文档分块,还是可以把整页嵌入为单个向量?

分块(chunking)是把大文档拆成更小片段再做嵌入,通常能提高精确度,因为每个向量代表更集中的语义。短文本可能直接整体嵌入就足够,但对长票据、政策或 PDF,分块并记录版本会更靠谱。

如何处理更新和删除以避免返回过时结果?

从一开始就规划更新策略:对经常改动的内容在发布或编辑时重新嵌入,并在源记录被删除时移除对应向量。如果不这样做,会返回指向已删除或过时文本的陈旧结果。

在 pgvector 和托管服务之间做选择,最安全的方法是什么?

最稳妥的办法是做一个实际的试点:使用真实查询并严格应用过滤,衡量相关性和延迟,并测试缺失元数据或陈旧向量等故障场景。选择能在权限规则下稳定返回良好前 N 条结果、且团队能承受的成本与运维工作量的方案。

容易上手
创造一些 惊人的东西

使用免费计划试用 AppMaster。
准备就绪后,您可以选择合适的订阅。

开始吧