现场是这样的。重建索引时同时往新旧两个集合写入,切换别名后对比发现新集合里有一成二的向量重复,原因是双写期间上游重试把同一条文档写了两次,而写入用的是随机主键。
中间走过弯路,把「切换前没有做数量与主键对账」当成主因,改完现象没变。
原因不止一个,得分开看。写入主键用随机 uuid,重复写入不会去重;双写窗口里上游重试没有幂等控制;旧集合里的删除操作没有同步到新集合。
第一件事是按文档 id 统计重复数量
python -c "import json;from collections import Counter;print(Counter(x['doc_id'] for x in map(json.loads,open('dump.jsonl'))).most_common(3))"
接着改成用文档 id 做确定性主键
curl -s -X PUT http://milvus:19530/v1/vector/upsert -H 'Content-Type: application/json' -d @upsert.json
然后切换前做数量与主键对账
python reconcile.py --old col_v1 --new col_v2 --by doc_id
剩下的就是按文档 id 把删除同步到新集合
python sync_delete.py --from col_v1 --to col_v2 --since 2026-11-01
怎么算真的好了,看的是同一批现象。新集合里同一文档只有一条向量,总数与旧集合一致,抽查二十个已删除文档在新集合里也查不到。
双写期间必须让主键可推导,随机主键加上游重试,重复几乎是必然的,切换前对账比事后去重省事。拖得越久,排查成本越高,因为现场状态会被后续操作覆盖。
