为 Pelican 博客加入搜索功能

Category 碎碎念

在目前的博客生态圈中,静态博客占了相当大的比例。静态博客因为足够轻量、便于备份和迁移而受到包括我在内的许多用户喜欢,但由于静态博客没有数据库,在组织内容上就不免有所不足,这就涉及到题中所说的搜索功能了。为静态博客部署搜索功能比较麻烦,一个稍简单的方法就是借于「必应」「谷歌」等搜索引擎的 API,用它们来搜索站内的内容,但是这种方法的效果并不好,如果网页还未被收录或是相应头键字在网页中的占比太小,就很难搜索到目标信息。另一种方法就是在站内建立本地的搜索,例如 Hexo 等博客框架都提供了相应的插件,在本地生成搜索匹配所需的文件,将其一并推送至服务器实现全站搜索,这种方法的兼容性、准确性都要更好,也是我选择的方案。

Pelican 也有类似的搜索插件 pelican-plugins/search,它主要是借助了 Stork 来实现搜索功能。Stork 在官方文档中指出,它可以用于为静态站点构建关速美观的搜索接口,所以理应可以用于所有类型的静态博客,我不了解其他博客框架是否使用了这个工具,但不得不提其搜索体验非常不错,十分值得一试。

安装 Stork

安装 C++ 生成工具

Stork 是基于 Rust 构建的工具,需要使用 Rust 的包管理器 Cargo 安装,若是在 macOS 或 Linux 系统上,直接按照官方文档给出的方法安装即可,而在 Windows 上就会比较麻烦,我在这里介绍一下 Windows 的操作方法。

 Note 后文所涉及的操作系统都是 Windows 10 系统,终端指的是 Windows 终端(Windows Terminal)。

首先,在 Windows 上,Rust 需要某些 C++ 生成工具,可以选择安装 Visual Studio 或仅安装 Microsoft C++ 生成工具。安装 Visual Studio 的方法非常简单(推荐),按下不表,若仅安装 Microsoft C++ 生成工具,可以在终端中输入

winget install Microsoft.VisualStudio.2022.BuildTools

由于 winget 下载速度感人,实在不推荐这种方法。

在安装好 Visual Studio 后,在开始界面搜索并打开 Visual Studio Installer,选择 修改 - 使用 C++ 的桌面开发,等待安装完成。

Visual Studio

安装 Rust

Rust 也可以使用 winget 安装,命令很简单:

winget install rustup

但是不太好用,所以我还是选择到 Rust 官网下载。下载完成后打开安装程序,弹出的是命令行窗口,默认安装在 C:\Users 路径下的目录中,如果不需要额外的设置,键入 1 后按回车即可。

但由于 C 盘空间不太够了,我需要修改一下安装的路径,在目标路径下创建以下两个文件夹并新建环境变量:

CARGO_HOME: E:\RUST\.cargo
RUSTUP_HOME: E:\RUST\.rustup

PATH 中添加变量 %CARGO_HOME%%RUSTUP_HOME%%CARGO_HOME%\bin,然后再打开安装程序,默认路径就已经改变,键入 1 按回车安装。

Rustup metadata and toolchains will be installed into the Rustup
home directory, located at:

  E:\RustT\.rustup

This can be modified with the RUSTUP_HOME environment variable.

The Cargo home directory is located at:

  E:\Rust\.cargo

This can be modified with the CARGO_HOME environment variable.

The cargo, rustc, rustup and other commands will be added to
Cargo's bin directory, located at:

  E:\Rust\.cargo\bin

安装完成后,在终端中输入 cargo --version 理应输出版本信息。

通过 Cargo 安装 Stork

虽然安装好了 Cargo,但不出意外的话,与其他包管理器类似,从官方的源下载内容的速度非常之慢,所以需要修改配置使用镜像源。

.cargo 目录下创建文件 config.toml,写入以下内容:

[source.crates-io]
replace-with = 'ustc'

[source.ustc]
registry = "git://mirrors.ustc.edu.cn/crates.io-index"

就使用了科大的镜像源,然后在终端中使用以下命令安装 Stork:

cargo install stork-search --locked

最后可以使用 stork --version 验证是否成功安装 Stork。

部署 Pelican Search

安装好 Stork 后的步骤就很简单了,在 Pelican 的 Python 环境中安装插件:

python -m pip install pelican-search

然后在 Pelican 设置中的 PLUGINS 引入 search,在主题的模板文件(一般是 base.html)中引入 Stork CSS 的 CDN(当然也可以改写后自己部署):

<link rel="stylesheet" href="https://files.stork-search.net/basic.css" />

以及 JavaScript:

<script src="https://files.stork-search.net/releases/v1.5.0/stork.js"></script>
<script>
    stork.register("sitesearch", "{{ SITEURL }}/search-index.st")
</script>

最后就可以在设计的搜索区域通过以下方式调用 Stork 搜索了:

Search: <input data-stork="sitesearch" />
<div data-stork="sitesearch-output"></div>

 Warning 以上 CSS 应在页面的头部,例如 <head> 中引入,而 JavaScript 则应在 <body> 的尾部引入。这是因为 HTML 文件是自上至下顺序执行的,如果加载 JavaScript 的位置靠前,比如在 <input data-stork="sitesearch" /> 元素之前引入,在执行时该元素还未生成,就会找不到匹配的搜索框,提示没有 query selector `input[data-stork="sitesearch"]`,导致 Uncaught StorkError

Pelican Search 的设置项

pelican-search 的设置项只有两项,一项 SEARCH_MODE 设定从 Markdown 文件建立索引还是从 HTML 建立索引,SEARCH_HTML_SELECTOR 可以用于指定从 HTML 的哪些内容中建立索引。但 Stork 的设置项不止这些,将其整合进 pelican-search 应该也不太难,留到以后有精力的时候尝试一下。

我浏览了一下 Stork 官方文档中的内容,发现了很多很有意思的东西。例如 minimum_indexed_substring_length 一项设置了建立索引的匹配项最短长度,默认值为 3,通俗来讲就是长于 3 的单词才会用于建立索引,那么在搜索时也需要起码键入 3 个字母才有结果。但这种做法对于中文来说就存在很大的问题,中文中最普遍的是双字词,所以文档中也提到 minimum_index_ideographic_substring_length 一项设置,默认值是 1,对于 CJK 字符而言,长于 1 的词就可以建立索引。可惜在我的试验中这个设置貌似并没有效果,在我使用汉字搜索时,也必须输入 3 个汉字才有结果,若要搜索双字词,只好用两个汉字加上空格的方法将就一下。除了这个问题之外就是使用中文搜索的精度不高,很难找到匹配项,所以 Stork 的最大不足其实就在于对中文的支持不好。据作者的消息,他也很希望能够提高 Stork 在中文搜索上的表现,可以期待一下后续的更新。

再来说说 Stork 的优点,那就是「快」。Stork 搜索的速度特别快,不论是汉字还是字母,击入三个字符秒出搜索结果,这一点的体验就特别好。另外 Stork 还支持包括英语在内的多种欧洲语言的词根检索,例如输入「get」,它亦能返回「getting」的检索结果,这个功能对于静态站点而言可谓强大。如果是英文语境下,Stork 搜索精度高、速度快、支持词根检索,简直是最为优雅的静态站点搜索插件,也期待一下后续它能否在中文搜索上也能提供如此流畅的体验。

 Note 不知是我的原因还是 Stork 的问题,生成的索引文件巨大,足足有 16 MB,完全不能在网页上使用。于是我花了一整天的时间升级 Nginx 并配置上了 Brotli 压缩传输,压缩后只有大约 900 KB 了,加载速度大大提升。


References