使用 Meili 搜索 Rust 包
Meili 即时搜索引擎的演示,展示了来自 crates.io 的软件包。

今天,我将引导您深入了解 crates.io,以及我是如何使用我们的即时搜索引擎:Meilisearch 制作一个替代搜索栏的。
Meili 即时、相关且容错的搜索引擎
Crates.io 是存储 Rust 社区包(crate)的官方网站,也是 cargo 包管理器上传、更新和下载这些包的地方。
Sean Griffin 是 crates.io 团队的一员,负责维护其当前的搜索引擎以及整个网站。Kornel Lesinski 构建了 lib.rs,作为 crates.io 的替代品,并使用 Tantivy 提供其搜索栏功能。老实说,我更喜欢它的颜色设计,这就是为什么我将其用于我们的搜索演示。
我决定运行我们的即时搜索引擎,并随着时间的推移测试其与现有解决方案的相关性。我们的搜索引擎使用完全不同的算法;它基于前缀搜索,并且能够容忍拼写错误。
Meili 具有容错能力并支持许多其他功能
于是我问自己:为什么不使用我们新的即时搜索引擎,并让它对我的社区有用呢?这会给我们带来大量的反馈,并且在此过程中可能会有一些拉取请求。
在 Meili,我们管理一个内部 Kubernetes 集群,这对于为客户托管演示很有用。本次演示的 Meilisearch 服务器目前运行在该集群的一个 Pod 上。
为了让 Meilisearch 展示这些包,我们需要找到 crates.io 上所有当前可用的软件包。幸运的是,这个索引在 GitHub 上以多个子文件夹的形式提供,其中包含包的名称和版本,大约有 32,000 个文件。每次包更新到新版本或某个版本被撤回时,都会进行一次提交。
因此,我使用了 crates.io-index 仓库来初始化我们新创建的 Meili 搜索引擎,但首先需要更多数据,例如每个包的描述、关键词和类别。再次,Rust crates.io 团队向我们提供了帮助,我与 Pietro Albini 进行了交流,他向我指明了不受速率限制的服务器,这些服务器提供包内容。
既然我们可以检索有用的数据,我创建了一个异步爬虫,它下载、提取、检索 Cargo.toml,并将基本数据上传到 Meilisearch。
Meili 面板界面显示原始文档
Meilisearch 现在能够理解这些数据,并为我们提供即时、相关且容错的响应。但是,新包呢?我们希望在新包发布时收到通知,并能够将其发送到 Meilisearch。
Docs.rs 是计算和存储 crates.io 上所有 Rust 包文档的官方网站。它每分钟都会比较 crates.io 索引,以了解新的包更新。幸运的是,它提供了这些更新的 Atom feed。
这就是 Heroku 登场的地方。Heroku 每月提供大约 1000 小时的免费服务器计算能力,并为我们提供调度器。我们可以利用这些免费额度,每 10 分钟通过抓取 Atom feed、像以前一样下载更新的包,然后实时更新我们的搜索引擎,自由地向 docs.rs 查询新更新的包!
获取新包需要 4 秒
搜索结果令人满意,但并非完全符合预期,有些地方不对劲。例如,当我们输入“serde”时,第一个结果是相关的,但接下来的结果却不相关。这与 Meilisearch 除了查询匹配词之外,没有足够的数据来对包进行评级有关。
Meilisearch 不知道如何仅凭匹配词来区分同等的包
下载量惊人地改善了搜索结果。这些数据可以通过crates.io 获取。每天都会进行一次完整的数据库导出,其中包含每个包的下载次数。我决定将这些下载量作为最后一个排名标准,以帮助 Meilisearch 区分被认为是同等的包。
借助下载量,Meilisearch 显示了更好的结果
我部署了一个 Heroku 调度器,每天运行以更新所有包的下载量;它大约需要 30 秒来下载 tarball、解压、读取 CSV 并将 32,000 个包的下载量上传到 Meilisearch。所以我们离每月 1000 小时的免费额度还很远。
我认为这个搜索演示相当不错,但我也考虑过添加同义词和停用词,因为 Meilisearch 支持这些功能。例如,输入“db”并看到与“database”相关的结果会很不错。停用词有助于忽略“the”或“that”这类有时会污染搜索结果的无用词,但我们需要小心,因为包名可能由停用词组成。
Meilisearch 还支持基本过滤功能,未来能够按类别或特定关键词搜索包将会非常棒。
所有这些改进都可以由您来完成;这个演示是开源的。核心引擎的源代码也在 GitHub 上提供,这正是本文的重点!请查看并讨论它,参与的人越多,功能就越多!