8gu 刷题工具题库重构:从 426 题到 468 题的覆盖优化纪实
对 8gu_killer 刷题工具的题库进行了全面重构,修复了解析引擎的 6 个核心问题,从 50w 字面试宝典中提取出 468 道高质量题目,覆盖全部 17 个章节。本文记录了完整的优化过程和踩坑经验。
背景
前几天把 50 万字的《程序员面试宝典》导入了 8gu_killer 刷题工具,从那份 2052 页的 PDF→Markdown 文档中提取 Q&A 对。第一版跑出来 426 道题,看着还行,但总感觉哪里不对。
直觉告诉我:那份材料洋洋洒洒 5 万多行、17 个章节,不可能就这点题。
于是做了两件事:
- 写了个精确覆盖率检查脚本,逐章对比源文件 vs 题库
- 发现 7 道题确实该删(答案太短或全是垃圾字符),但有 35 道题是本该提取出来却被漏掉的
地毯式排查:找到 6 个漏题 bug
Bug 1:GARBAGE_WORDS 杀伤范围太广
最开始设置的关键词黑名单里有三个词:"拍一期视频"、"MIC解析"、"粉丝私信"。
初衷是过滤掉 PDF 中的广告和推广内容,但实际效果是:
- "强引用、软引用、弱引用、虚引用有什么区别?"→ 答案正文里恰好包含 "MIC解析" 这个关键词片段 → 整道题被标记为垃圾 → 漏掉 JVM 重要题目
- 那些出现在答案正文中的推广词,本来不会影响题目质量,却因为过激的过滤规则把整道题删了
教训: 黑名单过滤的粒度应该细到"行"级别,而非"整道题"级别。只删广告行,不删包含广告行但本身是正经内容的题目。
Bug 2:TOC 过滤误伤长答案
题库中有个优化:因为 Markdown 文件前 700 行是目录(Table of Contents),检测到"……"(省略号)就认为是目录行,跳过不处理。
但有些题的答案正文中引用了代码或配置,里面包含 "......" 或类似的长省略号。原过滤逻辑是检查整个答案正文,一旦正文里有 "......" 就判为目录跳过。
修复很简单:只检查前 200 个字符。目录的特征在前几行就能判断,不需要扫描全文。
Bug 3:单英文单词过滤过于粗暴
有个过滤规则:如果题目只有一个英文单词(如 "Future"、"Paxos"、"init"),就判定为残留片段,跳过。
这本意是过滤掉 PDF 排版导致的碎片,但 "Future"(Java 并发编程中的 Future/Callable)、"Paxos"(分布式一致性算法)、"init"(容器初始化)全都是正经面试题。这些单英文单词只是在排版中恰好单独占了一行。
修复后,这 3 题全部恢复入库。
Bug 4:跨行题目格式不兼容
源文件中有一种特殊排版格式:
17.11
Spring 里面的事务你是如何使用的?事务的隔离级别?
题号在单独一行,问题描述在下一行。而我原来的解析逻辑只匹配 "X.Y 题目内容" 这种单行格式,导致这些跨行题目全部漏掉。
加了 TWO_LINE_NUM_RE(正则检测 17.11 这种纯数字行),然后再读下一行作为题目内容,解决了这个问题。
Bug 5:CORRUPTION_MAP 不完整
PDF→Markdown 转换过程中,大量中文字符被乱码字符替换:
| 乱码字符 | 正确字符 |
|---|---|
| ✁ | 是 |
| ✃ | 把 |
| ✂ | 会 |
| ➓ | 口 |
| ✲ | 消 |
| ✑ | 的 |
| ✦ 或 ❖ | · |
这些乱码字符遍布整个文件。修复方案:维护一个 CORRUPTION_MAP 做逐字符替换,同时在答案清洗时做全量替换。
Bug 6:水印行污染答案
PDF 转换后,"咕泡教育" 这类水印行随机出现在答案正文中。之前的设计是用 GARBAGE_LINES 集合逐行过滤:答案中的每一行如果命中黑名单,就单独跳过这一行,而不是删掉整道题。
这样既去掉了水印,又保住了题目本身。
修复效果
修复完成后重新跑解析,数据对比:
| 指标 | 修复前 | 修复后 | 变化 |
|---|---|---|---|
| 题目总数 | 426 | 468 | +42 |
| 乱码字符 | 有(✁✂➓等) | 0 | ✅ 已清除 |
| 水印残留 | 有(咕泡教育) | 0 | ✅ 已清除 |
| 垃圾标题 | 有 | 0 | ✅ 已清除 |
| 难易分布 | 简单 113 / 中等 148 / 困难 165 | 简单 126 / 中等 161 / 困难 181 | ✅ 更合理 |
按章节分布:
| 章节 | 题数 |
|---|---|
| Java 基础 | 71 |
| MySQL | 65 |
| Spring | 64 |
| 计算机网络 | 47 |
| 社招 46 连问 | 45 |
| Redis | 40 |
| 消息队列 | 20 |
| 腾讯云 15 连问 | 18 |
| Zookeeper | 16 |
| 面试真题 | 14 |
| 小厂后端 | 13 |
| 蚂蚁金服一面 | 12 |
| 虾皮服务端 | 11 |
| 字节跳动面试 | 11 |
| JVM | 10 |
| 字节二面 | 6 |
| Dubbo | 5 |
总结
这次改动的核心思路就一句话:宁可多留十条疑似垃圾,也别误杀一道正经题。
之前的设计太保守了,用各种过滤规则疯狂砍题,结果把不该砍的也砍了。面试题库这种东西,覆盖度比纯净度重要得多——用户刷题的时候发现缺了一道高频题,体验比看到一道题带两行广告要差得多。
具体改动的四个要点:
- 降低过滤阈值 — 减少 GARBAGE_WORDS 条目,用行级过滤代替题级过滤
- 支持更多格式 — 补充 TWO_LINE_NUM_RE 处理跨行题目
- 修复编码损伤 — 完善 CORRUPTION_MAP 覆盖所有已知乱码字符
- 覆盖验证 — 写 coverage_check.py 逐章对比源文件,精确统计每章漏题量
最后验证通过的信号:全量使用自动化脚本跑一遍检查,所有指标绿了——0 乱码、0 水印、0 垃圾、难易分布 126/161/181、17 章全部覆盖。