索引分片

将过大的倒排索引按词条范围拆分成多个小文件,使客户端搜索时只需下载命中的分片,大幅降低带宽占用。

#type / concept #status / growing #tech / dev / frontend #resource / pagefind

[!info] related notes

索引分片

一句话定义

索引分片(Index Sharding)是将一个过大的倒排索引按词条范围拆分成多个小文件的策略,使客户端搜索时只需下载命中的那个分片,而不是整个索引。

核心机制 / 工作原理

为什么需要分片

如果一个网站有几千篇文章,倒排索引中可能包含几十万甚至上百万个词条。把所有词条放在一个索引文件中,这个文件本身也可能达到数 MB 大小。

用户每次搜索时,如果都要下载这个完整的索引文件,首屏体验会很差——尤其是在移动网络环境下。

分片的思路

核心思路是把大索引表按某个键(通常是词条的首字母、哈希值或词条范围)拆分成多个小片段:

shard_a-d.json   → 包含 a 到 d 开头的词条
shard_e-h.json   → 包含 e 到 h 开头的词条
shard_i-l.json   → 包含 i 到 l 开头的词条
...
shard_w-z.json   → 包含 w 到 z 开头的词条

同时维护一个很小的元数据表(meta index),记录每个分片包含哪些词条范围。这个元数据表通常只有几 KB。

查询流程

  1. 浏览器首先只加载很小的元数据表(几 KB)
  2. 用户输入查询词(比如 “proxmox”)
  3. 查元数据表,判断这个词条属于哪个分片
  4. 只下载那一个分片文件(通常也只有几 KB)
  5. 在分片内执行搜索,返回匹配的文档列表

这样无论索引总量多大,单次搜索的网络开销都只和一个分片的大小成正比。

Pagefind 中的实现

Pagefind 是索引分片策略的典型实践。它在 pnpm build 构建完成后运行,用 Rust 构建倒排索引,然后按词条范围将索引切分成几百个极小的分片文件(每个通常只有几 KB),存放在 pagefind/ 目录下。

搜索时,浏览器先加载一个很小的 pagefind 入口文件和元数据表,然后根据查询词动态拉取对应的分片。这就是为什么一个包含 2400 多篇文章、28 万个词条的知识库,搜索首屏加载可以控制在 30KB 以内。

与全量索引的对比

环节全量索引(单文件)索引分片
首屏加载下载整个索引文件(可能数 MB)只下载元数据表(几 KB)
搜索时在已下载的完整索引中查找定位分片 → 下载分片 → 在分片中查找
结果渲染数据已全在内存,直接取用按需调用 result.data() 懒加载摘要
适合规模小站(< 100 页)中大型站(数百到数万页)

分片在其他领域的类比

分片策略不限于搜索索引,在分布式系统中也很常见:

  • 数据库分片(Database Sharding):按哈希或范围把数据分到不同数据库节点,减轻单节点压力
  • CDN 分片:把静态资源分散到不同域名或节点,用户就近获取
  • 消息队列分片(如 Kafka Partition):把消息流分散到多个分区,支持并行消费

核心思想都一样:把大规模数据拆成小块,让每次操作只需接触其中一小部分。

边界与易混淆点

  • 索引分片(Index Sharding)和浏览器域名分片(Domain Sharding)是不同概念。前者是把数据文件切小,后者是把静态资源分散到多个域名以绕过 HTTP/1.1 并发连接数限制
  • 分片不是越细越好。分片过多会导致请求数量增加(每个分片一次 HTTP 请求),需要在”单个分片大小”和”总请求数”之间找到平衡
  • 在 Pagefind 中,分片策略由工具自动处理,开发者不需要手动调整分片粒度
  • 分片策略常和懒加载配合使用:先通过分片定位到小文件,再通过懒加载按需获取结果数据
创建于 2026/6/21 更新于 2026/6/21