毫秒级响应:前端本地搜索的“降维打击”

你一定被原生 IndexedDB 的查询限制气笑过:它只支持前缀匹配IDBKeyRange.bound),想搜"中间字符"?对不起,原生没有 LIKE %keyword%

在 AI Prompt Manager 场景下,用户可能搜"前端"、"报告"、"审计",这些词可能出现在标题中间。如果直接 getAll() 拿出来在 JS 里 filter,数据量上万时,内存占用主线程卡顿会直接让你的"资深"头衔蒙尘。


1. 为什么原生查询不行?

原生 IndexedDB 的索引是 B-Tree 结构,它能极快地找到"以某字符开头"的数据,但无法处理"包含某字符"。

  • 低级做法getAll() + Array.prototype.filter。数据量 10k+ 时,解析 JSON 的开销会让 UI 瞬间掉帧。
  • 高级做法倒排索引(Inverted Index)

2. 方案一:引入 FlexSearch (极致性能的首选)

FlexSearch 是目前 Web 端最快的全量搜索库,它的速度比 Fuse.js 快一个数量级。

实战集成:PromptDB + FlexSearch

JavaScript

javascript 复制代码
import { Index } from "flexsearch";

class SearchablePromptDB extends PromptDB {
  constructor() {
    super();
    // 创建内存索引,开启"模糊匹配"(suggest)
    this.index = new Index({
      tokenize: "forward", // 适合前缀+中间搜索
      resolution: 9,
      cache: true
    });
  }

  // 1. 同步索引:在数据存入 DB 的同时,存入 FlexSearch
  async addWithIndex(prompt) {
    await this.set(prompt);
    this.index.add(prompt.id, `${prompt.title} ${prompt.content}`);
  }

  // 2. 毫秒级搜索
  search(query) {
    const results = this.index.search(query, { limit: 20 });
    // results 返回的是 id 数组,再去 DB 拿具体对象(或从内存缓存拿)
    return results; 
  }
}

3. 方案二:手写"倒排索引" (不依赖库的深度方案)

如果你不想增加包体积,可以利用 IndexedDB 的 multiEntry 特性。

核心技巧:词根索引化

将 Prompt 的标题和标签拆分成字/词,存入一个专门的 searchTerms 数组字段。

JavaScript

scss 复制代码
// 存入时
const prompt = {
  id: 'p1',
  title: '金融审计助手',
  // 手动分词:['金', '融', '审', '计', '助', '手', '金融', '审计']
  searchKeywords: splitWords('金融审计助手') 
};

// 在 DB 初始化时,为这个数组字段开启 multiEntry
store.createIndex('keywords_idx', 'searchKeywords', { multiEntry: true });

// 查询时
const range = IDBKeyRange.only('审计');
const request = index.getAll(range); // 瞬发响应,因为它是原生索引

注:multiEntry: true 会为数组中的每个元素在 B-Tree 中创建一个独立的指针。


4. 性能瓶颈的终极解决方案:Web Worker

即便搜索算法再快,当数据量达到 10 万级,字符串分词索引构建依然会占用主线程。

架构设计:将搜索推入边缘

  1. 主线程:只负责接收用户输入和渲染结果。
  2. Worker 线程:持有 FlexSearch 实例,监听 IndexedDB 的变化。
  3. 流程:输入 -> PostMessage -> Worker 搜索 -> 返回 ID 列表 -> 主线程渲染。

JavaScript

ini 复制代码
// search.worker.js
self.onmessage = ({ data: { type, payload } }) => {
  if (type === 'SEARCH') {
    const results = flexIndex.search(payload);
    self.postMessage(results);
  }
};

5. 优化建议

  1. 分词策略 :中文搜索最简单有效的是 "二元分词" 。例如"我的代码",拆分为 ['我', '的', '代', '码', '我的', '的代码']
  2. 防抖 (Debounce) :搜索框必须加 150-300ms 防抖,避免用户打字太快导致 Worker 任务堆积。
  3. 结果高亮 :搜索是毫秒级的,但千万别忘了在 UI 上用 <mark> 标签高亮匹配字符,这才是"体感"流畅的关键。
  4. 分片加载:搜索结果如果太多,只取前 20 条,配合滚动加载。

相关推荐
摸鱼的春哥1 小时前
专家实验让AI做战争决策,AI的选择太暴力了
前端·javascript·后端
明月_清风2 小时前
存储配额:用 navigator.storage.estimate() 预判浏览器什么时候会删你的数据
前端·indexeddb
漂流瓶jz10 小时前
BEM、OOCSS、SMACSS、ITCSS、AMCSS、SUITCSS:CSS命名规范简介
前端·css·代码规范
陈随易14 小时前
真的,你可以不用TypeScript
前端·后端·程序员
郑州光合科技余经理14 小时前
代码展示:PHP搭建海外版外卖系统源码解析
java·开发语言·前端·后端·系统架构·uni-app·php
唐璜Taro15 小时前
Vue3 + TypeScript 后台管理系统完整方案
前端·javascript·typescript
dustcell.15 小时前
haproxy七层代理
java·开发语言·前端
掘金酱15 小时前
「寻找年味」 沸点活动|获奖名单公示🎊
前端·人工智能·后端
患得患失94915 小时前
【前端】前端动画优化的核心
前端