构造反例样本的目的,是在批量替换真正执行前,找出那些“替换后会变坏”的文本位置。做法不是随机抽样,而是按替换规则的触发条件反向设计:先列出规则可能误伤的文本形态,再为每种形态准备一条真实存在的记录,逐条跑替换并对比结果。反例样本合格的标准只有一条——如果这条记录被改坏,你能在批量执行前发现,并且知道该保留、改写还是退出。
旧内容、旧系统或旧合作关系要退出时,最容易被忽略的不是明显要删的部分,而是那些暂时没被规则命中的内容。它们看起来安全,只是因为当前替换规则的关键词、字段或匹配范围还没覆盖到它们。把这类内容误当成“保留项”,反例样本就会漏掉最关键的一批测试对象。
区分方法是给每条记录标注退出状态,而不是标注内容好坏:
一个实际动作:在替换脚本运行前,先导出全部待处理记录,只给“确定保留”和“待定”两类打上标记。这个动作的结果会直接决定下一步——如果“确定保留”的记录数量很少,说明旧结构本身已经接近整体退出,替换可以更激进;如果数量很多,说明替换规则必须收窄匹配范围,否则会大面积误伤。
常见的抽样思路是按栏目、按时间或按流量分层抽取。这对评估整体质量有用,但对批量替换不够,因为替换出错往往集中在少数文本形态上,而不是均匀分布。更有效的做法是反过来问:这条替换规则在什么情况下会改错?
假设要把旧品牌名统一替换为新名称,可能的误伤模式包括:
每一条误伤模式,至少要有一条对应的真实记录进入反例样本。样本不需要多,但必须覆盖每一种误伤模式,并且这些记录要来自实际数据,不能临时编写——临时编写的例子往往过于干净,测不出真实文本里的边界情况。
这里可以做一个注明假设的短例子:假设某站有 800 条旧记录,按栏目分层抽 40 条,其中可能只有 2 条包含引文中的旧名称;而按误伤模式定向找,能在 10 分钟内定位到全部 7 条引文记录。前者的测试覆盖率取决于巧合,后者取决于规则本身。这个比较说明的是抽样方法差异,不代表任何真实站点的比例。
跑完反例样本后,如果发现某条记录被改坏,不要立刻修改替换规则。先判断这条记录属于哪种情况:
这三种判断会导向完全不同的下一步。如果混在一起,最常见的后果是不断给规则打补丁,最后规则复杂到没人能预测它的行为。一个可操作的分界:如果某条记录需要为它单独增加一条例外规则,就说明它应该被单独处理,而不是留在批量替换里。
反例样本跑完后,通常会把替换前后的结果做对比。这时要注意,替换前后出现的差异不一定来自替换本身。搜索需求会随季节波动,采集时间不同会导致数据口径不一致,旧系统和新系统的统计方式也可能不同。这些因素都会让“替换后变差”看起来像是替换造成的。
可行的做法是:在反例样本中保留一组不参与替换的对照记录,它们与测试记录处于相近的栏目和相近的时间段,但不在替换范围内。对比时先看对照组有没有同步变化——如果对照组也在变,那么测试组的变化就不能单独归因于替换。这是比较方法上的约束,不是对任何具体工具或平台的要求。
另外,某条记录在替换后流量归零,也不能单独证明替换处理正确。它可能是替换导致的,也可能是该内容本身的需求已经消失、采集口径变化,或者它本来就在退出范围内。要区分这些解释,需要看它在对照记录中的相对位置,而不是只看它自己的绝对值。
反例样本跑完,通常会得到三类记录,对应三种动作:
这个顺序不能颠倒。如果先批量替换再回头处理被改坏的记录,损失往往不可逆,尤其是引文、专有名词和标识符被改动后,很难从备份中精确还原。反例样本的价值就在于把这三类判断提前到执行之前,让批量替换只处理已经确认过的范围。
最后一步是记录反例样本本身:哪些记录被选为反例、对应哪种误伤模式、最终判定为保留、改写还是退出。这份记录不需要复杂,但要能回答一个问题——下次规则变化时,哪些记录需要重新测试。没有这份记录,反例样本就只是一次性检查,无法在后续改动中复用。