faiss-cpu 1.8.0,12 万条 768 维向量直接建 IndexIVFFlat,nlist 设 4096,训练时报 clustering 4096 points but only 120000 training points,之后检索召回明显偏低。

一开始怀疑是「nprobe 仍是默认 1,只扫一个倒排桶」,查了一圈,方向不对。

排查方向其实有限,先把可能性排一排。nlist 超过训练样本的三十分之一,聚类中心不够分。也可能是训练集用了全量数据,耗时且没有代表性。

少数情况下是向量维度高但样本少,PQ 子空间切得过细。

动手时先按样本量重算一个 nlist

python -c "import math;n=120000;print(int(4*math.sqrt(n)))"

接着重建索引并只训练一次

python -c "import faiss,numpy as np;xb=np.load('xb.npy');idx=faiss.IndexIVFFlat(faiss.IndexFlatL2(768),768,1385);idx.train(xb);idx.add(xb);faiss.write_index(idx,'ivf.faiss')"

调 nprobe 观察召回变化

python -c "import faiss,numpy as np;idx=faiss.read_index('ivf.faiss');idx.nprobe=16;print(idx.search(np.load('xq.npy'),10)[1][:1])"

压一次单查询耗时

python bench_faiss.py --index ivf.faiss --queries 1000

同一份数据我导出了两份,一份留底,一份拿来试。

这类问题以前遇到过,但这次的触发条件和上次不一样。

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

改完先别撤,确认这几项。训练不再告警,nprobe 设 16 时 recall@10 达到 0.9,单次查询耗时 8 毫秒。

提醒一点。nlist 和 nprobe 是一对,前者定桶的粗细,后者定扫几个桶,只改一个方向都对不上。如果同一现象隔几天又出现,说明根因没找到,别当偶发处理。

作者 9823189