现场是这样的。Qdrant 1.9 用 docker 起单节点,collection 里 12 万条向量,按 source=manual 过滤检索时接口回 400,原文 Bad request: Index required but not found for 'source' in the payload,重建 collection 再导入一遍仍然一样。

中间走过弯路,把「字段是嵌套结构,索引建的路径和 filter 里的 key 不一致」当成主因,改完现象没变。

把日志和配置对完,能解释这个现象的基本就这几处。payload 索引没建,Qdrant 对带 filter 的字段要求先 create_payload_index;索引建在别的 collection 或别名上,实际查询打的是另一个集合;批量导入时关掉了索引,导入完成后忘了补建。

先看集合里到底有哪些 payload 索引

curl -s http://127.0.0.1:6333/collections/docs | jq '.result.payload_schema'

给 source 字段补一个 keyword 索引

curl -X PUT http://127.0.0.1:6333/collections/docs/index -H "Content-Type: application/json" -d '{"field_name":"source","field_schema":"keyword"}'

带上同样的 filter 重跑查询

curl -X POST http://127.0.0.1:6333/collections/docs/points/search -H "Content-Type: application/json" -d '{"vector":[0.1,0.2],"filter":{"must":[{"key":"source","match":{"value":"manual"}}]},"limit":5}'

末了确认索引状态和点位数量对得上

curl -s http://127.0.0.1:6333/collections/docs | jq '.result.payload_schema.source, .result.points_count'

这类改动我都写进变更记录,过两周再出问题时能对上号。

别只看报错消失,验证要多做一步。同样 filter 的查询返回 200,hits 里每条 payload.source 都是 manual,payload_schema 中 source 的类型为 keyword,点位数量与导入量一致。

带 filter 的向量检索必须在过滤字段上建索引,Qdrant 不会自动补,导入前建好比事后重建省时间。监控比日志更早给出信号,事后回看经常能提前半小时发现异常。

作者 9823189