AustinDatabases

MongoDB 全文索引 与 展示查询数据的一部分,提高性能

❝

开头还是介绍一下群,如果感兴趣PolarDB ,MongoDB ,MySQL ,PostgreSQL ,Redis, OceanBase, Sql Server等有问题,有需求都可以加群加群请联系 liuaustin3 ,(共3400人左右 1 + 2 + 3 + 4 +5 + 6 + 7 + 8 )(1 2 3 4 5 6 7 8群已经爆满  9群 为纯聊天群,默认不加入不得发广告,自己公众号文章链接等,发一次直接踢,默认加入8群,开10群PolarDB专业学习群115+)

MongoDB 到底支持不支持全文索引,回答是支持,但是怎么使用,使用中有什么问题,为什么有的人说,或者谣传,使用MongoDB 的全文索引后,还是要使用ES。

今天我们说说这个事情,首先我们要确认一点MongoDB 自 2.4 版本(2013年)引入全文索引实验性支持,并于 2.6 版本(2014年)正式将其作为核心功能内置并默认开启。无论是 MongoDB 7.0 还是最新的 8.0 版本,均原生、完整地支持本地自建环境下的全文索引(Text Index)功能。用户无需依赖任何外部组件,即可直接在自建集群中创建和检索文本索引。

第一,一个集合只能拥有一个全文索引,在多个字段的情况下,全文索引可以覆盖多个字段,将这些KEY VALUE 放入到一个全文索引中。在创建全文索引会对文本进行分词,最后一个事情就是,写性能的损耗,全文索引的底层数据结构相对复杂,其构建和更新的开销高于普通的B-TREE的单字段索引,因此在高频写入的场合要谨慎操作。


test_search_db> db.articles.drop();
true
test_search_db> 

test_search_db> print("开始生成 10 万条数据,请稍候...");
| 
| const totalRecords = 100000;
| const batchSize = 5000; // 每 5000 条数据批量提交一次
| let bulk = db.articles.initializeUnorderedBulkOp();
| 
| // 词库:用于随机组合生成文本
| const keywords = ["MongoDB", "Database", "AI", "Cloud", "Performance", "Index", "Query", "Optimization", "Full-text Search", "Developer", "Java", "Python", "Node.js", "Cluster", "Scaling", "Big Data", "Analytics"];
| const verbs = ["improves", "accelerates", "transforms", "simplifies", "manages", "secures", "analyzes", "powers"];
| const readyText = ["This article explores the advanced features of modern technologies.", "A deep dive into indexing strategies and best practices.", "How to build scalable applications with high availability.", "An introductory guide for developers and architects."];
| 
| function getRandomElement(arr) {
|     return arr[Math.floor(Math.random() * arr.length)];
| }
| 
| function generateRandomString(wordCount) {
|     let sentence = [];
|     for (let i = 0; i < wordCount; i++) {
|         sentence.push(getRandomElement(keywords));
|         if (i % 3 === 0 && i > 0) sentence.push(getRandomElement(verbs));
|     }
|     return sentence.join(" ") + ". " + getRandomElement(readyText);
| }
| 
| // 3. 循环生成并分批插入
| for (let i = 1; i <= totalRecords; i++) {
|     // 随机生成标题、摘要和正文,确保里面包含我们要搜索的关键词
|     let title = `${getRandomElement(keywords)}${getRandomElement(verbs)}${getRandomElement(keywords)}`;
|     let summary = generateRandomString(8);
|     let content = generateRandomString(30); // 正文较长
| 
|     bulk.insert({
|         article_id: i,
|         title: title,
|         summary: summary,
|         content: content,
|         views: Math.floor(Math.random() * 10000),
|         createdAt: new Date(Date.now() - Math.floor(Math.random() * 10000000000))
|     });
| 
|     // 达到批次大小,执行写入并重置 bulk
|     if (i % batchSize === 0) {
|         bulk.execute();
|         bulk = db.articles.initializeUnorderedBulkOp();
|         print(`已写入 ${i} 条数据...`);
|     }
| }
| 
| // 检查是否有剩余未提交的数据
| if (totalRecords % batchSize !== 0) {
|     bulk.execute();
| }
| 
| print("数据填充完毕!当前总数据量:", db.articles.countDocuments());
开始生成 10 万条数据,请稍候...
已写入 5000 条数据...
已写入 10000 条数据...
已写入 15000 条数据...
已写入 20000 条数据...
已写入 25000 条数据...
已写入 30000 条数据...
已写入 35000 条数据...
已写入 40000 条数据...
已写入 45000 条数据...
已写入 50000 条数据...
已写入 55000 条数据...
已写入 60000 条数据...
已写入 65000 条数据...
已写入 70000 条数据...
已写入 75000 条数据...
已写入 80000 条数据...
已写入 85000 条数据...
已写入 90000 条数据...
已写入 95000 条数据...
已写入 100000 条数据...
数据填充完毕!当前总数据量: 100000

在插入完数据后,我们需要针对数据进行验证和创建索引。

test_search_db> show collections;
articles
test_search_db> db.articles.find().limit(1);
[
  {
    _id: ObjectId('69fe22f484970425839df8a3'),
    article_id: 1,
    title: 'Analytics manages Index',
    summary: 'Java Node.js Optimization Index transforms Database Cloud Performance manages Python. An introductory guide for developers and architects.',
    content: 'Database Python Query Cloud simplifies Java Python AI analyzes Scaling AI Analytics improves Python Database Developer powers Performance Node.js Database improves Java Full-text Search Java improves Index Scaling Performance transforms Node.js Analytics Cloud improves Full-text Search Query Cluster simplifies Index Node.js. A deep dive into indexing strategies and best practices.',
    views: 5895,
    createdAt: ISODate('2026-02-11T17:30:28.608Z')
  }
]

通过全文索引进行数据的查询

test_search_db> db.articles.createIndex({ content: "text" });
content_text
test_search_db> db.articles.find(
|   { $text: { $search: "Database" } }
| ).limit(10);
[
  {
    _id: ObjectId('69fe231e84970425839ec463'),
    article_id: 52161,
    title: 'Performance analyzes Cloud',
    summary: 'AI Analytics Index Optimization analyzes Query Query Developer simplifies Index. An introductory guide for developers and architects.',
    content: 'Query Python Database Full-text Search accelerates Query Cluster Cluster manages Performance Developer Developer simplifies Database Database Full-text Search transforms Database Developer Query accelerates Database Analytics Index powers Java Database Python powers Database Database Database transforms Developer Performance Database improves Database Index. How to build scalable applications with high availability.',
    views: 4930,
    createdAt: ISODate('2026-05-01T16:06:04.940Z')
  },
通过查看执行计划,发现当前的查询走了相关的全文索引

通过查看执行计划,发现当前的查询走了相关的全文索引。

那么如果是多字段的情况,针对一个表只能有一个全文索引的情况下,我们先删除,在进行后续的添加。

db.articles.find( |$text: { $search: searchKeyword } },{     title: 1,      summary: 1,      content: 1,     score: { $meta: "textScore"

 } ).sort(   { score: { $meta: "textScore" } } |).limit(5).explain("executionStats").executionStats;

数据库查询执行计划

实际上MongoDB的全文索引使用 $test + TextIndex 倒排索引来完成的,建立全文索引可以针对一个key value也可以针对多个key value进行,

db.articles.createIndex({
  title: "text",
  summary: "text",
  content: "text"
}, {
  weights: {
    title: 10,
    summary: 3,
    content: 1
  },
  name: "ArticleTextIndex"
})

在针对多个key value进行全文索引查询的时候,可以给每个字段权重,通过权重来指定那些key value更能代表出每个查询可以过滤的采样率。

而当全文索引查询时,如果我们要展示出查询的信息,可以做预先展示,也就是查询的数据只对全文索引命中的部分,展示一小段数据如下,我们在preview 里面将要展示的内容进行截取,只展示前20个字符,通过降低展示的数据,提高数据查询的性能。

db.articles.find(
  { $text: { $search: searchKeyword } },
  {
    title: 1,
    summary: 1,
    preview: { $substrCP: ["$content", 0, 20] },
    score: { $meta: "textScore" },
    _id: 0
  }
)
.sort({ score: { $meta: "textScore" } })
.limit(10);
查询数据preview

详述PG修改字段类型不锁表的原理 step by step

传统RDBMS架构师的MongoDB思维破局与落地实践

如果没有了磁盘,数据库是不是更快,硬件会改变数据库设计的理念吗?

什么MongoDB 8.0 无索引加速聚合操作? 疯了吧!

体现价值-我们靠PostgreSQL迁移PolarDB,给公司省下了100万 “巨款”

《告别迁移焦虑:OceanBase MySQL 模式能否兼容 DBA 的“祖传”运维 SQL?》

干数据库不是买白菜:光盯着License几毛钱,看不见300台机器的电费?

一个秘密,不是你 SQL 写对了,是优化器帮“擦了屁股”  客户问迁移后为什么快了--迁移到PolarDB后的故事

AI 时代,我却用不上一个靠谱的数据库产品

AI 引入后,MySQL 列权限控制,插入,更新,读取,删除 --有了AI 真是越帮越忙

PostgreSQL 大表改字段卡死的问题解决了吗?  解决了方案在此

AI 引入DBA 工作,造成工作量增加,忙不过来,根本忙不过来!!!

三无项目导致MongoDB 持续1406% CPU 问题解决

阿里云MongoDB 部署安全吗? 多可用区怎么搞?

Image