我在一个周末花10美元为创作者构建了一个50万域名搜索引擎
马林,星期天,凌晨2点。我无法入睡,对搜索引擎再次感到恼火。每一个我真正关心的查询——作品集、杂志、小而奇怪的艺术项目、一人软件——都被一堆企业文档和SEO泥淖淹没了。所以我在凌晨2点做了你该做的事情:我打开了终端,打算写个计划。"我想为自己做一个搜索引擎。大约有4000万个域名。我们可以存储每个域名的一点元数据。即使每个1KB,那也是40GB,这个是可以做到的。"到星期三午餐时,我已经对560,183个主页进行了编目,接下来没有值得查询的内容,并决定停止。这就是那个周末的故事:我构建了什么,什么崩溃了,它花了多少钱,如果你想自己构建一个,我会告诉你什么。主要观点,如果你只读一段:大约10美元,一夜的GPU租用,以及几个小时的操控,你可以拥有一个个人搜索索引,涵盖数十万个网站,占用不到1GB的磁盘空间。这就是整个提案。以下所有内容是我如何达到这一点以及其中的尖锐边缘。完整的技术细节提供了单独的信息。 我实际上想要构建的不是“索引网络”。而是:找到正在做事的人,艺术、代码、硬件、诗歌、小剧院,而不被docs.company.com淹没。个人的、单用户、无需账户。一个仅在主页上爬行的爬虫,一个小的本地语言模型,读取每个主页并写出一个名称、两三句话、一个类别和一些标签。顶部有一个小搜索UI,带有模糊匹配,这样我可以输入一个单词的一半仍然找到正确的网站。我写下我明确不想构建的内容,主要是为了让帮助我的代理不会安静地“简化”成更大的东西:没有IP扫描,没有Redis,不存储完整的页面HTML,没有重新抓取调度器,没有多租户。忽略只是一个类别上的复选框,在搜索时应用。爬虫仍然总结了电子商务网站,我只是不用看它们。简单的数学是数千万个域名,每个大约1KB的元数据,这对于一个Postgres服务器来说真的微不足道。页面文本本身从未打算成为一个语料库,只是一个在模型完成后立即被丢弃的临时缓冲区。 机器 四个进程,其中三个在我自己的PC上,一个租来的GPU,从未直接接触数据库: 一个抓取器。抓取一个待处理的域,尝试HTTPS然后HTTP,使用简单的HTML解析器提取标题、正文文本和出站链接,不执行JavaScript。将行设为“准备好”。 一个工作者。抓取一个准备好的域,如果页面是空的、停放的或是一个机器人挑战墙,则完全跳过模型,否则向一个小的本地模型(Gemma,4B参数)发出一个结构化请求,并返回一个名称、摘要、类别和标签。擦除临时文本,同时根据它们来自的页面类型对出站链接的优先级进行排队。 一个管理员。这个进程根本不接触主队列。它从产生了过多页面的主机中采样域,向模型询问“阻止、保留或不确定”,并安静地维护一个黑名单。为什么我需要这个稍后会详细介绍。 一个API和一个小的Web UI。带有过滤器的搜索,一个页面可以切换隐藏的类别,一个仪表板让我能够实际看到工厂在做什么,而不是眯着眼睛看日志。抓取器抓取的所有内容在“进行中”时直接存在于域自己的数据库行中。一旦模型完成,文本就会被擦除。这比听起来重要得多,因为在任何真实规模下,你都不能让原始页面文本无限堆积。四千万个行乘以几千字节很快就会加起来,而我只需要在模型读取文本的几秒钟内用它。 网络实际上是90%企业的 第一个版本在几个小时内就能工作。指向一个样本域,观察摘要,搜索它们。很好。然后,星期天下午,我查看了实际已编目内容,发现是错误的网络。超过90%的企业网站和文档。我的种子列表有偏差,而爬虫对接下来追逐什么没有意见。解决方案不是阻止任何东西。阻止感觉诱人但错误,因为一个无聊的企业文档页面仍然可能链接到某人的个人博客,而我不想失去这个。相反,我为队列加权:标记为“作品集”或“杂志”或“软件”的页面将其出站链接的优先级大大提升,被标记为“企业”或“文档”的页面则降低优先级。一个文本文件,category-priority.txt,成为了整个周末的方向盘。我调整一个数字,观察接下来一个小时的输入,重新调整。那天下午,我擦除了数据库两次,因为质量差到足以重新开始。有两个BUG显著突出:一个网站的摘要字段只是说“学术资料”,这是模型不小心放错位置的类别标签。解决办法是:将可疑的短摘要视为失败,并以更严格的提问重新尝试。
本站免费、广告极少。如果觉得有帮助,可以请我们喝杯咖啡 —— 任何金额都对持续运营有实际帮助。
☕请我喝杯咖啡