Atlas Search 索引性能
在此页面上
资源要求
索引大小和配置
创建 Atlas Search 索引时,字段映射默认为动态,这意味着 Atlas Search 会动态索引集合中所有可动态索引的数据类型。其他选项(例如启用突出显示等)也可能导致索引占用更多磁盘空间。您可以通过以下方式减少 Atlas Search 索引的大小和性能占用:
注意
某些限制仅适用于 M0
、M2
和 M5
集群上的 Atlas Search。要了解更多信息,请参阅 Atlas Search 免费和共享层级限制。
Considerations
某些索引配置选项可能会导致索引占用很大一部分磁盘空间。在某些情况下,您的索引大小可能比数据大很多倍。尽管这是预料之中的,但请务必注意以下索引密集型功能:
自动完成(Autocomplete)
Atlas Search 自动完成操作符可用于在您的应用程序中构建类似于输入时搜索的功能。Atlas Search 自动完成 字段类型可能会导致索引过大,尤其是在以下情况中:
使用
nGram
分词。设置一个较宽的
minGrams
到maxGrams
范围。将包含数百万个文档的集合的
minGram
值设置为1
。
可以通过以下方法减少 autocomplete
类型索引使用的空间:
将
minGrams
和maxGrams
的范围减至最小。通常,我们建议将maxGrams
设置为要查询字段中最长单词的字符数。如果您不确定,对于英语字段,我们建议先将maxGrams
值设置为10
。避免使用
nGram
分词策略,因为对于给定的字符串,Atlas Search 为nGram
创建的词元比为edgeGram
或rightEdgeGram
分词创建的词元更多。
将 string
字段索引为自动完成类型时,我们建议您也将该字段索引为 Atlas Search string类型,这样做有以下优点:
使用自动完成操作符时提高完全匹配的分数。有关示例,请参阅如何在 Atlas Search 中使用自动完成教程中的高级示例。
使用 autocomplete 操作符和另一个支持字符串搜索的操作符(例如文本操作符)在同一查询中查询同一字段。有关示例,请参阅跨多个字段搜索示例。
嵌入式文档
Atlas Search停止在副本集或单个分片上复制大于每个分区 2、100、000、000索引对象的索引更改,其中每个带索引的嵌入式文档都算作单个对象。 使用 embeddedDocuments
字段类型可能会导致索引对象超过此限制,从而导致索引转换为 Stale
可查询状态,并可能导致结果过时。 如果您为拥有或即将拥有超过 十亿个索引对象的集合创建Atlas Search索引,则必须使用2.1 numPartitions
选项或对集群分片。
索引对象的确切数量可能会因文档更改和删除的速率而异。搜索 Lucene Docs 最大数量指标提供了每个副本集或分片中所有索引的当前索引对象数量的上限。您可以通过执行以下操作来估算单个索引中索引对象的预期数量:
计算每个文档的索引对象数量。对于每一级嵌套,每个嵌入式文档都算作一个单独的索引对象。
total number of index objects = 1 + number of nested embedded documents 将每个文档的索引对象数量乘以集合中的文档总数
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
字段未进行索引。使用以下方法计算索引对象:
计算每个文档的索引对象数量。
Number of ``teachers`` embedded documents = up to 2 Total number of index objects per document = 1 + 2 = 3 乘以集合中的文档总数。
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
名为 teachers
和 teachers.classes
的文档数组被索引为 embeddedDocuments
类型,并启用了动态映射。使用以下方法计算索引对象:
计算每个文档的索引对象数量:
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 乘以集合中的文档总数。
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
分析器
使用 multi
分析器以多种不同方式分析同一字段可能会导致索引过大,尤其是在分析具有很长值的字段时。
多语言搜索
您可以使用 Atlas Search 语言分析器为多种语言编制索引。有关 Atlas Search 提供内置分析器的语言列表,请参阅语言分析器。有关示例,请参阅如何运行多语言 Atlas 搜索查询教程。要索引和查询目前不在内置语言分析器列表中的语言,可以创建自定义分析器。有关示例,请参阅自定义语言分析器示例。
假设集合中的每种语言都有一个文档。请考虑以下内容:
您可以使用语言分析器在同一索引中单独索引这些字段。单个索引可以在同一查询中支持多种语言。
或者,您可以为每个语言创建一个索引,这在隔离不同的语言文档时非常有用。请注意,每个索引都是变更流游标,因此维护成本可能很高。
如果语言文档嵌套在父文档中,则可以创建单一索引。但是,索引定义有效负载可能很大,查询也可能相当复杂。
要了解有关这些数据模型和索引定义的更多信息,请参阅 MongoDB 博客。
同义词集合
仅当同义词源集合较小时,才能快速插入和更新同义词源集合。为了获得最佳性能,我们建议批量插入和更新同义词源集合。
除了数据库中同义词集合使用的磁盘空间外,同义词映射定义不需要额外的磁盘空间。然而,同义词映射会在内存中创建工件,因此,对于包含许多文档的同义词集合,Atlas Search 会创建占用更多内存的工件。
搜索内存管理
Atlas Search 同时使用文件系统缓存和 Java 虚拟机 (JVM) 堆内存。它会在 JVM 堆中存储各种对象(例如查询对象、搜索器对象以及在索引与搜索操作中使用的其他临时数据),以便处理和追踪此查询。它会将内存映射文件(如段文件、字典文件等)存储在文件系统缓存中以提高其性能,尤其是在读取索引文件时。
在部署中,当 mongod
与 mongot
进程均在同一节点上运行时,分配给 mongod
的内存会根据集群层而有所变化:
对于
M40
及更高层级的集群,mongod
会将 50% 或更多的物理 RAM 专用于 WiredTiger 缓存,而剩余内存则用于内存中操作、底层操作系统和其他系统服务。对于
M30
及更低层级的集群,mongod
将 25% 的物理 RAM 用于 WiredTiger 缓存。
因此,分配给 mongot
的内存是总 RAM 的一个子集,这可能会导致 mongod
和 mongot
之间出现资源争用问题,不仅涉及内存,还涉及 CPU 和磁盘 IO。
在 mongot
进程运行于单独的搜索节点上的部署中,Atlas 会将一部分可用 RAM 分配给 JVM 堆,并使用少量内存进程(例如,监控与自动化进程),而其余内存则可用于搜索。
如果您的搜索索引较大且可用内存较低,则可能会因内存不足而在索引与查询期间出现性能下降问题。如果您为索引中具有任意键的文档启用动态映射,搜索索引则可能会变得很大。此问题可能会导致映射爆炸。mongot
过度消耗内存可能会导致 mongot
运行出现 OOM,而此问题也可能导致 mongot
崩溃。
您可以使用以下指标来确定 mongot
是否正在运行 OOM:
Search Page Faults
和Disk IOPS
的数量增加。如果操作系统不断从磁盘检索所需的页面并将其读取到 RAM 中,则会发生这种情况。Normalized Process/System CPU
和IOWait
的水平升高,可能会导致性能下降。
我们建议您将生产就绪的应用程序迁移到专用搜索节点。正确调整搜索节点的大小非常重要,因为内存不足可能会导致性能问题。
创建和更新 Atlas Search 索引
创建 Atlas Search 索引需要大量资源。索引构建时,Atlas 集群的性能可能会受到影响。
Atlas 复制集合上的所有写入。这意味着对于每个具有 Atlas Search 索引的集合,写入都会放大到为该集合定义的 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 Search 已部署在您的 Atlas 集群上。部署新的 Atlas Search 版本时,您的 Atlas 集群在返回查询结果时可能会遇到短暂的网络故障。为了缓解部署期间的问题,并尽量减少对应用程序的影响,请考虑以下操作:
在应用程序中执行重试逻辑。
配置 Atlas 维护窗口。
注意
Atlas Search 升级仅在维护窗口期间开始,维护窗口结束后可能会继续。
要详细了解每个版本中的变更,请参阅 Atlas Search 变更日志。
纵向扩展索引性能
您可以通过将集群升级到具有更多内核的更高层级来扩展 Atlas Search 索引的初始同步和稳定状态索引。Atlas Search 使用所有可用内核的百分比运行初始同步和稳定状态索引,并且随着升级集群使新内核可用并使性能得到提升。
Atlas 集群配置更改
如果您重新配置部署以使用本地 NVMe 存储类型或扩容基于 NVMe 的集群,在每个节点完成其基础配置或扩容操作后,Atlas Search 会对所有已配置的 Atlas Search 索引执行初始同步。如果 Atlas Search 索引初始同步所花的时间比完成集群配置更改所需的时间更长,则在 Atlas 集群中的所有节点上完成初始同步后,您才能运行 $search
查询。
我们建议部署专用搜索节点以独立扩展 Atlas 集群和 $search
工作负载。专用搜索节点仅运行 mongot
进程,因此可提高 mongot
进程的可用性、性能和工作负载均衡。