十、向量数据库

说明:文中所有类名 / 方法名均在本地 spring-ai 1.1.3 的 jar 中核对过。中文文档(1.0 时代示例)里几处旧 API,统一整理在最后的「踩坑清单」。

1. 它是什么

  • 传统关系库:精确匹配 (where id = ?)。

  • 向量库:相似性搜索 ------ 给一个查询向量,返回"相似"的向量(KNN)。

  • 向量库本身不生成向量 ,只负责存储 + 检索。向量由 EmbeddingModel 生成(float[])。

  • 在 RAG 里的位置:

    灌库:文档 → 切分 → EmbeddingModel 向量化 → VectorStore 存储
    提问:问题 → 向量化 → 相似度检索 topK → 检索结果作为上下文拼进提示词 → 大模型回答

2. 核心 API(1.1.3 实测签名)

java 复制代码
// 只读检索(函数式接口,最小权限原则)
@FunctionalInterface
public interface VectorStoreRetriever {
    List<Document> similaritySearch(SearchRequest request);
    default List<Document> similaritySearch(String query) { ... }
}

// 读写
public interface VectorStore extends DocumentWriter, VectorStoreRetriever {
    void add(List<Document> documents);
    void delete(List<String> idList);
    void delete(Filter.Expression filterExpression);
    default void delete(String filterExpression) { ... }   // 字符串 DSL
    default <T> Optional<T> getNativeClient() { ... }      // 拿底层原生客户端
}

Document 常用方法(注意是 getText()):

java 复制代码
doc.getId();
doc.getText();
doc.getMetadata();
doc.getScore();

SearchRequest 默认值:topK = 4、similarityThreshold = 0.0(即 SIMILARITY_THRESHOLD_ACCEPT_ALL,不过滤)。

3. 支持的 19 种实现

Azure / Cassandra / Chroma / Elasticsearch / GemFire / MariaDB / Milvus / MongoDB Atlas / Neo4j / OpenSearch / Oracle / PgVector / Pinecone / Qdrant / Redis / SAP Hana / Typesense / Weaviate,外加 SimpleVectorStore(内存实现,教学用)。

4. 三种接入方式

A. Starter 自动配置(推荐)

xml 复制代码
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-vector-store-milvus</artifactId>
</dependency>
yaml 复制代码
spring:
  ai:
    vectorstore:
      milvus:
        client: { host: localhost, port: 19530 }
        initialize-schema: true     # ⚠ 1.1 起默认 false,需要显式打开
        embedding-dimension: 1536   # 必须和 embedding 模型维度一致

这样才会有 VectorStore bean 可以 @Autowired。

B. 手动配置(不用自动配置)

依赖换成非 starter 的 spring-ai-milvus-store,然后:

java 复制代码
@Bean
public VectorStore vectorStore(MilvusServiceClient client, EmbeddingModel embeddingModel) {
    return MilvusVectorStore.builder(client, embeddingModel)
            .collectionName("test_vector_store")
            .indexType(IndexType.IVF_FLAT)
            .metricType(MetricType.COSINE)
            .batchingStrategy(new TokenCountBatchingStrategy())
            .initializeSchema(true)
            .build();
}

C. SimpleVectorStore(本模块在用)

不会被自动配置,必须自己声明:

java 复制代码
@Bean
public SimpleVectorStore vectorStore(EmbeddingModel embeddingModel) {
    return SimpleVectorStore.builder(embeddingModel).build();
}

内存存储,重启即丢,只适合演示 / 教学。

5. 读写删最小示例

java 复制代码
// 写
vectorStore.add(List.of(new Document("Spring AI rocks", Map.of("country", "BG"))));

// 读(两种方式等价)
List<Document> docs  = retriever.similaritySearch("Spring");
List<Document> docs2 = retriever.similaritySearch(SearchRequest.builder()
        .query("Spring").topK(5).similarityThreshold(0.7).build());

// 删:按 ID / 按过滤表达式 / 按字符串表达式
vectorStore.delete(List.of(doc.getId()));
vectorStore.delete(b.eq("country", "BG").build());
vectorStore.delete("country == 'BG'");

性能:按 ID 删最快;按过滤器删可能扫索引;大批量删除要分批做。

6. 元数据过滤(只作用于 metadata,类似 SQL where)

字符串 DSL:

复制代码
"country == 'BG'"
"genre in ['comedy','drama'] && year >= 2020"

编程式:

java 复制代码
FilterExpressionBuilder b = new FilterExpressionBuilder();
Filter.Expression exp = b.and(b.in("genre", "drama", "documentary"),
                              b.not(b.lt("year", 2020))).build();

运算符:

  • 比较:== != > >= < <=
  • 组合:AND/&&、OR/||
  • 其它:IN、NIN、NOT、IS NULL / IS NOT NULL(并非所有向量库都实现了 NULL 判断)

本项目提醒:KnowledgeBase 的元数据是 source / category,笔记示例里的 type == 'Spring'、genre == 'fairytale' 命中不了,要么改语料,要么改过滤表达式。

7. 批处理策略(大批量灌库必看)

  • 接口:org.springframework.ai.embedding.BatchingStrategy#batch(List<Document>)。
  • 默认实现 TokenCountBatchingStrategy:上限 8191 token、预留 10%,即实际 8191 * 0.9;单文档超限直接抛异常。
  • 覆盖默认:注册一个自己的 bean 即可(自动配置会被替换)。
java 复制代码
@Bean
public BatchingStrategy customBatchingStrategy() {
    return new TokenCountBatchingStrategy(EncodingType.CL100K_BASE, 8000, 0.1);
}
  • 若 embedding 模型支持 autoTruncate(如 Vertex AI),要把批处理上限设成模型实际限制的 5~10 倍,否则批策略先抛异常、模型根本没机会截断。
  • 但静默截断会丢掉长文档尾部信息 → 更推荐灌库前先切分。

8. 读写分离写法(推荐)

灌库服务依赖 VectorStore,检索服务只依赖 VectorStoreRetriever:

java 复制代码
@Service
class DocumentRetriever {
    private final VectorStoreRetriever retriever;

    DocumentRetriever(VectorStoreRetriever retriever) { this.retriever = retriever; }

    List<Document> findSimilar(String query) { return retriever.similaritySearch(query); }
}

好处:最小权限、依赖更少、函数式接口可用 lambda / 方法引用造测试替身。

9. ⚠ 1.1.3 踩坑清单(文档 vs 实际)

文档 / 教程写法 1.1.3 实际
Document::getContent Document::getText(另有 getFormattedContent())
chatModel.generate(prompt) chatModel.call(String)
schema 自动初始化 initialize-schema 默认 false,需显式打开
直接 @Autowired VectorStore 必须有具体 starter 或自己声明 bean;SimpleVectorStore 不自动配置
Document.getScore() 一定有值 存在该 API,但不匹配时为 null,用前先判空

本项目专属坑:DeepSeek 没有 embedding 接口 ,spring.ai.openai.embedding.* 必须另配服务(SiliconFlow / 通义兼容模式 / Ollama),否则 add() 直接 404;且入库与检索必须用同一个 embedding 模型,否则维度不匹配。

java 复制代码
List<Document> docs = new JsonReader(new FileSystemResource(file), "name", "description").get();
vectorStore.add(docs);
相关推荐
Ivanqhz1 小时前
干涉图着色
java·服务器·网络·数据库·人工智能·深度学习
꯭自꯭闭꯭2 小时前
达梦DMDSC主备搭建
linux·服务器·数据库
用户EasyAdminBlazor2 小时前
EasyAdminBlazor 审批并发控制:两个人同时审批为什么只能成功一个?
数据库
杨云龙UP2 小时前
TDengine Community 超级表建表实战:统一21个TAG与DOUBLE/字符串数据模板
运维·服务器·数据库·时序数据库·tdengine·涛思数据·stable建表
katasea3 小时前
第05章:信创技术栈选型:服务器、操作系统、数据库、中间件适配对比
服务器·数据库·中间件
梓沂3 小时前
记一次 Oracle 测试库自动刷新脚本的踩坑实录
数据库·oracle
2501_931803753 小时前
MySQL 索引核心原理
数据库·mysql
浪潮IT馆3 小时前
Windows 10 安装 PostgreSQL 9.6.24 完整教程
数据库·windows·postgresql
Elastic 中国社区官方博客4 小时前
14 个 alerts,1 个 incident:使用 Elasticsearch 中的 ES|QL 衡量 alerting rule 噪声
大数据·运维·数据库·elasticsearch·搜索引擎·全文检索