站内搜索:原理与配置#
本页记录本站搜索是怎么工作的——机制、产物、限制与配置位置。 一句话:搜索完全在浏览器里跑,没有服务端查询;索引在构建时生成, 由浏览器下载后现场建立。
一、为什么中文要特别处理#
本站搜索引擎是 lunr.js(由 MkDocs Material 提供)。lunr 是英文分词思路: 按空白与标点切词,再对词做词干化。中文没有空格,因此如果直接把中文丢给它, 整个句子会被当成一个词,搜索基本失效。
Material 的做法不是换引擎,而是在构建期把中文预先切好,再用一个特殊字符
把词与词标记开——这个字符就是零宽空格 U+200B(下称 \u200b,肉眼不可见)。
二、构建时发生了什么(jieba 切词 + 零宽空格)#
本项目使用 MkDocs Material 9.7.7,其 search 插件内置 jieba 中文分词
(material/plugins/search/plugin.py;配置项 jieba_dict、jieba_dict_user)。
构建每个页面段落时,它会把连续的汉字串交给 jieba.cut(),再用 U+200B 连接回去:
原文: 关于成立一个编程论坛的想法
索引里:关于\u200b成立\u200b一个\u200b编程\u200b论坛\u200b的\u200b想法
同时,索引的 config.separator 被设成包含 \u200b 的字符类:
[\s\u200b\u3000\-、。,.?!;]+
即:空白、零宽空格、全角空格、中日标点都是分隔符。于是 jieba 切出来的词 就成了真正的检索单位,标点也自然分词(这也是「简单、自洽、利他」能被拆成三个词的 原因)。
在
search_index.json里该正则是以转义形式存放的(写作[\\s\\u200b…]+), 上面给出的是它被解析后的形态。所以
mkdocs.yml里那句注释「jieba is installed → Chinese segmentation works」 对这个版本是准确的:jieba 由 search 插件自己调用,不是靠外部钩子。
三、索引产物#
| 项 | 值(2026-09-18) |
|---|---|
| 文件 | site/search/search_index.json |
| 大小 | 约 738 KB(未压缩) |
| 粒度 | 按标题切分的段落,不是整页 |
| 条目 | 274 段 / 27 页 |
| 预构建索引 | index: null → 没有,由浏览器现场构建 |
| 文件名指纹 | 无(每次构建同名覆盖) |
结构是两部分:config(lang、separator、pipeline、fields)+ docs(每段的
location / title / text)。location 里的中文是百分号编码的,例如
wiki/pages/%E4%B8%89%E5%85%AC%E7%90%86%E6%BA%AF%E6%BA%90/。
四、浏览器里发生了什么#
- 打开任意页面,Material 异步请求
search/search_index.json; - 首次搜索时,用 lunr.js 依
config现场建立索引——这就是搜索框里 「正在初始化搜索引擎」的含义; - 输入查询 → 查询串只按
separator切分(浏览器端没有 jieba); - 命中按段落返回,支持结果高亮(
search.highlight)与分享链接 (search.share,形如?q=关键词)。
五、由此推出的实际限制(重要)#
- 查询要是一个「词」,而不是一句话。 索引里存的是 jieba 切出来的词;浏览器端 只按分隔符切查询,所以粘一整句没有分隔的中文进去,它仍然只是一个 token, 必须与索引中的某个词完全一致才命中。
- 通常能命中:
卡尔维诺、自洽、公理、荣耀经、利他 - 多半搜不到:把整句原文粘进去
- 专有名词可能被 jieba 切错。 人名、书名、曲名、自造词(如「三公理」「肾后」 「老彼得」)若切错,就搜不到。补救办法是给分词器提供词典:
plugins:
- search:
jieba_dict: tools/jieba_dict.txt # 替换主词典(谨慎)
jieba_dict_user: tools/jieba_user.txt # 追加用户词(推荐)
config.lang目前解析为['en'](只装英文词干),与主题的language: zh并不同步。对汉字 token 无害,但若要做更地道的中日韩处理, 可显式配置 search 的lang(Material 随包提供lunr.zh.min.js)。prebuild_index默认关闭。 打开(prebuild_index: python|node)能把 lunr 索引预构建进 JSON、省下客户端 CPU,但文件会更大——在带宽受限时反而更慢, 需按实际链路权衡。- 搜索是纯客户端的:没有服务端检索,整包索引都会下发给访客。
六、运维注意#
search_index.json不带文件名指纹,所以它必须可被重新校验;若服务器不发Cache-Control,浏览器可能复用旧索引(见DEPLOY.md的缓存策略一节)。- 索引体积随页面数增长;中文经 jieba + 零宽空格处理后偏大,因为每个词都要多付 3 字节的 U+200B。
- 排障口诀:搜索框一直停在「正在初始化搜索引擎」= 索引没有下载完, 而不是「搜索坏了」。先在浏览器控制台看该请求的状态与耗时。
七、配置位置一览#
# mkdocs.yml
theme:
language: zh # 界面语言
features:
- search.highlight # 结果高亮
- search.share # 生成 ?q= 分享链接
plugins:
- search # 可选项:lang / separator / jieba_dict /
# jieba_dict_user / prebuild_index / indexing / fields
搜索索引由 tools/build_site.py 每次构建时重新生成,不是手工维护的文件,
也不在 wiki/ 手工层内。
参见#
本页创建于 2026-09-18,最后更新于 2026-09-19。