一个周末的优化实验,把3GB的SQLite数据库压成了10MB的二进制文件。这不是魔法,是把"够用就行"的工程哲学推到了极致。

作者维护的Taskusanakirja(简称tsk)是一款芬兰语-英语词典,核心功能是输入即搜索的增量查询。本质上这是个前缀搜索问题,标准解法是trie树。第一版用Go实现时,这套方案跑得很顺:对六位数级别的词条做基础优化——只返回前50到100个匹配结果,再把1-3个字符的组合全部预计算缓存——内存控制在60MB左右,个人重度使用一年都没感觉到延迟。

打开网易新闻 查看精彩图片

但芬兰语是高度黏着型语言。一个基础词可能有超过一百种词尾变化,而且这些变化不规则。更麻烦的是芬兰语的正字法极其规范,口语中的音变会如实反映在拼写上,基础词会随着词尾叠加而拉伸、变形、转音。初学者看到"Opiskelijassammekin on leijonan sydän"这种句子,大概率会卡在某个词上拆不开。这款工具的设计目标之一,就是帮学生找准切分点。

trie树在这里栽了。40万词条能塞进50MB内存,但4000万到6000万条变形词完全不是同一个量级。作者一度妥协:把变形词单独打包成带FTS(全文检索)的SQLite数据库,3GB一次性下载。能用,但体验糟糕。

转机来自一个更古老的数据结构——有限状态转换器(FST)。这东西在语音识别和拼写检查里用了很多年,但相对冷门。FST的核心思想是:用状态转移图共享前缀和后缀,把词典压缩成最小确定自动机。对于高度规则又高度变化的黏着语,这种结构恰好能吃掉重复的模式。

最终成果:10MB二进制文件,替代了3GB数据库。内存占用从"需要解释为什么下载这么大"变成了"用户根本感知不到存在"。查询延迟保持在同一水平——都是"感知不到"级别。

作者特意把数字都做了近似处理,因为精确数字不重要。关键认知是:有人用高度特化的静态数据结构,把内存开销砍到了原来的三百分之一。这个比例本身,比任何具体实现细节都值得记住。