跳到正文
艾影✦流浪

给 SQLite 加上中文全文搜索

约 2 分钟 5 次阅读

这是一篇演示文章,用来展示博客的排版与功能。你可以在后台编辑、替换或删除它。

英文文本可以按空格切词,中文不行。「全文搜索」这四个字,默认的 unicode61 分词器会把它当成一个整体,于是搜「搜索」什么也找不到。

trigram:把文本切成三个字一组#

SQLite 3.34 起,FTS5 内置了 trigram 分词器。它把文本切成重叠的三字片段:

全文搜索 → 全文搜 / 文搜索

查询时也按同样的方式切分,只要片段都能匹配上,就算命中。好处是不需要任何词典,对中英文混排同样有效。

CREATE VIRTUAL TABLE posts_fts USING fts5(
  title, excerpt, plain,
  content='posts', content_rowid='id',
  tokenize='trigram'
);

两个字怎么办#

三元组的代价是:少于三个字符的查询无法使用索引。对于「光影」「旅行」这样的双字词,程序会退回到 LIKE 查询。个人博客的文章数量有限,这样做完全够快。

结果排序#

FTS5 提供 bm25() 打分函数,可以给不同字段设置权重。标题命中比正文命中重要得多:

ORDER BY bm25(posts_fts, 8.0, 3.0, 1.0)

三个参数依次对应标题、摘要和正文。

保持索引同步#

用触发器在文章增删改时同步更新索引,业务代码完全不用关心:

CREATE TRIGGER posts_au AFTER UPDATE ON posts BEGIN
  INSERT INTO posts_fts(posts_fts, rowid, title, excerpt, plain)
    VALUES ('delete', old.id, old.title, old.excerpt, old.plain);
  INSERT INTO posts_fts(rowid, title, excerpt, plain)
    VALUES (new.id, new.title, new.excerpt, new.plain);
END;

试试右上角的搜索吧。

推荐阅读

评论

还没有评论。读完有想法的话,写在下面吧。