外观
上亿试题,采集、去重与持续更新怎么展开?
标准回答
我负责过从试题采集、离线处理到入库和持续更新的数据链路,主要使用 Python 和 Scrapy。项目记录的累计数据量达到上亿,但这里的累计记录数,不能直接当作当前去重后的独立题目数或在线索引文档数。
这条链路的关键是把抓回来的内容转成可以稳定检索的数据。原始页面可能有 HTML 差异、重复题干、选项顺序变化和答案不一致,不能只关心抓取速度。采集、规范化处理、存储和搜索索引需要分别看,数据质量问题也要能追到来源和处理阶段。
去重尤其需要谨慎。只按原始字符串判断,会把格式不同的相同题目保留下来;只按题干合并,又可能把选项或答案不同的记录错误合并。具体采用哪种规则和冲突策略,要以项目实际代码为准,不能因为数据量大就默认已经做了复杂的语义去重。
持续更新还要考虑失败重试、重复入库以及后台处理对在线查询的影响。我的经历覆盖这条产品数据链路,但没有可核对的原始记录时,我不会额外报出去重率、分片数或存储体量。规模和质量要分别用对应证据说明。
关键机制
- 需要区分原始抓取、规范化题目、去重结果和搜索索引,保留来源与处理版本,便于定位错误。
- 去重可基于规范化文本、内容摘要或相似性,但具体算法、冲突处理和误合并策略必须对应实际实现。
- 增量更新与失败重试要防止重复入库;批量处理需要背压和恢复点,避免任务积压冲击在线服务。
通俗例子
题干相同但选项顺序或答案不同,不能仅按原始字符串是否一样决定合并;相同题目的 HTML 差异又可能制造大量重复。
追问与回答
数据多为什么还能搜得快?
全文检索通常依靠倒排索引缩小候选范围,而不是每次把全部题目扫描一遍。但数据多不代表查询一定快,分词、字段映射、查询方式、分片和资源都会影响耗时。项目中我使用 Elasticsearch,并优化索引、查询和接口链路,也引入缓存减少重复搜索。具体速度和容量需要结合当时配置与监控,不能只用“有索引”解释全部性能。
采集程序挂了怎样继续?
技术上要保留可恢复的任务状态和已处理边界,重启后继续未完成工作,同时让重复处理不会导致重复入库。Scrapy 本身有任务持久化相关能力,但是否启用、存了哪些状态、哪些请求可恢复,都需要看配置。我的项目实际续跑方式要与实现核对,不能因为用了 Scrapy 就声称自动拥有完整断点恢复和恰好一次写入。
易混淆点
不要编造具体分片数、去重率、存储 TB 数或数据来源授权范围。规模口径应能由记录核对。
参考资料
内容来源
- Android 技术札记 · 原条目
product-data