本文汇总了 MongoDB 8.3 版本向量搜索的常见问题。
说明
- 当前 MongoDB 8.3 版本正在灰度发布中,如需使用向量搜索功能,请提交工单联系技术申请使用。
- MongoDB 8.3 版本的向量搜索功能通过集成的 mongot 搜索节点提供。mongot 是专为全文搜索和向量搜索设计的索引与查询执行引擎,负责管理 Search 索引并执行检索查询。
在创建 Search 索引时,需要通过 similarity 参数指定相似度计算方法。MongoDB 向量搜索支持三种算法。
核心选择原则
根据向量数据的归一化状态和业务场景决策,具体如下:
- 最常用,适用于文本嵌入和语义检索场景。它衡量两个向量在方向上的相似程度,对向量的模长不敏感,是处理由各类 Embedding 模型(如 text-embedding-v4)生成向量的通用选择。如果无法确定向量的归一化状态,选择 cosine 是安全的默认选项。
- 当且仅当向量已归一化(即模长为 1)时,点积与余弦相似度等价,且计算效率更高。若您的向量来自归一化模型,或您已手动归一化,可优先选用此方法以提升性能。
- 衡量向量在空间中的绝对距离,距离越小越相似。适用于特征向量空间中的绝对距离度量场景,如图像特征比对或物理特征相近性判断。
配置示例
量化技术通过压缩向量数据的精度,显著降低存储和内存开销,是降低大规模向量搜索成本的关键手段。您可以在索引定义中通过 quantization 参数指定量化策略。
- 保精度最高,成本也最高。存储和检索使用原始 32 位浮点向量。适用于向量数量较小或对检索精度有极致要求的场景。
- 平衡之选。将 32 位浮点数映射为更小的整数(如 int8),可将内存和存储开销降低约 75%(降至原来的 1/4),同时保持良好的检索精度,通常能保留 90% 以上的召回率。是大多数生产环境推荐的默认选项。
- 极致压缩。将每个维度压缩为 1 位(0 或 1),内存开销可降低约 96%(降至原来的 1/24)。为了弥补精度损失,MongoDB 会自动执行重打分(Rescoring)步骤,即使用原始全精度向量对二进制检索的 top-K 结果进行重新排序,以尽可能保证最终结果的准确性。适用于百万级、十亿级规模的向量场景,且对成本极度敏感、可接受微小精度损失的业务。
配置示例
"quantization": "scalar"
您可以在同一个集合中存储多个向量字段。例如,为商品标题生成一个向量,为商品描述生成另一个向量,为商品图片再生成一个向量。这些字段都可以在同一个 Search 索引中定义。
注意
目前 $vectorSearch 阶段一次只能对一个向量字段进行检索。也就是说,您无法在一次查询中直接对"标题向量"和"描述向量"同时进行搜索并自动合并结果。
推荐方案:分别查询,再合并结果
您可以对每个向量字段分别执行 $vectorSearch,然后使用聚合管道将结果合并。
方法一:使用 $unionWith 合并
{ $vectorSearch: { path: "title_embedding", queryVector: [...], numCandidates: 100, limit: 20 } },
{ $project: { _id: 1, title: 1, score: { $meta: "vectorSearchScore" }, source: { $literal: "title"
{ $vectorSearch: { path: "desc_embedding", queryVector: [...], numCandidates: 100, limit: 20 } },
{ $project: { _id: 1, title: 1, score: { $meta: "vectorSearchScore" }, source: { $literal: "desc"
{ $unionWith: { coll: "products", pipeline: pipelineA } },
{ $unionWith: { coll: "products", pipeline: pipelineB } },
{ $group: { _id: "$_id", title: { $first: "$title" }, scores: { $push: "$score" } } },
{ $addFields: { finalScore: { $sum: "$scores" } } },
{ $sort: { finalScore: -1 } },
说明
$unionWith 是 MongoDB 通用的聚合管道操作符,适用于所有版本。上述示例中,我们分别对两个向量字段执行检索,然后通过 $unionWith 合并结果,再按 _id 分组后对分数求和排序。您也可以根据业务需要,为不同字段分配不同的权重。
方法二:使用 $rankFusion
如果您的 MongoDB 版本是 8.3 或更高,可以使用 $rankFusion 阶段来更简洁地合并结果。$rankFusion 会自动对多个 $vectorSearch 的结果进行去重和融合排序。
path: "title_embedding",
queryVector: [0.1, 0.2, ...],
queryVector: [0.1, 0.2, ...],
weights: { titleSearch: 0.6, descSearch: 0.4 }
当您需要在向量搜索的基础上,叠加精确的条件筛选(如"查询与某商品描述相似,且价格低于 500 元、库存充足的商品")时,就需要添加过滤字段。
操作方式
- 索引定义:在 Search 索引的 fields 中,为需要过滤的字段(如 price, category, inStock)指定 type: "filter"。
- 查询阶段:在 $vectorSearch 阶段使用 filter 参数传入 MQL 过滤条件。
索引定义示例
{ type: "vector", path: "embedding", ... },
{ path: "category", type: "filter" },
{ path: "price", type: "filter" }
查询示例
db.collection.aggregate([
filter: { $and: [ { category: "Electronics" }, { price: { $lt: 500 } } ] },
注意
- 您必须在索引中将过滤字段定义为 filter 类型,否则过滤操作无法生效。
- 筛选后的查询通常比未筛选的查询慢,因为需要先执行预过滤再计算向量相似度。过滤性能取决于过滤条件的选择性——选择性越高(匹配的文档越少),性能通常越好。
- 对数据进行预过滤不会影响 $vectorSearch 返回的相似度分数(范围 0~1)。
- 启用量化(scalar 或 binary)可以解决预过滤查询的内存问题,而无需增加更多内存。
建议将选择性高(即不同值较多的字段,如 userId)作为过滤字段,以有效缩小检索范围,提升性能。
向量搜索依赖独立于 mongod 的搜索进程 mongot,您需要为 mongot 合理规划存储与内存资源。估算的核心思路是先统计 mongod 中的向量数据总量,再推算出 mongot 索引所需的存储和内存。最终规格建议预留 40% 剩余空间。
不同实例类型的估算方式有所不同,具体如下。
您可根据以下步骤完成 mongot 内存与存储的估算。
向量数据总大小(GiB)= 文档数量 × 向量维度 × 4 ÷ 1024³
说明
- 4 表示 float32(32 位单精度浮点数)类型每个维度占 4 字节。
- 1024³ 用于将字节转换为 GiB(1 GiB = 1024³ 字节)。
- 向量维度由您使用的 embedding 模型决定。embedding 模型是将文本转换为向量的 AI 模型,由 OpenAI、Google、Cohere 等厂商提供,也可从 Hugging Face 等开源社区获取。常见模型的维度参考:OpenAI ada-002(1536)、OpenAI 3-large(3072)、Cohere v3(1024)、Google gecko(768)。MongoDB 支持的维度上限为 8192,详情请参见 $vectorSearch(聚合阶段)。
- 单条向量大小示例:1536 维 × 4 = 6144 字节 ≈ 6 KiB。
- 方法 B:通过 MongoDB Shell 查询
- 如果您不确定向量维度,或集合中存在多个向量字段,可在 MongoDB Shell 中执行以下脚本自动计算。
var collName = "<集合名称>";
var fieldName = "<向量字段名>";
var result = db.getCollection(collName).aggregate([
{ $sample: { size: sampleSize } },
{ $match: { [fieldName]: { $exists: true } } },
avgDim: { $avg: { $size: "$" + fieldName } },
if (result.length === 0) {
print("未找到包含字段 " + fieldName + " 的文档,请检查字段名是否正确。");
var avgDim = result[0].avgDim;
var sampledCount = result[0].count;
var totalDocs = db.getCollection(collName).estimatedDocumentCount();
var vectorSizeBytes = totalDocs * avgDim * 4;
var vectorSizeGiB = vectorSizeBytes / (1024 * 1024 * 1024);
print("===== 向量数据估算结果 =====");
print("集合名称: " + collName);
print("预计文档总数: " + totalDocs);
print("采样文档数: " + sampledCount);
print("平均向量维度: " + avgDim.toFixed(0));
print("单条向量大小: " + (avgDim * 4 / 1024).toFixed(2) + " KiB");
print("向量数据总大小: " + vectorSizeGiB.toFixed(2) + " GiB");
说明
若集合中包含多个向量字段(如 title_embedding 和 image_embedding),请分别修改 fieldName 执行脚本,并将各字段的结果求和。
- 获得向量数据总大小后,即可计算 mongot 所需的磁盘空间。
- 请先确认您是否同时启用了全文搜索索引。启用与否对于计算 mongot 所需磁盘空间的差异如下:
- 仅向量搜索:总磁盘需求 = 向量索引磁盘大小(阅读向量索引磁盘大小部分)
- 向量搜索 + 全文搜索:总磁盘需求 = 向量索引磁盘大小 + 全文索引磁盘大小(阅读全部内容)
向量索引磁盘大小 = 向量数据总大小 × 1.0(基线)
说明
上述公式计算的是向量索引的基础大小。HNSW(分层可导航小世界图)结构会产生额外的元数据开销,但通常较小。本文已在步骤 4 中通过 40% 的冗余空间统一覆盖这部分开销。
- 如果同时启用了全文搜索索引,需额外计算磁盘占用。
全文索引磁盘大小 = 索引文本总大小 × 扩展系数
- 磁盘规格确定后,接下来计算内存需求。总内存需求由以下三部分组成:
总内存需求 = 向量索引内存 + JVM 堆内存 + 文件系统缓存
说明
文件系统缓存由操作系统自动管理,您需要主动规划的是向量索引内存和 JVM 堆内存。
向量索引所需内存 = 向量索引磁盘大小 × 1.25
说明
MongoDB 官方建议在索引大小基础上额外增加 20%~25% 的缓冲空间,用于 HNSW 图结构在内存中的运行时开销。因此系数为 1.25(即 100% + 25%)。详情请参见 mongot 部署的资源分配注意事项。 - 计算示例:向量索引磁盘大小为 5.72 GiB,则所需向量索引内存 = 5.72 × 1.25 = 7.15 GiB。
- 当索引规模较大时,可通过向量量化将浮点向量(如 float32)压缩为低精度表示,以降低内存占用。MongoDB 支持的量化方式如下:
注意
当向量索引磁盘大小超过 3 GiB 时,建议评估启用量化。详情请参见矢量量化。 - 步骤 2 和步骤 3 计算的是当前负载所需的最小规格。在实际生产环境中,还需叠加安全余量以应对未来增长和运维操作。
推荐磁盘空间 = mongot 总磁盘需求 ÷ 0.6
推荐内存大小 = mongot 总内存需求 ÷ 0.6
- 预留 40% 意味着当前负载只占最终规格的 60%。因此:最终规格 = 当前负载 ÷ 0.6。
说明
如果暂时无法精确估算,建议 mongot 存储空间与 mongod 的初始存储配置值保持一致,后续根据监控调整。
规格与选型参考
说明
使用场景:您处于规划阶段,还没有精确的文档数量或向量维度数据,需要快速估算规格。
与精确计算的关系:如果您已经完成了步骤 1~4 的精确计算,请优先使用计算结果。速查表仅用于规划阶段的快速参考,两者可能存在差异。
- 步骤 2:根据您的向量数据大小,在下表中找到对应配置
- 下表将上述官方分类映射到具体的向量数据规模,方便您直接对号入座。
说明
- 上表基于纯向量搜索、未启用量化的场景。当向量数据总大小超过 10 GiB 时,建议启用量化以降低内存需求。
- 规格调整是迭代过程,建议部署后根据实际监控持续优化。
完整估算示例
以下是一个中型电商推荐场景的完整计算过程。本示例与上文“规格速查表”中“中型(向量数据大小 1~10 GiB)”配置相对应,可作为精确计算的验证参考。
业务假设:
- 100 万条商品文档,每条包含 1536 维向量(OpenAI ada-002)
- 同时启用全文搜索(标准分词,索引文本约 500 MiB)
说明
示例 JVM 堆的确定逻辑
JVM 堆的大小取决于最终选择的内存规格,mongot 默认分配系统可用内存的 25% 给 JVM 堆。因此需要先假设一个规格,再验证是否够用。
本示例根据规格速查表“中型”的内存范围(32~64 GiB),取最低值 32 GiB 作为假设规格:
- JVM 堆 = 32 × 25% = 8 GiB
- 总内存需求 = 向量索引内存 7.15 GiB + JVM 堆 8 GiB = 15.15 GiB
- 叠加 40% 余量:15.15 ÷ 0.6 = 25.25 GiB → 向上取整为 32 GiB
- ✅ 验证通过:25.25 GiB ≤ 32 GiB
如果验证不通过,则需要换更大的规格(如 64 GiB)重新计算,直到验证通过。
副本集实例 vs 分片集群实例(3 个分片)对比:
示例推荐配置:32 GiB 内存 / 200 GiB 磁盘 / 4 vCPU(来源:MongoDB 官方低 CPU 工作负载中型规格表,详见上方“规格速查表”的配置说明。4 vCPU 为中型规格下限,QPS > 100 时建议从 8 vCPU 起步。)