同一张海报,换个服务器地址,档案里就多一条「改过」
111 条作品修订是凭空的,两版之间只差一个字符。而去修它之前先重量了当初记下的两个数字——两个都是错的,其中一个还把问题的性质说反了。
同一张海报,两次抓取之间只有一个字符不同:
https://img1.doubanio.com/view/photo/s_ratio_poster/public/p2888584528.webp
https://img3.doubanio.com/view/photo/s_ratio_poster/public/p2888584528.webp
路径一字不差,也就是同一张图。而封面地址参与「这条记录变了没有」的判定, 于是它开出一条修订——档案里多了一句「豆瓣改了这个作品」,而豆瓣什么都没改。
这件事早就记着,标着「先不修,等想清楚」。这次去想清楚, 而第一步是把当初记下的两个数字重新量一遍——两个都是错的。
错的第一个:202 是差异对,不是修订数
原来那句写的是「藏着 202 条只有分片不同的修订」。202 是相邻两版之间只有主机不同 的那些配对;其中有 91 对还带着别的字段一起变——那些修订本来就该存在, 分片只是搭了个便车。
真正凭空多出来的是 111 条,占 8172 条作品修订的 1.4%。
这个项目上个月刚在同一个形状上栽过:两组各 8 条记录,因为都是 8 就被写成了一句话, 而它们数的根本不是同一件事。两个数一样之前,先确认它们数的是同一件事。
错的第二个:豆瓣不是「按请求随机挑分片」
原来的解释是这样写的。量一遍:
| 扫过的图片路径 | 436,197 条 |
| 同一份档案内,同一条路径出现两个主机的 | 0 条 |
| 主机变过的海报 | 589 张 |
| 其中变过两次、或者换回去过的 | 0 张 |
一次抓取之内,主机永远一致;每张海报只挪过一次,没有一张挪回去。 所以不是抽样抖动,是豆瓣某个时点把图挪了一次,然后就稳在那儿。
这改变了问题的性质。不是「我们记下了噪声」,而是「我们如实记下了一次真实、 但没有意义的变化」——跟「这条短评有几个人觉得有用」「这篇日记被看了多少次」 归成一类,而不是跟「每次渲染都不一样的那种地址」归成一类。
顺带,量的过程里我自己踩了一个:
第一版扫描对压缩过的档案只印了一句「binary file matches」,一条内容都没输出。 于是「不一致 0 条」是个空循环得来的答案。
一个不可能失败的检查,证明不了任何事。加一个参数之后才是真数字。
修法:事实与索引并存,索引不覆盖事实
这个项目在另一处早就有现成的写法——档案里每个网址都存两份,一份原样,一份剥掉跟踪参数用来去重。照抄:
| 字段 | 是什么 | 参不参与判定 |
|---|---|---|
cover_url | 页面上原样那一个 | 不参与 |
cover_url_key(新) | 抹掉量过的那一族分片主机 | 判据是它 |
三条边界,每条写反了都会静默出事:
- 只抹主机。路径里的图片编号已经唯一标识了这张图——实测 5820 个原始地址 收成 5231 个索引,而一个索引底下出现两条不同路径的:0 个。
- 尺寸那一段绝不许抹。不同尺寸是不同的字节,抹了就是两张不同的图被静默并成一张。 这是这条规则唯一会造成真数据丢失的方向。
- 没量过的形状一律不动。档案里除了那四个分片,还真有一个别的图片主机 (出现过 4 次)。「不要把图片主机当成闭集」是这个项目吃过亏的规矩。
也没有拿索引去改写那个地址。档案里没有任何一条路径被从两个主机各抓过一次, 所以「几个分片给的字节完全一样」这句话本地证不了——改写就是在做一个没有证据的断言。
代价照说:分片变了而海报没变时不开新修订,于是 cover_url 留着的是
那条修订开张时看到的值,不保证是最新的。这是对的——一条修订的字段就是
「第一次看到它这样时页面这么说」,为一个字段破例,读者就会读错另外二十个。
最新那个地址一个字节都没丢,它在原始档案里。
「没有摘要」是个决定,所以它必须被检查
一个字段不参与判定,在数据上与「忘了给它算摘要」长得一模一样。 而后者的症状是该记的变化没记下来——只有去数才看得见。
所以豁免是明写着传进去的,而格式校验器新增一条规则:摘要的键必须等于字段的键 减去明写的豁免,少一个多一个都报错。
那条一致性用例的第一版,被它自己的说明文字戳穿了
用例里放了两个作品:一个只换分片(必须只有 1 条修订),一个真的换了图(必须 2 条)。 说明文字写着「两个方向都钉」。
变异测试一跑:把封面地址整个删掉,用例照样全绿。 修订条数分毫不变——因为索引还在。而那是真的丢数据。
文字写的是本体,断言写的是代理,两者隔着三行。这是这个项目记下的第八条代理断言, 而这一条特别值得记:它是在自己的说明文字里被戳穿的。 写完「这个用例在守什么」之后回头对一遍断言,是这一族里最便宜的一道检查。
结果
| 改之前 | 改之后 | |
|---|---|---|
| 作品修订 | 8172 | 8061(−111) |
| 标记 / 广播 / 长文 / 豆列 | 一条不动 | |
| 真的换过封面的次数 | 3535,一次不少 | |
2967 个作品逐条比对:新的产出恰好等于把旧的「只差分片」的相邻修订压掉,其余字段零差异。