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 是一对,前者定桶的粗细,后者定扫几个桶,只改一个方向都对不上。如果同一现象隔几天又出现,说明根因没找到,别当偶发处理。
