This page explains key performance optimization strategies for MongoDB Vector Search and how we used them to create our benchmark. To learn how to interpret this guide, see How to Use This Benchmark.
Para nosso benchmark, usamos o conjunto de dados Amazon Reviews 2023, um enorme conjunto de dados de e-commerce que contém 571,54mi de análises em 33 categorias de produtos, representando interações de maio 1996 de a setembro de 2023. Com cerca de 48,2 milhões de itens exclusivos cobertos por essas revisões, ele fornece dados multimodais ricos, incluindo avaliações de usuários (classificações, texto, votos de utilidade), metadados de itens (descrições, preço, imagens) e gráficos de interação usuário-item. Analisamos subconjuntos do conjunto de dados de itens (5,5mi e 15,3mi) que contêm títulos e descrições, e usaram o modelo voyage-3-large
da Voyage AI para incorporá-los usando a seguinte lógica:
source = "Item: Title: " + record["title"] + " Description: " + record["description"] source_embedding = vo.embed(source, model="voyage-3-large", input_type="document", output_dimension=2048)
A qualidade dos resultados para os filtros é determinada pelo cálculo da similaridade de Jaccard (intersection / expected number of results
) usando os resultados de uma query ANN e os resultados float ENN exatos correspondentes para a mesma entrada de texto e número de vetores solicitados. Recall é calculado encontrando a interseção média em 50 queries de amostra que podem ser feitas em um conjunto de dados de e-commerce.
Observação
Para ver o código-fonte usado para benchmarking, bem como o código usado para incorporar o conjunto de dados de origem, consulte Repositório de testes de desempenho.
Fatores que afetam o desempenho
This section outlines several factors that impact performance for MongoDB Vector Search and how we configured our benchmark to test them.
Quantização
A quantização reduz a precisão das incorporações vetoriais para diminuir o uso de memória e melhorar a velocidade da pesquisa, com concessões em termos de precisão da pesquisa.
Quantização escalar
A quantização escalar converte vetores de ponto flutuante de 32 bits em inteiros de 8 bits, alcançando uma redução de 4x no uso de memória. As comparações de vetores inteiros exigem menos tempo de computação em comparação com vetores de ponto flutuante e requerem menos recursos, mas podem resultar em uma penalidade na precisão da pesquisa.
Quantização binária
A quantização binária converte vetores em representações de 1 bit, alcançando uma redução de 32x no uso de memória. As comparações de vetores binários envolvem o cálculo da distância de Hamming e exigem ainda menos tempo de computação em comparação com vetores inteiros e menos recursos. No entanto, a penalidade na precisão da pesquisa ao passar de vetores float para vetores binários é tão significativa que, para compensar isso, adicionamos uma etapa de reavaliação, o que aumenta a latência. No momento da consulta, os principais numCandidates
acumulados durante a pesquisa são reordenados por seus vetores de fidelidade completa no disco antes de gerar os principais resultados limit
.
Dimensionalidade vetorial
Utilizamos o modelo voyage-3-large
da Voyage AI para incorporar os tamanhos médio (5.5mi) e grande (15.3mi) de conjuntos de dados vetoriais. Escolhemos esse modelo de incorporação devido ao seu desempenho superior em muitos benchmarks de IR e porque ele é treinado com o Aprendizado de Representação Matryoshka e a quantização em mente. Portanto, ele apresenta um bom desempenho em dimensões menores com a quantização ativada, mesmo em volumes maiores de vetores.
Utilizamos a indexação em visualizações para criar campos adicionais que dividem as primeiras N dimensões do vetor com 2048 dimensões de origem, gerando vetores com 1024, 512 e 256 dimensões, e os indexamos como faríamos com o campo de origem.
Observação
Você deve usar a versão 8.1 do MongoDB ou posterior para criar um índice de pesquisa vetorial em uma exibição.
db.createView( "all_dims_amazon_dataset", "2048d_amazon_dataset", [ { $addFields: { "1024_embedding": { $slice: ["$embedding", 1024] }, "512_embedding": { $slice: ["$embedding", 512] }, "256_embedding": { $slice: ["$embedding", 256] } } } ] )
db.all_dims_amazon_dataset.createSearchIndex( "all_dims_vector_index", "vectorSearch", { "fields": [ { "numDimensions": 2048, "path": "embedding", // original 2048d embedding produced by voyage-3-large "quantization": "scalar", // adjust to binary when needed "similarity": "dotProduct", "type": "vector" }, { "numDimensions": 1024, "path": "1024_embedding", "quantization": "scalar", "similarity": "cosine", // sliced embeddings aren't normalized, so must use cosine "type": "vector" }, { "numDimensions": 512, "path": "512_embedding", "quantization": "scalar", "similarity": "cosine", "type": "vector" }, { "numDimensions": 256, "path": "256_embedding", "quantization": "scalar", "similarity": "cosine", "type": "vector" } ] } )
Semelhante a diferentes representações em cada posição, as várias dimensionalidades impactam a capacidade representativa de cada vetor. Consequentemente, você pode alcançar maior precisão com vetores de 2048d em comparação com vetores de 256d, especialmente quando mede em relação a uma linha de base de ponto flutuante de 2048d ENN.
In addition to requiring more storage and memory, higher dimensional vectors are somewhat slower to query compared to lower dimensional vectors, but this is mitigated significantly as MongoDB Vector Search leverages SIMD instructions when performing vector comparisons.
Filtragem
Também criamos uma definição de índice separada na coleção contendo todos os 15,3mi itens, que inclui filtros em dois campos para habilitar queries pré-filtradas nesse conjunto de dados.
db.large_amazon_dataset.createSearchIndex( "vectorSearch", "large_vector_index", { "fields": [ { "numDimensions": 2048, "path": "embedding", "quantization": "scalar", // adjust to binary when needed "similarity": "dotProduct", "type": "vector" }, { "path": "category", "type": "filter" }, { "path": "price", "type": "filter" } ] } )
Executamos queries de pesquisa vetoriais, tanto quanto com quanto sem filtro, no grande conjunto de dados indexados:
# unfiltered query query = [ { "$vectorSearch": { "index": "large_vector_index", "path": "embedding", "queryVector": embedding.tolist(), "limit": k, "numCandidates": candidates, } }, { "$project": {"embedding": 0} } ]
# filtered query query = [ { "$vectorSearch": { "index": "large_vector_index", "path": "embedding", "queryVector": embedding.tolist(), "limit": k, "numCandidates": candidates, "filter": {"$and": [{'price': {'$lte': 1000}}, {'category': {'$eq': "Pet Supplies"}}]} } }, { "$project": {"embedding": 0} } ]
Observação
Ambos os padrões de query excluem os campos incorporados na saída usando a etapa $project
. Isso é sempre recomendado para reduzir a latência, a menos que você precise de incorporações nos seus resultados.
Configuração de nó de pesquisa
MongoDB Vector Search performance scales with dedicated Search Nodes, which handle vector computations separately from your primary database workload and make efficient use of dedicated hardware instances. All tests were conducted using an M20
base cluster, but depending on the type of test, we reconfigured the Search Nodes used to better fit our test case. All tests were run using Search Nodes on AWS us-east-1, with an EC2 instance also in us-east-1
making requests. There are three types of Search Nodes that you can provision on AWS, which vary in terms of disk, RAM, and vCPUs that they have available:
Tipo de nó | Perfil de Recursos | Uso recomendado |
---|---|---|
CPU baixa | Baixa proporção de disco para memória (~6:1), baixa vCPU | Bom ponto de partida para muitas cargas de trabalho vetoriais que não usam quantização. |
CPU alta | Alta proporção de disco para memória (~25:1), alta vCPU | Escolha de alto desempenho para cargas de trabalho com alta QPS ou cargas de trabalho que aproveitam a quantização |
Otimizado para armazenamento | Alta proporção de disco para memória (~25:1), baixa vCPU | Opção custo-efetiva para cargas de trabalho que utilizam quantização |
Dimensionamento do conjunto de dados da Amazon
Um vetor flutuante de 768dimensão ocupa ~3kb de espaço no disco. Esse requisito de recurso é dimensionado linearmente com o número de vetores e o número de dimensões de cada vetor: 1M 768d vetores ocupa ~3GB; 1M 1536d ocupa ~6GB.
Utilizando quantização, geramos vetores de representação que são mantidos na memória a partir dos vetores de alta fidelidade armazenados no disco. Isso reduz a quantidade de memória necessária em 3,75x para quantização escalar e 24x para quantização binária, mas aumenta a quantidade de disco necessária para armazenar os vetores não quantizados e quantizados.
1 vetor quantizado escalar 768d requer 0,8 kb de memória (3/3.75
) e ~3,8 kb de disco (3 + 3/3.75
). Considerando essas opções de hardware e os requisitos de recursos para quantização, selecionamos os seguintes níveis de nós de pesquisa para os diferentes casos de teste:
Caso de Teste | Recursos necessários (RAM, armazenamento) | Search Node Tier RAM, disk, vCPUs | Preço para nós 2x |
---|---|---|---|
Conjunto de dados médio (5.5M vetores, todas as dimensões), quantização escalar | 22, 104.5 GB | S50-otimizado para armazenamento 32 GB, 843 GB, 4 vCPUs | $1.04/hr |
Conjunto de dados médio (5,5mi vetores, todas as dimensões), quantização binária | 3.43, 104.5 GB | S30-high-cpu 8 GB 213 GB 4 vCPUs | $0.24/hr |
Grande conjunto de dados (15,3mi vetores, 2048d), quantização escalar | 32.64, 155.04 GB | S50-otimizado para armazenamento 32 GB, 843 GB, 4 vCPUs | $1.04/hr |
Grande conjunto de dados (15,3mi vetores, 2048d), quantização binária | 5.1, 155.04 GB | S30-high-cpu 8 GB 213 GB 4 vCPUs | $0.24/hr |
binData
Compactação de vetor
Para o grande conjunto de dados, utilizamos um recurso adicional chamado compactação vetorial, que reduz a pegada de cada vetor na coleção de origem em cerca de 60%. Isso acelera a etapa dentro de uma query quando os IDs são hidratados na coleção de origem, e essa é uma etapa recomendada para todas as grandes cargas de trabalho.
Concurrency
Avaliamos não apenas a latência da query serial, mas também a taxa de transferência/QPS quando 10 e 100 solicitações são emitidas simultaneamente.
Observação
O mecanismo recomendado para lidar com uma maior taxa de transferência é o dimensionamento horizontal do número de nós de pesquisa, o que não medimos nestes testes.
Fragmentação
Avaliamos o impacto da fragmentação do nosso cluster e da nossa coleção no campo _id
sobre a taxa de transferência do sistema, com foco na simultaneidade de solicitações de 10 e 100 para o grande índice quantizado binário.