Nuxt 3 个人站搜索实践:用 MongoDB 文本索引做轻量全文搜索
个人站不想一开始引入 Elasticsearch 时,可以先用 MongoDB 文本索引。本文记录文章集合索引设计、查询写法,以及中文分词限制下的补救办法。

作者
ZHOUYI
我的个人站文章量不大,搜索主要找标题、标签、摘要和少量正文关键词。单独维护 Elasticsearch 太重,于是先用已有的 MongoDB 做文本索引。它能快速跑通,但中文场景要提前管理预期:它更像关键词匹配,不是完整中文搜索引擎。
索引设计:只索引值得搜索的字段
我不建议把整篇 Markdown 原样塞进文本索引。更稳的做法是保存一份 keywords 字段,在发布文章时从标题、标签、摘要和正文里提取关键词,并用空格分隔。索引字段可以设置权重,让标题和标签更容易命中。
字段提取不必追求完美。我的做法是发布时把标题、标签、摘要和正文前几百字合并成一段纯文本,再用简单规则去掉 Markdown 标记。若文章有分类或系列名,也一并写入 keywords。这样搜索更贴近用户实际输入,也避免索引被无意义长文撑大。
await db.collection('articles').createIndex(
{ title: 'text', summary: 'text', tags: 'text', keywords: 'text' },
{ weights: { title: 10, tags: 6, summary: 3, keywords: 2 }, default_language: 'none' }
)查询:过滤发布状态,按相关度排序
在 Nuxt 3 的 server API 里,先清洗用户输入,去掉过长或特殊字符,再交给 $text。查询时只返回列表需要的字段,并用 textScore 排序。个人站建议限制条数,避免无意义的全量扫描。
const q = sanitizeQuery(input)
const cursor = db.collection('articles').find(
{ status: 'published', $text: { $search: q } },
{ projection: { title: 1, slug: 1, summary: 1, score: { $meta: 'textScore' } } }
).sort({ score: { $meta: 'textScore' } }).limit(20)接口层还要处理空关键词和异常。q 为空时直接返回空列表,不要进数据库;查询超时就记录日志并返回友好提示。个人站搜索不是核心链路,宁可降级,也别让一个慢查询拖慢整站。
中文分词限制:不要把它当中文搜索引擎
- MongoDB 文本索引对连续中文不友好,不能自动理解“前端性能优化”这类词。
- 写入时可以把关键词预处理成空格分隔,例如“前端 性能 优化 Nuxt”。
- 如果需要拼音、同义词、高亮和更复杂的相关度,后续再换 MeiliSearch、Typesense 或 Elasticsearch。
这套方案的价值是简单:数据还在 MongoDB,接口也能放进 Nuxt 服务端。搜索量小的个人站可以先用,等搜索需求变复杂再迁移。若担心数据库压力,可给热门搜索词加一层 Redis 缓存,但要注意过期时间,避免新文章迟迟搜不到。索引字段或权重变更后,要重建索引并观察慢查询。