老师给出“倒排索引合并时,文档频率高的词会拖慢查询”这类结论,你无法验证,最直接的办法是构造一个假设的小型语料,分别改变词频和文档长度,观察合并步骤中比较次数的变化。反例练习的目的不是推翻结论,而是找出结论成立的前提条件。
把结论改写成一句可以证伪的话,例如“在倒排列表按文档编号升序排列的前提下,高频词一定比低频词产生更多比较”。如果这句话在某个条件下不成立,那个条件就是你需要补充的反例边界。假设你手头有五个文档,词A出现在全部五篇中,词B只出现在两篇中,但两篇的倒排列表长度相差很大。
此时不要急着说结论错了。先列出可能影响结果的因素:列表是否有序、查询是否要求全部命中、是否使用了跳表指针、合并时是否提前终止。这些因素中只要有一个不同,同样的词频就可能得出相反的观察。
反例练习的核心是控制变量。以下是一个假设的对照设计,只用于说明比较方法,不代表任何真实系统:
如果实验组的比较次数明显高于对照组,那么“高频词拖慢合并”这个结论在你的设定下成立。如果两组比较次数接近,说明真正起作用的可能是列表长度差,而不是词频本身。这一步的结果会直接决定你下一步该查什么:是查跳表优化,还是查查询重写策略。
老师只给结论时,你最容易漏掉的是记录过程。一个可复核的反例记录至少包含四部分:初始条件、你改变了什么、观察到了什么、以及这个观察能排除哪种解释。假设你在第三步把列表顺序从升序改成降序,发现比较次数反而减少,这时你不能直接宣布“升序更差”,因为降序可能触发了另一种提前退出逻辑。
更稳妥的做法是:把顺序、长度、是否使用跳表分别作为独立变量,每次只改一个。改完后用同一组查询重复三次,取比较次数的中位数,而不是单次结果。这样做的结果是,你能区分“顺序影响”和“随机波动”,下一步就可以把精力放在真正有影响的变量上。
反例练习做到最后,你得到的往往不是“老师错了”,而是一句带条件的判断:在倒排列表等长且有序的前提下,词频高低对合并比较次数的影响很小;当列表长度差异超过某个范围时,长度差才是主导因素。这个条件句比原始结论更有用,因为它告诉你什么时候可以忽略词频,什么时候必须处理长列表。
如果你发现多个反例都指向同一个边界条件,例如“只在没有跳表的情况下成立”,那就把这个条件写进你的笔记,并找一个有跳表的场景重新验证。验证结果无论正反,都会让你对结论的适用范围更清楚。这一步的动作是主动改变一个前提,结果是你的判断从“记住结论”变成“知道结论在什么条件下失效”。
如果反例练习中参考了论坛帖子或培训材料,而材料没有给出可复现的步骤,不要直接采信其中的数字。你可以先检查它是否说明了语料规模、查询类型和比较口径。缺少这三项中的任何一项,那个数字就只能当作线索,不能当作证据。此时更合理的动作是回到自己的最小对照实验,用你能控制的条件重新观察一次。
假设某份材料声称“高频词查询慢三倍”,但没有说明文档长度分布。你可以构造两个长度分布不同的假设语料,分别测量比较次数。如果结果差异很大,说明“慢三倍”这个说法依赖特定分布,不能直接搬到你的场景里。这个判断会影响你下一步是继续读材料,还是先补做长度分布实验。
反例练习的价值在于把别人给的结论变成你自己的条件判断。每补一个反例,你就多知道一个边界;边界越清楚,下一步该验证什么就越明确。