news 2026/4/18 1:44:01

使用 PostgreSQL + pgvector 实现 RAG 向量存储与语义检索(Java 实战)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
使用 PostgreSQL + pgvector 实现 RAG 向量存储与语义检索(Java 实战)

使用 PostgreSQL + pgvector 实现 RAG 向量存储与语义检索(Java 实战)

在 RAG(Retrieval-Augmented Generation)系统中,向量存储与相似度检索是最核心的一环。
本文将使用PostgreSQL + pgvector,结合Java + 阿里百炼 Embedding 模型,实现一个完整、可运行的向量存储与语义检索示例。

本文不仅关注“能跑”,更重点解释为什么这么设计以及RAG 中最容易踩的坑


一、pgvector 是什么?

pgvector是 PostgreSQL 的一个扩展插件,为 PostgreSQL 提供了专门的vector 类型,用于存储高维向量,并支持:

  • 余弦距离(cosine distance)
  • 欧氏距离(L2)
  • 内积(inner product)
  • 向量索引(ivfflat / hnsw)

这使得 PostgreSQL 可以直接作为向量数据库使用,非常适合中小规模 RAG 场景。


二、安装 PostgreSQL 与 pgvector

安装过程不再赘述。

👉 可参考 CSDN 博主进击的女IT的文章:
https://blog.csdn.net/weixin_63908159/article/details/156075242


三、建表与索引设计(非常重要)

1️⃣ 建表语句

CREATETABLEdocument(id BIGSERIALPRIMARYKEY,contentTEXTNOTNULL,embedding vector(1024),create_timeTIMESTAMPDEFAULTnow());

⚠️注意
vector(1024)必须与 Embedding 模型输出的向量维度一致。如果模型输出是 1536 维,这里必须改成vector(1536),否则插入时会报错:expected xxx dimensions

2️⃣ 向量索引(否则数据一多会非常慢)

CREATEINDEXidx_document_embeddingONdocumentUSINGivfflat(embedding vector_cosine_ops)WITH(lists=100);

查询前建议设置:

SETivfflat.probes=10;

四、Java 实体类设计

pgvector在 Java 中无需特殊类型映射,直接使用String承载即可。

@DatapublicclassDocument{privateLongid;privateStringcontent;/** * pgvector 字段 * 使用 String 承载,例如:[0.12,0.34,...] */privateStringembedding;privateLocalDateTimecreateTime;}

五、Embedding 模型配置(阿里百炼)

配置文件 (application.yml):

alibaba:dashscope:key:sk-xxxurl:https://dashscope.aliyuncs.com/compatible-mode/v1/embeddingsmodel:text-embedding-v4

配置类:

@Configuration@ConfigurationProperties(prefix="alibaba.dashscope")@DatapublicclassAlibabaDashscopeConfig{privateStringkey;privateStringurl;privateStringmodel;}

六、文本向量化服务(EmbeddingService)

功能:文本 → 向量 (List<Float>)

@Service@Slf4jpublicclassEmbeddingService{@AutowiredprivateAlibabaDashscopeConfigconfig;publicList<Float>getEmbedding(Stringtext){if(StrUtil.isBlank(text)){returnList.of();}Map<String,Object>body=Map.of("model",config.getModel(),"input",List.of(text));HttpResponseresponse=HttpRequest.post(config.getUrl()).header("Authorization","Bearer "+config.getKey()).header("Content-Type","application/json").body(JSONUtil.toJsonStr(body)).timeout(30000).execute();JSONObjectjson=JSONUtil.parseObj(response.body());JSONArrayembedding=json.getJSONArray("data").getJSONObject(0).getJSONArray("embedding");returnembedding.toList(Float.class);}}

七、向量存储与相似度查询

Mapper

@MapperpublicinterfaceDocumentMapperextendsBaseMapper<Document>{/** * 向量相似度搜索(余弦距离) */@Select(""" SELECT id, content FROM document ORDER BY embedding <=> #{embedding}::vector LIMIT #{limit} """)List<Document>searchByEmbedding(@Param("embedding")Stringembedding,@Param("limit")intlimit);@Insert(""" INSERT INTO document (content, embedding) VALUES (#{content}, #{embedding}::vector) """)voidinsertDocument(@Param("content")Stringcontent,@Param("embedding")Stringembedding);}

Service

@Service@RequiredArgsConstructorpublicclassDocumentService{privatefinalDocumentMappermapper;privatefinalEmbeddingServiceembeddingService;publicvoidaddDocument(Stringcontent){List<Float>vector=embeddingService.getEmbedding(content);StringpgVector=vector.stream().map(String::valueOf).collect(Collectors.joining(",","[","]"));mapper.insertDocument(content,pgVector);}publicList<Document>search(Stringquery,inttopK){List<Float>vector=embeddingService.getEmbedding(query);if(vector.isEmpty()){returnList.of();}StringpgVector=vector.stream().map(String::valueOf).collect(Collectors.joining(",","[","]"));returnmapper.searchByEmbedding(pgVector,topK);}}

八、Controller 接口

@RestController@RequestMapping("/document")@RequiredArgsConstructorpublicclassDocumentController{privatefinalDocumentServiceservice;@GetMapping("/add")publicvoidadd(@RequestParamStringcontent){service.addDocument(content);}@GetMapping("/search")publicList<Document>search(@RequestParamStringquery,@RequestParam(defaultValue="5")inttopK){returnservice.search(query,topK);}}

九、为什么“最近流行什么”查询不到结果?

这是语义检索中最容易被误解的一点:

向量检索 ≠ 关键词匹配

向量检索判断的是语义是否在同一语义空间

示例:

文本语义中心
Java 是一门流行的后端开发语言编程 / 后端
最近流行什么趋势 / 热点

👉 两者在语义空间中的距离很远,因此检索不到是正常且正确的行为。

正确做法:

  1. Query Rewrite(查询重写)
  2. 补充领域上下文

例如:

最近流行的后端开发语言有哪些?


十、总结

  • pgvector可以让 PostgreSQL 直接作为向量数据库使用。
  • 向量检索本质是语义相似度计算
  • RAG 的效果高度依赖于:
    • 文档内容的表达方式
    • Query 是否足够具体
    • 相似度阈值与 TopK 的设计

📌项目完整源码地址(Gitee)
https://gitee.com/tfxing12138/rag-demo.git

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/9 17:57:24

Thymopoietin II Fragment (29-41) ;GEQRKDVYVELYL

一、基础理化性质 英文名称 &#xff1a;Thymopoietin II Fragment (29-41)三字母序列&#xff1a;Gly-Glu-Gln-Arg-Lys-Asp-Val-Tyr-Val-Glu-Leu-Tyr-Leu-OH单字母序列&#xff1a;GEQRKDVYVELYL精确分子量&#xff1a;1611.82 Da等电点&#xff08;pI&#xff09;&#xff1…

作者头像 李华
网站建设 2026/3/18 4:09:10

如何写出一个完整的测试用例?

&#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快测试用例是为了验证软件功能或需求而设计的一组测试输入、执行条件和预期结果。编写测试用例的目的是确保测试过程全面高效、有据可查。一般来说&#xff0c;编写测…

作者头像 李华
网站建设 2026/4/17 12:57:29

功能测试的测试工作流程

&#x1f345; 点击文末小卡片 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 按照产出的文档&#xff0c;介绍项目开发过程中的工作步骤 一、测试计划&#xff1a;这个计划&#xff0c;我个人觉得应该在详细设计确定后&#xff0c;代码开始…

作者头像 李华
网站建设 2026/4/14 0:10:42

Postman 怎么测接口?新手教程

在当前&#xff0c;API&#xff08;应用程序接口&#xff09;的使用变得越来越普遍。其中&#xff0c;HTTP/HTTPS API 是最常见的一种。无论是开发前端还是后端&#xff0c;测试 API 都是一个关键环节。Postman 是一种流行且强大的 API 测试工具&#xff0c;能够帮助开发人员轻…

作者头像 李华
网站建设 2026/4/3 4:31:19

计算机毕业设计之jsp基于SSM的社区志愿者服务管理系统

社区志愿者服务管理系统的目的是让使用者可以更方便的将人、设备和场景更立体的连接在一起。能让用户以更科幻的方式使用产品&#xff0c;体验高科技时代带给人们的方便&#xff0c;同时也能让用户体会到与以往常规产品不同的体验风格。与安卓&#xff0c;iOS相比较起来&#x…

作者头像 李华
网站建设 2026/4/10 9:45:39

文章跨境版权保护难题多?可信时间戳全流程解决方案来救场!

随着全球文化交流日益频繁&#xff0c;文章跨境传播已成为常态。据《中国网络文学国际传播报告&#xff08;2025&#xff09;》显示&#xff0c;中国网络文学海外活跃用户已达2亿人&#xff0c;覆盖全球200多个国家和地区。然而&#xff0c;跨境传播带来的版权保护问题也日益凸…

作者头像 李华