MongoDB 全文检索

MongoDB 全文检索(Full-Text Search)完全指南

核心结论$text 索引 + 聚合管道 是 MongoDB 内置全文检索的 唯一推荐方式,支持 多语言、权重、排序、短语、高亮,性能媲美 Elasticsearch(中小规模)。


一、$text 索引 vs 其他方案

方案推荐度适用场景
$text 索引5 stars中小规模(< 1000万文档)、快速集成
Atlas Search5 stars大规模、复杂搜索、云原生
Elasticsearch4 stars超大规模、实时分析、复杂查询
正则 $regex1 star仅简单匹配,性能差

二、创建 $text 索引(一键开启)

// 单字段
db.articles.createIndex({ title: "text" })

// 多字段 + 权重
db.articles.createIndex(
  {
    title: "text",
    content: "text",
    tags: "text"
  },
  {
    weights: {
      title: 10,
      content: 5,
      tags: 1
    },
    name: "article_text_index",
    default_language: "chinese"  // 或 english, spanish 等
  }
)

权重title 匹配得分是 content 的 2 倍


三、基本搜索语法

需求查询写法
关键词{ $text: { $search: "MongoDB 性能" } }
短语{ $text: { $search: "\"快速入门\"" } }
排除{ $text: { $search: "MongoDB -备份" } }
多词 OR{ $text: { $search: "索引 优化" } }
// 搜索包含 "MongoDB" 但不包含 "备份"
db.articles.find({
  $text: { $search: "MongoDB -备份" }
})

四、得分排序 + 投影(必须)

db.articles.find(
  { $text: { $search: "性能优化" } },
  {
    score: { $meta: "textScore" },  // 获取匹配得分
    title: 1,
    excerpt: 1,
    _id: 0
  }
)
.sort({ score: { $meta: "textScore" } })  // 按相关度排序
.limit(10)

输出

{
  "title": "MongoDB 索引优化实战",
  "excerpt": "通过覆盖索引提升 100 倍性能...",
  "score": 2.5
}

五、高级搜索技巧

1. 多语言支持

// 创建索引时指定语言
default_language: "chinese"

// 覆盖多语言字段
db.articles.createIndex({
  title_en: "text",
  title_zh: "text"
}, { default_language: "none" })

2. 短语 + 模糊

// 精确短语
{ $text: { $search: "\"MongoDB 教程\"" } }

// 模糊(自动分词)
{ $text: { $search: "MongoDB 教程" } }

3. 大小写与标点

$text 忽略大小写、标点,支持 词干提取(stemming)

// 以下都匹配
"mongodb", "MongoDB", "MONGODB"
"running", "run", "ran"

六、结合聚合管道(推荐)

db.articles.aggregate([
  // 1. 全文搜索
  { $match: { $text: { $search: "性能优化" } } },

  // 2. 投影得分
  {
    $project: {
      title: 1,
      excerpt: { $substr: ["$content", 0, 200] },
      score: { $meta: "textScore" }
    }
  },

  // 3. 排序
  { $sort: { score: { $meta: "textScore" } } },

  // 4. 分页
  { $skip: 0 },
  { $limit: 10 }
])

七、搜索高亮(自定义实现)

// 服务端高亮函数
function highlight(text, keyword) {
  const regex = new RegExp(`(${keyword})`, 'gi');
  return text.replace(regex, '<mark>$1</mark>');
}

// 查询 + 高亮
const results = await db.articles.find(
  { $text: { $search: "MongoDB" } },
  { title: 1, content: 1, score: { $meta: "textScore" } }
)
.sort({ score: { $meta: "textScore" } })
.limit(5)
.toArray();

results.forEach(doc => {
  doc.highlight = highlight(doc.content, "MongoDB");
});

八、性能优化

优化点建议
索引字段选择只索引 title, content, tags
权重合理高权重字段放高分
避免全表扫描结合其他条件 $match
覆盖索引投影字段在索引中
// 覆盖查询(totalDocsExamined: 0)
db.articles.find(
  { $text: { $search: "索引" } },
  { title: 1, _id: 0, score: { $meta: "textScore" } }
)
.sort({ score: { $meta: "textScore" } })
.explain()

九、限制与注意事项

限制说明
每个集合只有 1 个 $text 索引需合并字段
不支持部分匹配mongo* → 用 $regex
不支持排序字段不能在 sort 中用 $text
不实时写入后稍有延迟

十、Node.js + Mongoose 实现

// Schema
const articleSchema = new Schema({
  title: String,
  content: String,
  tags: [String],
  lang: { type: String, default: 'chinese' }
});

// 创建索引
articleSchema.index(
  { title: "text", content: "text", tags: "text" },
  { weights: { title: 10, content: 5 }, default_language: "chinese" }
);

// 查询
const results = await Article.find(
  { $text: { $search: "性能优化" } },
  { score: { $meta: "textScore" } }
)
.sort({ score: { $meta: "textScore" } })
.limit(10);

十一、Atlas Search(云原生增强版)

// Atlas 专用 $search 阶段
db.articles.aggregate([
  {
    $search: {
      index: "default",
      text: {
        query: "MongoDB 性能",
        path: ["title", "content"]
      },
      highlight: { path: "content" }
    }
  },
  { $limit: 10 },
  { $project: { title: 1, highlight: { $meta: "searchHighlights" } } }
])

优势:支持 同义词、自动补全、facet、地理搜索


十二、终极案例:博客搜索系统

// 1. 创建索引
db.posts.createIndex(
  {
    title: "text",
    content: "text",
    tags: "text"
  },
  {
    weights: { title: 10, content: 3, tags: 5 },
    default_language: "chinese"
  }
)

// 2. 搜索 API
app.get('/search', async (req, res) => {
  const { q, page = 1, limit = 10 } = req.query;
  const skip = (page - 1) * limit;

  const results = await db.posts.aggregate([
    { $match: { $text: { $search: q } } },
    {
      $project: {
        title: 1,
        excerpt: { $substrCP: ["$content", 0, 200] },
        tags: 1,
        score: { $meta: "textScore" }
      }
    },
    { $sort: { score: { $meta: "textScore" } } },
    { $skip: skip },
    { $limit: parseInt(limit) }
  ]).toArray();

  res.json({ results, total: results.length });
});

总结:全文检索黄金三步

步骤命令
1. 创建索引createIndex({ field: "text" }, { weights })
2. 搜索{ $text: { $search: "关键词" } }
3. 排序.sort({ score: { $meta: "textScore" } })

你现在可以:

// 一行开启全文搜索
db.collection.createIndex({ content: "text" })

把你的搜索需求告诉我,我帮你写完整方案:

  1. 搜索字段(标题、内容、标签?)
  2. 语言(中文?英文?)
  3. 是否需要高亮、分页、同义词?

回复 3 个关键词,我生成:索引 + 查询 + 高亮 API!

文章已创建 2371

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部