💡 小细节:使用 filter(Post.is_published.is_(True)) 比 == True 更符合 SQLAlchemy 的规范,也能避免某些数据库布尔类型(比如 Postgres 的 BOOLEAN)在比较时发生隐式转换问题。
1.2 搜索结果高亮 + 摘要截取
直接展示整篇文章内容太臃肿,最好的做法是:优先使用文章已有的摘要,如果没有则截取正文中包含关键词的部分,并对关键词高亮。下面的高亮函数在截取时会围绕关键词前后取上下文,比直接截取前 200 字更能体现相关性。
在模板里要记得为高亮添加样式,并且优先展示文章摘要:
⚠️ 安全提醒:模板里使用了 | safe 过滤器,因为 highlight_excerpt 返回的是包含 <mark> 标签的 HTML。不过这个函数中所有用户输入都已经过处理:查询关键词被 re.escape() 转义,原始文本也先用 striptags 去掉了 HTML 标签,因此不存在 XSS 风险。
2. 进阶过滤:分类与时间筛选
大多数博客不需要太复杂的布尔查询,但加上分类筛选和时间范围(近 7/30 天或指定起始日期)会非常实用。我们可以在原有搜索基础上补充这两个维度。
路由代码升级如下:
在模板顶部添加一个筛选栏,使用 GET 表单,这样筛选条件可以随 URL 分享:
3. 优化方案:PostgreSQL 内置全文检索
LIKE/ilike 虽然简单,但有两个硬伤:
- 无法利用索引(除非只用
xxx%前缀匹配,但博客通常需要任意位置匹配),文章超过 1 万篇后速度会明显下降; - 没有分词能力,比如搜索“道满博客”,匹配不到“道满的博客”。
如果你的博客运行在 PostgreSQL 上(个人博客强烈推荐,免费功能又全),就可以使用它的内置全文检索解决这两个问题。
3.1 基础版:使用 chinese 配置
PostgreSQL 从 12 版本开始内置了中文分词配置(虽然分词质量一般,但能用)。用法如下:
3.2 生产环境优化建议
① 添加 GIN 索引,查询速度提升几十倍
在 Post 模型中添加一个计算列存储搜索向量,并为它创建 GIN 索引:
⚠️ 计算列在 SQLite 中不支持。如果开发环境使用 SQLite,可以将这段代码脱敏注释掉,生产环境再启用。
② 给不同字段设置权重
标题的相关性应该比正文更高。PostgreSQL 的 setweight 函数可以做到:
权重由高到低为 A > B > C > D,ts_rank 会自动计算加权分数,让标题更匹配的文章排在前列。
③ 使用 jieba 分词改进中文处理
PostgreSQL 内置的中文分词比较粗糙,比如“人工智能”会被拆成“人”“工”“智”“能”。如果需要更好的分词效果,可以考虑:
- 在插入/更新文章时,使用 Python 的
jieba分词生成 tsvector,再存入数据库; - 或者安装 PostgreSQL 插件
zhparser,它能借助 SCWS 分词引擎提供更准确的中文分词。
这两条路的投入产出根据你的博客规模选择即可。
4. 方案总结与选型建议
通过以上三种方案,你可以根据博客的规模灵活选择:
所有代码示例都基于你熟悉的 Flask + SQLAlchemy 技术栈,可以直接迁移到实际项目中。
🔗 扩展阅读

