【免费下载链接】WindInput
清风输入法 | 轻量、快速、可定制的开源中文输入法,专为五笔和码表输入方案设计,支持全拼/双拼(Windows / macOS / Linux)
WindInput(清风输入法)是一款轻量、快速、可定制的开源中文输入法,专为五笔和码表输入方案设计,支持全拼/双拼,覆盖 Windows / macOS / Linux。它的"越用越懂你"背后,是一套基于嵌入式 KV 数据库 redb 的持久化层:用户词、词频统计、Shadow 候选调序规则,全部落在一个.redb单文件里。本文带你完整拆解这套设计的核心思路,无需阅读全部源码也能看懂它是怎么做的。
为什么选 redb?
输入法的学习数据有几个典型特点:
- 数据量小但写频繁:每次选词都要记录一次"用了哪个词";
- 需要崩溃安全:写一半断电,词库不能坏;
- 需要按前缀范围扫描:"打了
sh开头的码,要能列出所有sh…的用户词"; - 单文件可携带:备份、导入导出时直接拷走即可。
用 SQLite 当然也行,但 redb 是 Rust 原生的嵌入式 KV 引擎,零外部依赖、自带事务、key 有序,天然支持 range 扫描,和"词库 = 一组有序 KV"的模型严丝合缝。清风输入法的存储层 wind-store 就是围绕它构建的,是整个系统中最底层、无内部依赖的 crate。
设计演进过程记录在 docs/redesign/store.md,里面详细对比了旧版 Go 实现(bbolt)的问题,例如时间戳单位不一致、记录用 JSON 序列化偏臃肿等,Rust 重写时一并修正。
扁平表 + 复合 key:redb 里没有"嵌套目录"
redb 不支持数据库嵌套(不像 bbolt 有 bucket 树),所以用扁平 table + 复合 key来表达层次。核心设计是:
key 用
\0做字段分隔符,把"方案 id"编进 key 前缀,靠 key 的字典序天然实现按方案隔离 + 前缀范围查询。
主要表一览(定义见 store.rs):
| 表名 | key 编码 | 存什么 |
|---|---|---|
user_words | 方案\0输入码\0词语 | 用户词(自己造的词) |
temp_words | 同上 | 临时学习词(自动造词) |
freq | 同上 | 词频:{count, last_used}定长 12 字节 |
shadow | 方案\0输入码 | Shadow 调序/删除规则 |
phrases | 输入码\0文本 | 全局短语(不分方案) |
draft_words | 方案\0输入码\0词语 | 自动造词草稿层(待验证) |
stats_daily/meta | 日期 / 固定键 | 打字统计 / 版本号、设备 ID |
这个编码是范围查询的基础:查某方案下某输入码的所有词,就是一次range前缀扫描;短语刻意不带方案前缀,因为"手机号、住址"这类短语与用五笔还是拼音无关。
用户词:定长二进制比 JSON 香
每条用户词是一条记录,字段包括weight(权重)、count(使用次数)、created_at(创建时间)、boundary(音节边界)等。设计上有几个值得学习的点(user_words.rs):
- code 和 text 存在 key 里,value 只放定长二进制字段。词库动辄十万条,JSON 序列化的体积和解析开销都是浪费;
- 字段演进走"惰性升级":记录从 16 字节长到 28 字节,旧记录读出来缺的字段按默认值处理,不需要写迁移脚本;
- 流式遍历不物化:遍历设置页词库列表时,回调直接借用 redb 页里的字节(
UserWordView),只对真正要保留的少数几条做拷贝,避免"翻一页先创建 38 万个 String"。
词的学习规则也很直观:重复添加同码同词取最大权重;每次选中该词count + 1,达到阈值就提升权重。
词频系统:与权重彻底解耦
这是整个设计中含金量最高的决策,权威文档是 docs/redesign/frequency.md:
旧版把"使用频率"算成一个 boost加到词的 weight 上,但词库权重量级巨大(拼音可达千万级),有上限的 boost 加上去几乎不起作用——"用了几十次还是排不上去"。新版彻底推翻:
| 概念 | 含义 | 作用 |
|---|---|---|
| 权重 weight | 词库自带 | 默认排序维度 |
| 词频 frequency | 只记真实使用数据{count, last_used} | 独立的排序维度 |
词频只在 freq.rs 里存 12 字节(count u32 + last_used i64),排序时才作为独立维度参与,绝不修改 weight。不同方案用不同策略:
- 码表方案:用过的词置顶(used-first),可选"一次到顶"(MRU)或"逐次提升"(count 累积)两种策略;
- 拼音方案:按半衰期衰减分参与排序——
(base_scale × log2(count+1)) × exp(-ln2 × 时长 / 半衰期),最近用过的词上浮,久未用自然回落,且整句候选恒定豁免不被词频挤下。
一句话总结:码表的"用过"是永久的,拼音的"用过"是会褪色的。
Shadow 规则:候选置顶与删除的"影子层"
打错了想置顶某个候选、或者屏蔽一个永远用不上的候选?这些手动干预就是 Shadow 规则,实现见 shadow.rs:
- 按"方案 + 输入码"分组,记录
pinned(置顶到某位置)和deleted(屏蔽)两类规则; - 置顶优先于删除,新规则插队首(LIFO),语义简单可预测;
cand_id精准去重是个细节亮点:像"今天日期"这种动态候选,文本每天都不一样,只比文本会导致规则"删不掉、恢复默认恒灰显",所以引入候选稳定 id 作为匹配键。
Shadow 的妙处在于它是排序后的应用点而非数据层——词库本身不动,规则单独存,随时可恢复默认。
工程细节:缓存回收、热替换与版本迁移
redb 用得好不好,差距在细节。wind-store 的 AGENTS.md 把几个"血泪教训"写得很直白:
- 唯一安全入口
with_db:所有读写必须经这个闭包,它持锁并检查暂停态,避免绕过 pause/resume 语义; - 页缓存是"只涨不落"的高水位:redb 的读缓存实测 19 万词的库全表扫描后会常驻 41 MB 不还。解法是双档回收——批量写完成后立即
drop_page_cache(关库重开一次,约 6 ms);全表扫描只做标记,等库空闲 3 秒后由后台线程回收,绝不打扰按键链路。相关测试见 tests/redb_cache_high_water.rs; - pause / resume 释放文件锁:Windows 下原子替换
.redb文件前必须解锁文件,这对热更新很关键; - 版本迁移框架:
meta表存schema_version,全新库直接打版本号,旧库按版本链逐步升级,当前CURRENT_VERSION = 1(store.rs)。
动手验证
wind-store不依赖任何平台特定代码,任意系统上都能直接跑测试(临时.redb文件建在系统临时目录):
cargo test -p wind-store配套的架构文档 docs/architecture/ 与 docs/redesign/store.md 记录了从 Go 到 Rust 重写的完整决策链,想深入"为什么这么设计"的同学值得一读。
小结
- redb 用扁平表 + 方案前缀复合 key优雅表达了"按方案隔离 + 前缀扫描"的词库模型;
- 定长二进制 value + 惰性字段升级,让十万级词库的小而快成为可能;
- 词频与权重彻底解耦,是修掉"学了不灵"顽疾的关键;
- Shadow 作为排序后的影子层,让用户的手动干预可存、可查、可恢复;
- 缓存回收、文件锁热替换、版本迁移三件套,把嵌入式数据库的生产级坑填平了。
这套设计对任何需要"本地学习数据 + 崩溃安全 + 前缀检索"的桌面应用都有很强的参考价值。
【免费下载链接】WindInput
清风输入法 | 轻量、快速、可定制的开源中文输入法,专为五笔和码表输入方案设计,支持全拼/双拼(Windows / macOS / Linux)
相关推荐
清风输入法 WindInput 图形设置详解:热键、词库与智能过滤一图流配置
清风输入法 WindInput 图形设置详解:热键、词库与智能过滤一图流配置 清风输入法(WindInput)是一款轻量、快速、可定制的开源中文输入法,专为五笔
如何用深蓝词库转换清理输入法词库:12 种过滤规则实战指南(词频/长度/中英文去重)
如何用深蓝词库转换清理输入法词库:12 种过滤规则实战指南(词频/长度/中英文去重) 深蓝词库转换 是一款开源免费的输入法词库转换程序,内置 12 种过滤规则,
桌面应用CLI开发工具如何用世界最小CSS框架lit.css快速构建现代化网站
如何用世界最小CSS框架lit.css快速构建现代化网站 在当今追求极致性能的Web开发世界中,lit.css以其仅395字节的超轻量级体积脱颖而出,成为世界上
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考