RAG项目学习笔记:用pgvector检索chunk的逻辑详解

发布时间:2026/10/4 4:11:33
RAG项目学习笔记:用pgvector检索chunk的逻辑详解 记录学习RAG项目的过程项目中配置了 Milvus 和 PGVector 两种向量检索的实现。本次来看一下使用pgvector检索chunk时具体的逻辑是怎样的。0. 先看一下项目中代码是怎么写的Override public ListRetrievedChunk retrieveByVector(float[] vector, RetrieveRequest request) { // 设置ef_search提升召回率 // noinspection SqlDialectInspection,SqlNoDataSourceInspection jdbcTemplate.execute(SET hnsw.ef_search 200); String vectorLiteral toVectorLiteral(vector); // noinspection SqlDialectInspection,SqlNoDataSourceInspection return jdbcTemplate.query(SELECT id, content, 1 - (embedding ?::vector) AS score FROM t_knowledge_vector WHERE metadata-collection_name ? ORDER BY embedding ?::vector LIMIT ?, (rs, rowNum) - RetrievedChunk.builder() .id(rs.getString(id)) .text(rs.getString(content)) .score(rs.getFloat(score)) .build(), vectorLiteral, request.getCollectionName(), vectorLiteral, request.getTopK() ); }1. 设置索引参数首先执行了jdbcTemplate.execute(SET hnsw.ef_search 200);解析HNSW 在最底层搜索时不是找到第一个看起来最近的就停而是维护一个候选队列不断尝试邻居直到确认没有更近的为止。问题来了队列太小 → 走两步就停了可能错过真正的最近邻快但不准队列太大 → 要考察的节点多搜得仔细但慢准但慢ef_search就是控制这个队列大小的旋钮。1.1 什么是HNSW索引HNSW 全称是分层可导航小世界图是最主流的索引算法。如果你学习过数据结构图那么就很好理解了。1、分层最底层包含所有向量每上一层包含的向量就越少节点稀疏从而能实现长距离跳跃。类似的思想跳表2、可导航假设向量数据库里有 8 个向量A~H建了 3 层图查询和 Q 最相似的向量。最顶层入口节点 A、B → 计算 A、B 与 Q 的距离B 更近移动到 B下沉到中间层。中间层从 B 出发看 B 的邻居C、D、EE 最近且比 B 更近 → 移动到 E再看 E 的邻居没有比 E 更近的 → 下沉到最底层。最底层含全部 A~H从 E 出发看 E 的邻居H 最近且比 E 更近 → 移动到 H再看 H 的邻居没有比 H 更近的 → H 就是结果。2. 来看执行的SQLSELECT id, content, 1 - (embedding ?::vector) AS score FROM t_knowledge_vector WHERE metadata-collection_name ? ORDER BY embedding ?::vector LIMIT ?逐个解析2.1 : :是什么两个冒号代表强制类型转换也就是把传入的字符串类型的向量数组转换为pgvector的向量类型vector。Q为什么要传入字符串类型A因为JDBC驱动不认识vector类型无法直接将float[]当做参数绑定所以在数据库端做一个类型转换。2.2 是什么在 PostgreSQL 的pgvector扩展中定义了三个常用的距离操作符余弦距离-欧几里得距离#负内积所以embedding ?::vector表示用db中存储的embedding向量和参数传入的向量做余弦距离计算。余弦距离 1 - 余弦相似度取值范围[0,2]0表示方向完全相同距离02表示方向完全相反距离最远。Q为什么要用1-余弦距离A目的是把距离转换成分数1 - 0 1 距离最近分数最高1 - 2 -1 距离最远分数最低这样做语义上更直观score“得分高匹配好”符合直觉。下游排序也方便。2.3 - 是什么where条件中的-写法 PostgreSQL 的 JSON/JSONB 路径操作符用于从 JSON 中按键提取文本值对应的-提取的是JSON 对象顺带一提MySQL 也有同名操作符-但语法不同需要加$符insert into test VALUES(1,{name: 张三, age: 25, hobbies: [读书, 跑步]}) SELECT * from test WHERE info-$.name 张三;

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询