Spring AI + Redis Vector Store 检索无结果排查实录:一个 TAG 类型导致的坑
前言
最近在做企业知识库问答系统时,采用了 Spring AI + Redis Stack 实现向量检索。
整体架构非常简单:
FAQ
↓
Embedding
↓
Redis Vector Store
↓
Similarity Search
↓
LLM生成答案
本以为是一个非常标准的实现,结果遇到了一个非常诡异的问题:
FAQ已经成功写入Redis,Embedding也生成成功,但向量检索始终返回空结果。
经过几个小时排查,最终发现问题竟然出在一个 Metadata 字段类型上。
本文记录完整排查过程,希望能帮助后来者少踩坑。
问题现象
RedisVectorStore 配置如下:
@Bean
public VectorStore vectorStore(
JedisPooled jedisPooled,
EmbeddingModel embeddingModel) {
return RedisVectorStore.builder(jedisPooled, embeddingModel)
.indexName("faq_index")
.prefix("faq:v2:")
.contentFieldName("answer")
.vectorAlgorithm(RedisVectorStore.Algorithm.HNSW)
.metadataFields(
RedisVectorStore.MetadataField.tag("faqId"),
RedisVectorStore.MetadataField.text("question"),
RedisVectorStore.MetadataField.tag("category")
)
.initializeSchema(true)
.build();
}
FAQ入库代码:
vectorStore.add(List.of(toDocument(faq)));
查询代码:
SearchRequest request = SearchRequest.builder()
.query(query)
.topK(5)
.build();
List<Document> docs =
vectorStore.similaritySearch(request);
结果:
FAQ成功导入
Redis中有数据
向量生成成功
但是:
similaritySearch() 返回 []
第一轮排查:怀疑向量没有写进去
首先查看 Redis 索引。
FT.INFO faq_index
结果:
Number of docs: 0
Number of records: 0
看到这里第一反应:
难道向量根本没写进去?
于是开始检查写入逻辑。
增加日志:
Boolean exists =
jedisPooled.exists("faq:v2:" + faq.getId());
log.info("exists={}", exists);
结果:
exists=true
exists=true
exists=true
...
说明文档确实已经写入Redis。
第二轮排查:验证索引状态
增加校验代码:
var result = jedisPooled.ftSearch(
"faq_index",
"*",
new FTSearchParams().limit(0, 0));
log.info(
"totalResults={}",
result.getTotalResults());
结果:
totalResults=10
进一步查看:
Map<String,Object> info =
jedisPooled.ftInfo("faq_index");
log.info(
"numDocs={}",
info.get("num_docs"));
输出:
numDocs=10
这说明:
- Redis索引正常
- 文档已被索引
- Vector字段存在
问题并不在写入阶段。
第三轮排查:验证Embedding维度
检查Redis中的向量维度:
Map<String,Object> doc =
(Map<String,Object>)
jedisPooled.jsonGet(key);
Object embedding =
doc.get("embedding");
输出:
dim=1024
再查看索引:
VECTOR HNSW FLOAT32 DIM 1024
维度完全一致。
排除维度不匹配问题。
第四轮排查:怀疑相似度阈值
尝试修改查询:
SearchRequest request =
SearchRequest.builder()
.query(query)
.topK(5)
.similarityThreshold(0.0)
.build();
结果:
依然为空
说明并非阈值过滤问题。
最终发现的问题
问题出在 Document Metadata。
最初代码:
private Document toDocument(Faq faq) {
Map<String,Object> metadata =
new HashMap<>();
metadata.put(
"faqId",
faq.getId());
metadata.put(
"question",
faq.getQuestion());
metadata.put(
"category",
faq.getCategory());
return new Document(
String.valueOf(faq.getId()),
faq.getAnswer(),
metadata);
}
注意这里:
metadata.put(
"faqId",
faq.getId());
faqId 是:
Long
而Redis Schema定义的是:
MetadataField.tag("faqId")
即:
faqId TAG
Redis TAG字段的要求
Redis Search中的TAG字段本质上是字符串类型。
正确的数据应该是:
{
"faqId": "1"
}
而不是:
{
"faqId": 1
}
虽然Redis JSON可以存储数字:
{
"faqId": 1
}
但是对于TAG索引字段来说:
TAG → String
TEXT → String
NUMERIC → Number
类型不一致可能导致:
- 索引异常
- 检索异常
- Metadata过滤异常
- Spring AI查询结果为空
修复方案
修改为:
metadata.put(
"faqId",
String.valueOf(faq.getId()));
完整代码:
private Document toDocument(Faq faq) {
Map<String,Object> metadata =
new HashMap<>();
metadata.put(
"faqId",
String.valueOf(faq.getId()));
metadata.put(
"question",
faq.getQuestion());
metadata.put(
"category",
faq.getCategory());
return new Document(
String.valueOf(faq.getId()),
"【" + faq.getQuestion() + "】\n"
+ faq.getAnswer(),
metadata);
}
重新构建索引后:
numDocs=10
totalResults=10
similaritySearch()
返回正常结果
问题解决。
经验总结
在 Spring AI + Redis Vector Store 场景下,Metadata 字段类型必须与 Redis Schema 保持一致。
推荐遵循下面的映射关系:
| Redis类型 | Java类型 |
|---|---|
| TAG | String |
| TEXT | String |
| NUMERIC | Integer / Long / Double |
| VECTOR | float[] |
例如:
MetadataField.tag("faqId")
对应:
metadata.put(
"faqId",
String.valueOf(id));
而不是:
metadata.put(
"faqId",
id);
Spring AI + Redis 排查Checklist
以后遇到检索无结果时,可以按下面顺序排查:
1. 查看索引
FT.INFO faq_index
关注:
num_docs
2. 查看文档
KEYS faq:v2:*
确认数据存在。
3. 查看向量维度
DIM
是否与Embedding模型一致。
4. 查看Metadata类型
确认:
TAG -> String
TEXT -> String
NUMERIC -> Number
5. 降低相似度阈值
.similarityThreshold(0.0)
排除过滤问题。
结语
这次问题最大的特点是:
写入成功、索引成功、Embedding成功,但检索结果为空。
由于错误并不会直接抛出异常,因此排查起来非常耗时。
如果你也在使用 Spring AI + Redis Vector Store,并且遇到“明明有数据却搜不到”的情况,不妨先检查一下 Metadata 字段类型是否与 Redis Schema 完全一致。
有时候,一个 Long 和一个 String 的区别,就足以让整个向量检索失效。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)