Docs 菜单

Atlas Search 索引性能

重要

如果您为拥有或即将拥有超过 十亿个索引对象的集合创建Atlas Search索引,则必须在集群使用2.1 numPartitions 分片。每个分区的索引分区限制为 2.1 十亿个对象。

创建 Atlas Search 索引时,字段映射默认为动态,这意味着 Atlas Search 会动态索引集合中所有可动态索引的数据类型。其他选项(例如启用突出显示等)也可能导致索引占用更多磁盘空间。您可以通过以下方式减少 Atlas Search 索引的大小和性能占用:

  • 指定自定义索引定义,减少索引数据的数量和类型。

  • 在索引定义中指定 string 类型时,将 store 选项设置为 false

注意

某些限制仅适用于 M0M2M5 集群上的 Atlas Search。要了解更多信息,请参阅 Atlas Search 免费和共享层级限制。

某些索引配置选项可能会导致索引占用很大一部分磁盘空间。在某些情况下,您的索引大小可能比数据大很多倍。尽管这是预料之中的,但请务必注意以下索引密集型功能:

Atlas Search 自动完成操作符可用于在您的应用程序中构建类似于输入时搜索的功能。Atlas Search 自动完成 字段类型可能会导致索引过大,尤其是在以下情况中:

  • 使用 nGram 分词。

  • 设置一个较宽的 minGramsmaxGrams 范围。

  • 将包含数百万个文档的集合的 minGram 值设置为 1

可以通过以下方法减少 autocomplete 类型索引使用的空间:

  • minGramsmaxGrams 的范围减至最小。通常,我们建议将 maxGrams 设置为要查询字段中最长单词的字符数。如果您不确定,对于英语字段,我们建议先将 maxGrams 值设置为 10

  • 避免使用 nGram 分词策略,因为对于给定的字符串,Atlas Search 为 nGram 创建的词元比为 edgeGramrightEdgeGram 分词创建的词元更多。

string 字段索引为自动完成类型时,我们建议您也将该字段索引为 Atlas Search string类型,这样做有以下优点:

Atlas Search停止在副本集或单个分片上复制大于每个分区 2、100、000、000索引对象的索引更改,其中每个带索引的嵌入式文档都算作单个对象。 使用 embeddedDocuments字段类型可能会导致索引对象超过此限制,从而导致索引转换为 Stale 可查询状态,并可能导致结果过时。 如果您为拥有或即将拥有超过 十亿个索引对象的集合创建Atlas Search索引,则必须使用2.1 numPartitions选项或对集群分片。

索引对象的确切数量可能会因文档更改和删除的速率而异。搜索 Lucene Docs 最大数量指标提供了每个副本集或分片中所有索引的当前索引对象数量的上限。您可以通过执行以下操作来估算单个索引中索引对象的预期数量:

  1. 计算每个文档的索引对象数量。对于每一级嵌套,每个嵌入式文档都算作一个单独的索引对象。

    total number of index objects = 1 + number of nested embedded documents
  2. 将每个文档的索引对象数量乘以集合中的文档总数

    total number of index objects x total number of documents in collection

请注意,此近似值是一个下限。

例子

考虑此教程中描述的名为 schools集合,假设该集合包含与下面类似的 1000 个文档:

{
"_id": 0,
"name": "Springfield High",
"mascot": "Pumas",
"teachers": [
{
"first": "Jane",
"last": "Smith",
"classes": [
{
"subject": "art of science",
"grade": "12th"
},
... // 2 more embedded documents
]
},
... // 1 more embedded document
],
"clubs": {
"stem": [
{
"club_name": "chess",
"description": "provides students opportunity to play the board game of chess informally and competitively in tournaments."
},
... // 1 more embedded document
],
... // 1 more embedded document
}
}

现在,请考虑 schools 集合中以下字段的索引定义:

名为 teachers 的文档数组被索引为 embeddedDocuments 类型,并启用了动态映射。但是,classes 字段未进行索引。使用以下方法计算索引对象:

  1. 计算每个文档的索引对象数量。

    Number of ``teachers`` embedded documents = up to 2
    Total number of index objects per document = 1 + 2 = 3
  2. 乘以集合中的文档总数。

    Number of documents in the collection = 1000
    Number of index objects per document = 3
    Total number of index objects for collection = 1000 x 3 = 3000

名为 teachersteachers.classes 的文档数组被索引为 embeddedDocuments 类型,并启用了动态映射。使用以下方法计算索引对象:

  1. 计算每个文档的索引对象数量:

    Number of documents = 1
    Number of ``teachers`` embedded documents = up to 2
    Number of ``classes`` embedded documents = up to 3
    Number of index objects per document = 1 + ( 2 x 3 ) = 7
  2. 乘以集合中的文档总数。

    Number of documents in the collection = 1000
    Number of index objects per document = 7
    Total number of index objects: 1000 x 7 = 7000

如果您的集合包含可能产生 2,100,000,000 个索引对象的较大数组,则必须对任何包含 embeddedDocuments 类型索引的集群进行分片

如果您想要使用相同的字段对数据进行筛选和分面操作,我们建议您按以下 Atlas Search 类型对字段建立索引:

有关通过另一个字段过滤数据进行分面的示例,请参阅如何在 Atlas Search 中使用分面教程。

使用 multi 分析器以多种不同方式分析同一字段可能会导致索引过大,尤其是在分析具有很长值的字段时。

您可以使用 Atlas Search 语言分析器为多种语言编制索引。有关 Atlas Search 提供内置分析器的语言列表,请参阅语言分析器。有关示例,请参阅如何运行多语言 Atlas 搜索查询教程。要索引和查询目前不在内置语言分析器列表中的语言,可以创建自定义分析器。有关示例,请参阅自定义语言分析器示例。

假设集合中的每种语言都有一个文档。请考虑以下内容:

  • 您可以使用语言分析器在同一索引中单独索引这些字段。单个索引可以在同一查询中支持多种语言。

  • 或者,您可以为每个语言创建一个索引,这在隔离不同的语言文档时非常有用。请注意,每个索引都是变更流游标,因此维护成本可能很高。

  • 如果语言文档嵌套在父文档中,则可以创建单一索引。但是,索引定义有效负载可能很大,查询也可能相当复杂。

要了解有关这些数据模型和索引定义的更多信息,请参阅 MongoDB 博客

仅当同义词源集合较小时,才能快速插入和更新同义词源集合。为了获得最佳性能,我们建议批量插入和更新同义词源集合。

除了数据库中同义词集合使用的磁盘空间外,同义词映射定义不需要额外的磁盘空间。然而,同义词映射会在内存中创建工件,因此,对于包含许多文档的同义词集合,Atlas Search 会创建占用更多内存的工件。

Atlas Search 同时使用文件系统缓存和 Java 虚拟机 (JVM) 堆内存。它会在 JVM 堆中存储各种对象(例如查询对象、搜索器对象以及在索引与搜索操作中使用的其他临时数据),以便处理和追踪此查询。它会将内存映射文件(如段文件、字典文件等)存储在文件系统缓存中以提高其性能,尤其是在读取索引文件时。

在部署中,当 mongodmongot 进程均在同一节点上运行时,分配给 mongod 的内存会根据集群层而有所变化:

  • 对于 M40 及更高层级的集群,mongod 会将 50% 或更多的物理 RAM 专用于 WiredTiger 缓存,而剩余内存则用于内存中操作、底层操作系统和其他系统服务。

  • 对于 M30 及更低层级的集群,mongod 将 25% 的物理 RAM 用于 WiredTiger 缓存。

因此,分配给 mongot 的内存是总 RAM 的一个子集,这可能会导致 mongodmongot 之间出现资源争用问题,不仅涉及内存,还涉及 CPU 和磁盘 IO。

mongot 进程运行于单独的搜索节点上的部署中,Atlas 会将一部分可用 RAM 分配给 JVM 堆,并使用少量内存进程(例如,监控与自动化进程),而其余内存则可用于搜索。

如果您的搜索索引较大且可用内存较低,则可能会因内存不足而在索引与查询期间出现性能下降问题。如果您为索引中具有任意键的文档启用动态映射,搜索索引则可能会变得很大。此问题可能会导致映射爆炸mongot 过度消耗内存可能会导致 mongot 运行出现 OOM,而此问题也可能导致 mongot 崩溃。

您可以使用以下指标来确定 mongot 是否正在运行 OOM

  • Search Page FaultsDisk IOPS的数量增加。如果操作系统不断从磁盘检索所需的页面并将其读取到 RAM 中,则会发生这种情况。

  • Normalized Process/System CPUIOWait的水平升高,可能会导致性能下降。

我们建议您将生产就绪的应用程序迁移到专用搜索节点。正确调整搜索节点的大小非常重要,因为内存不足可能会导致性能问题。

创建 Atlas Search 索引需要大量资源。索引构建时,Atlas 集群的性能可能会受到影响。

Atlas 复制集合上的所有写入。这意味着对于每个具有 Atlas Search 索引的集合,写入都会放大到为该集合定义的 Atlas Search 索引的数量。

在某些情况下,必须重新构建 Atlas Search 索引。重新构建 Atlas Search索引也会消耗资源,并可能影响数据库性能。Atlas Search 仅在以下情况下自动重新构建索引:

注意

Atlas Search 支持不停机索引,这意味着您可以在 Atlas Search 重建索引时继续运行搜索查询。Atlas Search 会在构建新索引时,将旧索引保持最新状态。我们建议,为此操作分配的可用磁盘空间为旧索引所用磁盘空间的 125%。您可以在“搜索已用磁盘空间”指标中查看索引当前使用的磁盘空间。

如果您的索引重新构建由于磁盘空间不足而失败,我们建议您暂时扩展集群容量以满足增加的需求。您可以按照修复存储问题中的描述手动进行此更改,即使对于启用了自动扩展的集群也是如此。

如果您部署了独立搜索节点,对于 Java 21 升级等某些更改,Atlas 会在索引重建期间自动部署额外的搜索节点,您无需分配任何额外的可用磁盘空间。Atlas 不会为因索引定义更改导致的索引重建而部署额外的搜索节点。

一旦 Atlas Search 重新构建索引,旧索引将自动替换,无需采取任何进一步操作。

Atlas Search 支持最终一致性,但不提供任何进一步的一致性保证。这意味着插入 MongoDB 集合并由 Atlas Search 编制索引的数据将无法立即用于 $search 查询。

Atlas Search 从 MongoDB 变更流中读取数据,并在异步进程中对这些数据进行索引。此进程通常非常快,但有时可能会受到复制延迟、系统资源可用性和索引定义复杂性的影响。大量的 Atlas Search 索引也可能导致 Atlas Search 索引的复制滞后和延迟。

当 Atlas Search 使用任意键为文档编制索引,且您拥有动态映射时,就会发生映射爆炸。mongot 进程可能会占用越来越多的内存,甚至可能崩溃。如果为索引添加的字段过多,可能会发生映射爆炸。要解决此问题,您可以升级集群,或使用 静态映射 (不会为数据中的所有字段编制索引)。

使用通配符路径搜索字段时,请使用类似元组的模式设计搜索。如果使用键值模式的通配符路径搜索,Atlas Search 会将每个键作为自己的字段进行索引,这可能会导致映射爆炸式增长。

例子

键值模式示例如下:

ruleBuilder: {
ruleName1: <data>,
ruleName2: <data>,
.....
ruleName1025: <data>
}

使用类似元组的模式重组相同数据的示例如下:

{
ruleBuilder: [
{name: ruleName1, data: <data>},
{name: ruleName2, data: <data>},
...
{name: ruleName1025, data: <data>}
]
}

您可以配置字段以存储在 Atlas Search 上,并改进后续聚合管道阶段的性能,例如 $sort$match$group$skip。如果原始文档和匹配的数据集由于过大而导致完整数据查找效率低下,便可使用此优化功能。如需详细了解如何在 Atlas Search 上存储特定字段以及仅返回这些存储的字段,请参阅在 Atlas Search 索引中定义存储的源字段以及返回存储的源字段

我们建议仅存储后续阶段所需的最少数量的字段。如有必要,可以在管道阶段结束时使用 $lookup 来检索整个文档,如示例所示。存储不必要的字段会增加磁盘利用率,并可能在索引和查询期间对性能产生负面影响。

Atlas Search 已部署在您的 Atlas 集群上。部署新的 Atlas Search 版本时,您的 Atlas 集群在返回查询结果时可能会遇到短暂的网络故障。为了缓解部署期间的问题,并尽量减少对应用程序的影响,请考虑以下操作:

  • 在应用程序中执行重试逻辑。

  • 配置 Atlas 维护窗口

    注意

    Atlas Search 升级仅在维护窗口期间开始,维护窗口结束后可能会继续。

要详细了解每个版本中的变更,请参阅 Atlas Search 变更日志。

您可以通过将集群升级到具有更多内核的更高层级来扩展 Atlas Search 索引的初始同步和稳定状态索引。Atlas Search 使用所有可用内核的百分比运行初始同步和稳定状态索引,并且随着升级集群使新内核可用并使性能得到提升。

如果您重新配置部署以使用本地 NVMe 存储类型或扩容基于 NVMe 的集群,在每个节点完成其基础配置或扩容操作后,Atlas Search 会对所有已配置的 Atlas Search 索引执行初始同步。如果 Atlas Search 索引初始同步所花的时间比完成集群配置更改所需的时间更长,则在 Atlas 集群中的所有节点上完成初始同步后,您才能运行 $search 查询。

我们建议部署专用搜索节点以独立扩展 Atlas 集群和 $search 工作负载。专用搜索节点仅运行 mongot 进程,因此可提高 mongot 进程的可用性、性能和工作负载均衡。