先把当时的情况摆出来。Milvus 2.4 用 upsert 只更新 title 字段,期望其他字段保留,结果 tags 与 created_at 全被写成默认值,因为 upsert 是整行替换而不是局部更新。

这类报错背后常见的原因有几处,逐个排除就行。upsert 的语义是整行覆盖。还有一种是动态字段没带就会被置空。

另外,缺省值被自动填充,看起来像数据丢了。少数情况下是没有先读旧行再合并。

第一件事是按主键把整行查出来

python -c "from pymilvus import Collection;c=Collection('docs');print(c.query('id==1',output_fields=['*']))"

再往下在应用层合并字段后再 upsert

python merge_upsert.py --id 1 --set title=new --collection docs

或用 delete 加 insert 保证语义清晰

python -c "print({'step':'delete then insert','pk':1})"

回读该行确认所有字段都在

python -c "from pymilvus import Collection;print(Collection('docs').query('id==1',output_fields=['tags','created_at']))"

这次没动代码,只在配置和运行环境上找原因。

隔了一天再看,现象没变,说明不是偶发。

怎么算真的好了,看的是同一批现象。回读的整行里 tags 与 created_at 保持原值,title 已更新,其他行不受影响。

这里还有个坑。upsert 不是 patch,需要局部更新时先读后合并,或者干脆用带条件的 update 语句。同一份配置在测试环境跑通,不代表线上没事,两边的默认值经常不一样。

作者 9823189