Spring AI × ES:用 kNN 检索做 RAG,统一搜索 + 问答栈是否成立?
问题
一个业务系统通常有两套”检索”:
- 关键词搜索:用户在搜索框输入”Java 教程”,ES 用 BM25 返回最匹配的文档。这是传统搜索。
- 语义检索:用户在 AI 对话里问”怎么学 Java”,RAG 用向量相似度从知识库召回相关内容。这是 AI 搜索。
传统做法是两套栈:ES 做关键词搜索,Milvus/Qdrant 做语义搜索。但 ES 从 8.x 开始原生支持 kNN(k-Nearest Neighbors)向量检索。于是就有一个诱人的想法:能不能只用 ES 一套,同时做关键词搜索和 RAG 语义搜索?
ES 的 kNN 做了什么
ES 8.0 引入了 dense_vector 字段类型 + knn 查询。8.12 后做了性能优化,支持 HNSW 索引。
1 | // mapping 定义 |
关键:同一个文档里,既有 content(全文搜索),又有 content_vector(语义搜索)。一次查询可以同时走两条路。
统一栈的优势
1. 架构简化
少一个向量数据库 = 少一个组件。运维、监控、数据同步管道的复杂度全部降低。
2. 混合检索天然支持
ES 可以做混合检索(Hybrid Search):BM25(关键词匹配)+ kNN(语义匹配),然后通过 RRF(Reciprocal Rank Fusion)融合结果。
这对 RAG 场景非常有价值。纯语义搜索有时会漏掉精确匹配的关键词,混合检索可以弥补。
1 | { |
3. 数据模型一致
MySQL → ES 同步一套数据,同时服务于”用户搜索”和”AI 问答”。不用维护两套向量数据的同步。
统一栈的代价
1. 性能天花板比专用向量库低
ES 的 kNN 是为”搜索场景”设计的,不是为”纯向量检索”设计的。如果你的向量量级在千万级以上、查询模式是纯语义搜索(没有关键词过滤),专用向量库(Milvus/Qdrant)的延迟和吞吐明显更好。
2. 写入压力
每个文档除了存文本,还要存一个 1536 维的向量。如果你每个文档做一次 Embedding 写入,写入量是纯文本搜索的几十倍。而且 ES 里 kNN 索引的构建也需要额外资源。
3. Embedding 成本
每新增/更新一个文档,都需要调用 Embedding 模型生成向量。在 Spring AI 里这不算复杂:
1 | Document doc = new Document("内容...", Map.of("title", "xxx")); |
但如果文档量大、更新频繁,Embedding API 调用会成为新的成本和性能瓶颈。
Spring AI 怎么接
Spring AI 有 ElasticsearchVectorStore:
1 |
|
然后就和用其他 VectorStore 一样的 API。Spring AI 把 ES 当成一个”向量存储”,但实际上 ES 的能力远超向量存储——它可以同时做全文搜索、聚合、过滤。
这种”一个组件、多种用法”是统一栈的核心价值。
什么场景适合统一栈?
| 场景 | 是否适合 ES 统一栈 |
|---|---|
| 内部知识库 RAG(十万级文档) | ✅ 非常适合 |
| 已有 ES 做搜索,加 RAG 能力 | ✅ 零额外组件 |
| 需要混合检索(关键词 + 语义) | ✅ ES 的混合检索最成熟 |
| 千万级以上纯向量检索 | ❌ 专用向量库更好 |
| 毫秒级 P99 延迟要求 | ⚠️ 需要压测验证 |
意味着什么
- 对大多数业务系统来说,ES 统一栈已经足够。 你的搜索量级大概率到不了需要专用向量库的程度。
- 混合检索(Hybrid Search)是 RAG 召回的未来方向。 纯语义不够准,纯关键词不灵活。ES 在这个方向上有天然优势。
- 架构选型要从”我能用什么”变成”我需要什么”。 不要因为看到别人用 Milvus 就跟着用。如果你的搜索已经在 ES 上,先试试 ES 的 kNN 够不够。
一句话:ES 统一关键词搜索 + 语义搜索的栈,在中小规模场景下成立。省一个中间件的价值,远大于”万一将来要换专用向量库”的顾虑。
