同一份档案放了两处,出处就多了九千条
一个下载文件夹里同一份档案躺了两遍,逐字节相同。产出的记录一条不差——错的是每条记录的出处,2933 条标记声称同一次抓取看见过它两次。记录对、出处假,而下游没有一处会读到它。
一个普通的下载文件夹里,同一份档案躺在两个地方:顶层一份,
20260806/ 下面一份,逐字节相同。
解压过两遍,或者整理之前先备份了一下——总之是人会做的事。
解析器把它读成了两份。而产出的记录,一条不多一条不少:
| 有那份重复 | 没有 | |
|---|---|---|
| 标记 | 2964 条(修订 3117) | 一模一样 |
| 广播 | 3423 条(修订 3898) | 一模一样 |
| 作品 / 长文 / 豆列 | 2964 / 5 / 6 | 一模一样 |
| 档案份数 | 27 份 | 26 份 |
| 观测次数 | 47646 | 41327 |
| 起点 | 7 个(3eef52 列了两次) | 6 个 |
记录是对的,因为合并本来就是并集——同一条捕获读两遍,第二遍什么都没添上。 错的是出处。
出处是这份档案唯一的凭据
canonical 里每一条记录都带着一串 capture_ids,指回 WARC 里
具体某一条捕获。整个项目的说法——「这不是我编的,你自己去看那一页」——
全押在这串东西上。
而多出来的那一份,让它开始说假话:
标记 2933 条修订里,同一个 bundle 记了两次「我看见了它」
作品 2933 条
广播 3188 条
它只看见过一次。多出来的那一次,是一个文件同时躺在两个文件夹里造出来的。
没有任何一处会报错,因为记录数是对的、修订数是对的、 页面是对的、导出是对的。只有去数出处才看得见。
为什么不干脆让人自己收拾干净
因为这条路走过。解析器早就不再要求把档案摊平: 它会钻进子目录,一个目录里混着几份索引也逐份读出来。理由每次都一样—— 要求人先手工整理,换来的只会是漏掉一份,而漏掉一份不会报错, 产出照样是一份看着完整的档案。
而「钻进子目录」这件事本身,让复制一个文件夹更容易变成两份档案, 不是更少。所以修法不是拒绝,是认出来。
判据:索引是不是前缀
抓取过程中索引只往后追加,导出只是把文件拷走。所以「早一次导出」的索引 一定是「晚一次导出」的前缀——逐字节相同只是它的特例。 这条性质是免费的,也足够严:
- 是前缀:同一份档案的一份拷贝。留捕获多的那个, 并把略过了哪个目录打印出来。
- 不是前缀:两个不同的东西顶着同一个编号。 两份都读,并报警告。
第二条要紧。丢掉其中一个才是不安全的方向——那会静默丢数据; 而两份都读的全部代价,只是重复的出处又回来了,而且这回它被说出来了。 方向不对称,处置就不该一样。
顺带说一句它为什么不影响你已经有的东西
样张站、导出到 NeoDB 的包、Markdown 树——一个字节都没变,
因为下游没有一处读 capture_ids。这不是「所以无所谓」,
恰恰相反:一个只有去数才看得见、而且下游全都不看的错误,
正是这个项目最怕的那一种。
修完之后拿真实档案跑了一遍,产出与「手工把那份重复删掉再跑」逐字节 相同——五个文件,五个哈希,一个不差。