1.概述
本文介绍一下如何使用 postgres 作为向量数据库,首先我们需要安装 postgres 数据库,接下来安装 pgvector 扩展支持,关于安装之前有介绍,这里就不再介绍
2.实现步骤
2.1 增加依赖
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-vector-store-pgvector</artifactId>
</dependency>
2.2 增加配置
spring:
ai:
vectorstore:
pgvector:
index-type: HNSW
distance-type: COSINE_DISTANCE
# 维度指定,需要看 向量模型的配置
dimensions: 1024
max-document-batch-size: 10000
initialize-schema: true
datasource:
url: jdbc:postgresql://192.168.2.14:5432/postgres
username: postgres
password: postgres
2.3 启动应用
做好前面两步后,我们可以启动应用,启动应用后,由于我们用的是 initialize-schema: true,所以应用启动后,系统会自动帮我创建好向量数据库的表。
2.4 向量入库测试
编写代码插入向量数据库表
@Autowired
public VectorStore vectorStore;
@GetMapping("/addDoc")
public ResponseEntity <String> addDoc(){
List<Document> documents = List.of(
// 1. 刘备
new Document("10001",
"刘备,字玄德,蜀汉昭烈皇帝。中山靖王刘胜之后,三国时期蜀汉开国皇帝。以仁德著称,三顾茅庐请诸葛亮出山,建立蜀汉政权。",
new HashMap<String, Object>() {{
put("name", "刘备");
put("prop", "仁德治国,三顾茅庐");
}}),
// 2. 诸葛亮
new Document("10002",
"诸葛亮,字孔明,号卧龙,蜀汉丞相。被誉为'智圣',精通兵法、天文、地理。著有《出师表》《诫子书》等,发明木牛流马、孔明灯等。",
new HashMap<String, Object>() {{
put("name", "诸葛亮");
put("prop", "运筹帷幄,发明创造");
}}),
// 3. 曹操
new Document("10003",
"曹操,字孟德,魏武帝。东汉末年杰出政治家、军事家、文学家。统一北方,实行屯田制,著有《观沧海》《短歌行》等诗篇。",
new HashMap<String, Object>() {{
put("name", "曹操");
put("prop", "统一北方,诗词文学");
}}),
// 4. 孙权
new Document("10004",
"孙权,字仲谋,吴大帝。三国时期东吴开国皇帝,继承父兄基业,联合刘备赤壁破曹,善于用人,开发江南。",
new HashMap<String, Object>() {{
put("name", "孙权");
put("prop", "知人善任,开发江南");
}}),
// 5. 张飞
new Document("10005",
"张飞,字翼德,蜀汉车骑将军。勇猛过人,据水断桥喝退曹军,义释严颜,与关羽并称'万人敌'。",
new HashMap<String, Object>() {{
put("name", "张飞");
put("prop", "勇猛过人,万人敌");
}}),
// 6. 吕布
new Document("10006",
"吕布,字奉先,三国第一猛将。手持方天画戟,骑赤兔马,有'人中吕布,马中赤兔'之称。先后认丁原、董卓为义父,后被曹操所杀。",
new HashMap<String, Object>() {{
put("name", "吕布");
put("prop", "武艺第一,三姓家奴");
}}),
// 7. 赵云
new Document("10007",
"赵云,字子龙,蜀汉翊军将军。常山赵子龙,单骑救主,截江夺阿斗,汉水空城计,被刘备称为'一身都是胆'。",
new HashMap<String, Object>() {{
put("name", "赵云");
put("prop", "单骑救主,一身是胆");
}}),
// 8. 司马懿
new Document("10008",
"司马懿,字仲达,晋宣帝。魏国杰出政治家、军事家,多次抵御诸葛亮北伐,最终发动高平陵之变,为西晋奠基人。",
new HashMap<String, Object>() {{
put("name", "司马懿");
put("prop", "老谋深算,篡魏建晋");
}}),
// 9. 周瑜
new Document("10009",
"周瑜,字公瑾,东吴大都督。美姿容,精音律,有'美周郎'之称。赤壁之战中火烧曹操水军,奠定三分天下格局。",
new HashMap<String, Object>() {{
put("name", "周瑜");
put("prop", "精通音律,赤壁破曹");
}}),
// 10. 黄忠
new Document("10010",
"黄忠,字汉升,蜀汉后将军。本为刘表部将,后归刘备。定军山斩夏侯渊,勇冠三军,与关羽、张飞、马超、赵云并称五虎上将。",
new HashMap<String, Object>() {{
put("name", "黄忠");
put("prop", "老当益壮,定军斩将");
}})
);
vectorStore.add(documents);
return ResponseEntity.ok("Added Documents");
}
添加完成后,我们可以查看pg数据库
2.5 查询数据
@GetMapping("/search")
public ResponseEntity <List<Document>> search(@RequestParam("query")String query){
Filter.Expression filterExpression = new Filter.Expression(Filter.ExpressionType.OR,
new Filter.Expression(Filter.ExpressionType.EQ, new Filter.Key("name"),new Filter.Value("刘备")),
new Filter.Expression(Filter.ExpressionType.EQ, new Filter.Key("name"),new Filter.Value("张飞")));
List<Document> results = this.vectorStore.
similaritySearch(SearchRequest.builder()
.filterExpression(filterExpression)
.query(query).topK(2).build());
return ResponseEntity.ok(results);
}
查询数据数据时,我们可以按照 元数据 和 向量查询。
2.6 创建索引
我们如果需要基于metadata 查询,需要创建索引,加快查询
- 不要自动创建数据库表
vectorstore:
pgvector:
# 指定生成的表名
table-name: article
index-type: HNSW
distance-type: COSINE_DISTANCE
dimensions: 1024
max-document-batch-size: 10000
initialize-schema: false
id-type: serial
- 创建数据库表
CREATE TABLE article (
id bigserial PRIMARY KEY,
content text,
# 注意这里时JSONB
metadata jsonb,
# 向量维度需要根据嵌入模型来
embedding vector(1024)
);
在字段上创建索引
CREATE INDEX idx_vector_store_metadata ON article USING GIN (metadata);
# 在某个属性上创建索引
CREATE INDEX idx_vector_store_name ON article USING GIN ((metadata->'name'));