三年前记的东西今天要用,路径还是"搜关键词 → 一屏结果里翻 → 打开确认"。翻到的那条往往只有参数,没有当时为什么这么定。存几秒,取十分钟,还不敢直接信。
问题不在工具。存是写入时付一次,取是每次访问都付,且随存量上升。多数人只优化存的那一侧——更快的输入法、更顺的目录、更花的模板;取的成本由每一次访问摊,没人给它记账,于是只涨不降。
1. 存与取是两笔不同的账
| 动作 | 成本发生时机 | 谁在付 | 是否随存量增长 | 有反馈吗 |
|---|---|---|---|---|
| 存 | 写入当下一次 | 写的人 | 不增长,每条固定 | 有,写完就安心 |
| 取 | 每次访问 | 未来的自己或别人 | 线性增长 | 没有,搜不到会以为"没记过" |
反馈不对称是关键:存有即时回报,取只有沉默失败。系统于是稳定地向"多存"倾斜,而不是向"好取"倾斜。
把两笔账并排放,结论自己会出来:存量到几千条量级时,一次取的平均成本已经明显高于一次存(按"每条存 30 秒、每次取 5–10 分钟、平均每条被取一到两次"这个量级估算,比值是三到二十倍)。这个比值随存量与复用次数继续放大,而存的动作永远只有那 30 秒。
一次典型取用的真实路径:
─── 目标:回答"上次那个限流为什么放在网关"
1. 搜「限流」 → 47 条
2. 加「网关」 → 9 条
3. 按时间排序,翻到目标 → 找到了
4. 打开:只有参数,没有判断依据
5. 回去翻聊天记录、重新查文档 ← 成本在这里爆掉
第 4 步暴露的不是检索问题:存的是结论,取的时候需要判据。这一条决定了后面所有小节的方向。
2. 检索失效的四个原因
| 原因 | 症状 | 怎么验证 | 处置 |
|---|---|---|---|
| 没有统一入口 | 同一件事散在 IM、文档库、本地文件 | 换一个库再搜一次,结果不同 | 定一个主库,其余只放链接 |
| 命名漂移 | 当时叫 A,今天叫 B | 搜旧名有结果,搜新名没有 | 建别名表,一条多入口 |
| 内容过期 | 记的是旧版本行为 | 打开后必须重新对文档 | 加 status 与复审日期 |
| 没有上下文 | 只有结论,没有适用条件 | 字都读得懂,就是不敢照做 | 补"当时的约束、放弃的方案、失效条件" |
四条里最贵的是第四条,因为它不会被"搜不到"暴露:搜到了、读完了、用错了才发现。前三条能在检索层修,第四条只能在写入层修。把第四条当检索问题处理,得到的结果是一堆越写越长的模板,而不是更好的记录。
// 别名表:一条记录,多个可搜入口,写在主库里而不是脑子里
├── 限流 → rate-limit/网关限流决策
├── 令牌桶 → rate-limit/网关限流决策
├── 熔断和限流的区别 → rate-limit/边界对照
└── WAF 与网关谁先拦 → rate-limit/部署位置
3. 三个层次,三种失败形态
| 层次 | 要回答的问题 | 失败形态 | 可观测信号 |
|---|---|---|---|
| 找得到 | 东西在不在 | 搜不到,于是重写一遍 | 无结果搜索率 |
| 找得快 | 要花多久 | 搜到 40 条,翻到第 20 条 | 复用时延 |
| 找到的是对的 | 能不能直接用 | 用了过期版本,事后才发现 | 过期条目占比、被纠正次数 |
多数人只修第二层:做目录、做双链、上标签。第二层天花板很低——存量翻倍,翻找时间只会更糟。第一层是入口问题,第三层是写作问题,都不是换检索工具能解的。
组织方式只有三种,选一种,别混:
| 组织方式 | 天然适合 | 失效点 | 换成另一种的代价 |
|---|---|---|---|
| 按项目 | 有明确交付期的活 | 项目结束后不再被打开 | 低,项目天然封闭 |
| 按时间 | 找回"我当时在想什么" | 记不住日期就无从下手 | 高,要重建索引 |
| 按主题 | 系统性回顾与写作 | 主题边界随认知移动 | 高,每次分裂都要迁移 |
混用的典型结果是两种都不好用:既找不到日期,也说不清归属。折中是一个主维度 + 一个可检索的面,例如按项目存、用 topic: 做面。
标签的熵增是必然的:每加一个标签,每条记录所属的命中集合就碎一层;三个标签之后,任何一个标签的检索结果都不再完整。标签是分面不是分类,价值随数量先升后降,拐点在几十个量级,不是一个可以无限扩的容器。
为什么标签只作用在第二层:它改变的只是候选集大小,既不改变"有没有这条记录",也不改变"这条记录对不对"。第一层靠入口,第三层靠写入时的判据,两者都发生在检索动作之外。
4. 索引、复用率与"不存"
手工索引一定过期。索引是存量的人工投影,存量变了投影不会自动更新,所以索引的前提是能从原文重建,且重建便宜到愿意定期做。重建的频率有一个自然刻度:每次批量改完命名或结构之后跑一次,而不是挂一个日历提醒——提醒会被忽略,变更之后的必要动作不会。
─── 最小可重建索引(每一项都能从原文重新算出)
project ← 目录或头部字段
status ← usable | stale | superseded
ttl ← 复审日期,到期进清理队列
aliases ← 该条在别名表里的全部叫法
─── 不要手工维护的东西
"重要程度""我的评分""完整目录树":无法从原文重算,必然腐坏
全文搜索匹配字符,不匹配意图。它擅长"我记得这里有个词",不擅长"我要找那段把取舍讲清楚的"。所以正文里必须出现你未来会搜的词:当时的约束、放弃的方案、谁提的要求、失效条件。这些词不是写给读者的,是写给检索的。
复用率是最诚实的度量:同一条被再次打开的次数。零次不是"备用",是负债——它占着检索结果的位置,让真会被用的那条更难被找到。这个数不需要埋点,打开记录本来就在编辑器或笔记应用的历史里;难的是接受它的结论:被反复打开的条目值得补全,一次都没打开过的说明当时的判断没有消费场景,而不是"总会有用"。定期清理比定期整理有效:整理只是重新排列,取用路径没变;清理减少存量,取用成本直接下降。
四个指标够用:
| 指标 | 怎么取 | 读法 |
|---|---|---|
| 复用时延 | 从"想用"到"打开正确那条"的分钟数 | 中位数上升=入口或命名坏了 |
| 无结果搜索率 | 搜索日志里零结果查询的占比 | 高说明缺条目或缺别名 |
| 过期条目占比 | status≠usable 的条数 / 总数 |
超过一定比例,整库不可信 |
| 二次打开率 | 被打开 ≥2 次的条目占比 | 衡量这个库有没有消费场景 |
"不存"也是检索策略的一部分。判断标准不是"以后可能有用",而是"有没有一个具体动作会来取它"。没有取用场景的记录,写得多好都只是把未来的检索空间弄脏。
5. 排错:六种"明明记过却找不到"
| 现象 | 真实原因 | 处理 |
|---|---|---|
| 搜关键词零结果 | 用了当时的叫法 | 补别名,或从项目目录反查 |
| 搜到了但不是那条 | 多个近义条目并存 | 合并成一条,其余指向链接 |
| 找到的版本已过期 | 没有 status / ttl | 加复审日期,过期进清理队列 |
| 只有结论,不敢用 | 写入时没记约束与失效条件 | 补"当时的判断",不只补结论 |
| 换工具后全丢 | 索引是手工的、不可重建 | 迁移前先保证能重新生成索引 |
| 越整理越难找 | 标签扩张,命中集合碎裂 | 砍标签,只留少数稳定分面 |
最后一条要单独说:整理有成就感,但不改变取用路径。判断一次整理值不值,只用一个数——整理之后,从想到用到打开正确那条,时间有没有降。
零结果查询是最便宜的一份体检报告,它的诊断顺序不该从"换工具"开始:
─── 无结果查询的诊断顺序
1. 把近 30 天的零结果查询原样导出来
2. 逐条问一句:是我没记,还是记了但叫法不同?
3. 叫法不同 → 补别名(一次性投入,长期生效)
4. 确实没记 → 进待写清单,按"有没有动作来取它"筛一遍
5. 记了但在别的库 → 入口问题,不是检索问题
6. 边界:什么时候不该建检索体系
| 场景 | 判断 | 更好的做法 |
|---|---|---|
| 存量少于几百条 | 全文搜索加时间排序就够 | 不建索引、不打标签 |
| 内容高度同质(同类工单、同类日志) | 检索靠字段过滤,不靠语义 | 结构化字段 + 数据库查询 |
| 只服务单次任务 | 用完即弃,无复用预期 | 不建库,原样归档 |
| 变化快于整理速度(舆情、行情) | 索引永远追不上 | 只保时间窗,过期即删 |
| 多人共享同一库 | 命名与状态无人负责 | 先定 owner 与 status 规则,再谈检索 |
| 只有自己在用 | 别人的命名习惯不构成成本 | 个人约定加全文搜索即可,不必上体系 |
// 建不建检索体系,先答三个问题
1. 同一个东西会被取用第二次吗? 不会 → 不建
2. 存量会不会超过"翻一屏能翻完"? 不会 → 全文搜索足够
3. 有没有人愿意负责命名与状态? 没有 → 先解决归属
一句话收口:检索体系的收益来自"同一个东西被取用多次",取用次数上不去时,任何结构性投入都是过度建设。
自测
- 为什么说"存与取是两笔不同的账"?取的那笔账由谁在付?
- 检索失效的四个原因里,哪一个不会被"搜不到"暴露出来?
- "找得快"这一层的天花板为什么很低?
- 手工索引为什么会必然过期?什么样的索引才允许存在?
- 为什么"定期清理"比"定期整理"更有效?
- 什么条件下,正式检索体系属于过度建设?