indexeddb离线搜索引擎核心是建倒排索引、web worker搜索、分块写入与事务同步。需建inverted_index和documents仓库,分词归一化后批量存词→文档id映射,搜索由worker查索引并返回docids,增删改文档时同步更新索引以保证一致性。

网页端用 IndexedDB 实现离线搜索引擎,核心不是“存数据”,而是“建索引、查得快、不卡主线程”。倒排索引必须落地在 IndexedDB 里,再配合 Web Worker 处理搜索逻辑,才能支撑万级文本的毫秒级本地检索。
设计带倒排索引的对象仓库结构
IndexedDB 本身不支持自动构建倒排索引,需要你手动拆词并存为独立记录。关键在于把“词 → 文档ID列表”这个映射关系,转化为可高效查询的数据库结构:
- 建一个名为 inverted_index 的对象仓库,主键设为
word(字符串),值为包含docIds: number[]的对象 - 同时建另一个仓库 documents 存原始文档,主键用自增
id,字段包括title、content、createdAt等 - 为
documents仓库创建title和content两个普通索引,用于后续补充检索或高亮 - 避免在
inverted_index中存长文本或冗余字段——它只负责跳转,不负责展示
构建倒排索引要分步做,不能全量塞进一次事务
一次性处理十万文档会触发内存溢出或 IndexedDB 事务超时。应采用分块 + 批量写入策略:
将调研报告、方案对比、数据分析、需求梳理、会议纪要、设计说明、代码评审、学习笔记等任务产物输出为可在浏览器直接打开的单文件 HTML,替代 Markdown 作为最终交付物。Markdown 在信息密度、视觉清晰度和可分享性上已跟不上 AI 产物的丰富度,HTML 能同时承载排版、表格、SVG 等。
- 前端预处理时,对每篇文档提取关键词(可用简单空格分词,或轻量级中文分词如 segmentit)
- 每个词归一化:转小写、去标点、去停用词(如“的”“了”“and”)
- 按文档 ID 分组聚合:例如文档 123 含词 [“react”, “state”],就向
inverted_index中对应 key 插入或追加 docId - 每 200 条词-文档映射打包为一个
store.put()批次,在单个readwrite事务中提交 - 构建完成后,可存一条元数据记录到
metadata仓库,标记indexBuiltAt和totalDocs
搜索时用 Web Worker 调用倒排索引,主线程只管渲染
用户输入关键词后,不能在主线程遍历所有文档,而应让 Worker 去查索引、合并结果、去重排序:
- 主线程将关键词发给 Worker,Worker 通过
indexedDB.open()打开数据库(注意:Worker 内可直接访问 IndexedDB) - Worker 使用
index.get(word)查单个词;多词查询(AND)则分别取 docIds 数组,用 Set 交集运算 - 结果只返回匹配的
docIds数组,不带原文内容——内容由主线程按需从documents仓库查 - 若需相关性排序,可在 Worker 中为每个 docId 计算词频(TF)或简单加权(如标题命中 +2 分,内容命中 +1 分)
- 最终结果传回主线程,交给虚拟滚动组件渲染,避免 DOM 批量操作阻塞
更新与同步需兼顾一致性与体验
用户新增/修改笔记时,倒排索引必须同步更新,否则搜不到新内容:
- 新增文档:先存入
documents,拿到自增id后,再提取词、更新inverted_index对应词条的docIds数组 - 修改文档:先从
documents读旧内容,删掉旧词对应的 docId;再写新内容,插入新词的 docId - 删除文档:从
documents删除,并遍历其所有词,在inverted_index中从对应数组里移除该 docId - 所有写操作都封装在同一个事务中,保证
documents和inverted_index数据一致 - 可加个简易版本号字段,每次索引重建后更新,避免 Worker 读到脏数据










