2026-09-23·by Sijie Wang#lucerna#software#architecture

full-text-search

全文搜索(每本书一个 FlexSearch 索引,磁盘持久化)

父级:key-designs

core/src/search/SearchEngineSearchIndexSearchServiceSearchIndexStoreaggregateConsecutive,以及 searchTokenize/searchIndexVersion)。

每本书一个 FlexSearch 索引,粒度是句子。 每条 CachedSentence 的显示文本就是一个文档;一次查询返回按相关度排序的句子命中,aggregateConsecutive 再把它们折叠成连续的段落(这样一个跨两句话的短语会读成一条结果,而不是两条)。结果携带句子的原始偏移量,因此从一次搜索命中跳转时,会通过 coordinate backbone 落到正确的页面上。

"恢复而不是重建"是承重的那个决定。 把整本书倒进一个全新的 FlexSearch 索引开销很大,所以索引会被序列化成一个磁盘 blob(通过 SearchIndexStoreexportSections/importSections),以内容哈希 + SEARCH_INDEX_VERSION 为键。重新打开书时,importSections 能在 500 毫秒内恢复索引,而不必重新分词建索引;版本号一旦提升,旧 blob 就作废并触发重建。一个门面层(markBuilding/attach/detach)把索引的生命周期和分页协调在一起(两者消费的是同一条句子流),这样搜索就不会自己再单独分词一遍。

它是支柱而不是一个可有可无的勾选项,原因在于:一个重度读者会不停地搜索,而书大到每次打开都重新建索引是无法接受的——所以"持久化 + 恢复 + 版本号"这套机制才是实质所在,这和 dynamic-pagination 以及句子缓存"版本化并恢复、而不是重新计算"的做法完全对称。

about this entry

One of sijie's wiki entries. The AI on this site is grounded in the same corpus and answers in sijie's voice, with citations back to entries like this one — answering costs sijie money, so it waits behind a code: enter an access code →

full-text-search