Para agentes de IA: um índice de documentação está disponível em https://www.mongodb.com/pt-br/docs/llms.txt — as versões de markdown de todas as páginas estão disponíveis anexando .md a qualquer caminho de URL.
Menu Docs

Crie uma arquitetura multilocatário para a Vector Search do MongoDB

You can implement multi-tenancy with MongoDB Vector Search so that a single instance of an application serves multiple tenants. This page describes design recommendations that apply specifically to MongoDB Vector Search. These recommendations differ from our multi-tenancy recommendations for Atlas.

Consulte as recomendações a seguir ao projetar uma arquitetura multilocatária para o MongoDB Vector Search.

Importante

Esta orientação pressupõe que você pode colocar locatários em uma única VPC. Caso contrário, você deve manter projetos separados para cada locatário, o que não recomendamos para o MongoDB Vector Search.

Recomendamos armazenar todos os dados do locatário em uma única coleção, e em um único banco de dados e cluster. Você pode distinguir entre locatários incluindo um campo tenant_id em cada documento. Este campo pode ser qualquer identificador único para o locatário, como um UUID ou um nome de locatário. Você pode usar este campo como um pré-filtro em seus índices de pesquisa do MongoDB Vector Search e consultas.

Essa abordagem centralizada oferece os seguintes benefícios:

  • Simples de modelar e dimensionar.

  • Simplifica as operações de manutenção.

  • Roteamento eficiente de query por meio de pré-filtragem por tenant_id.

    Observação

    Este filtro garante que as query retornem dados apenas para locatários que correspondem a este filtro.

Não recomendamos armazenar cada locatário em uma coleção ou banco de dados separado pelos seguintes motivos:

  • Impacto no desempenho: essa abordagem pode levar à variação das cargas de fluxo de alterações, dependendo do número de coleções, o que pode impactar negativamente o desempenho e os recursos de monitoramento.

  • Sem isolamento adicional: As garantias de isolamento de dados no Atlas se aplicam no nível do banco de dados. O uso de coleções separadas dentro do mesmo banco de dados não oferece nenhum benefício adicional de isolamento de dados. O uso de bancos de dados separados introduz complexidade operacional sem vantagens de segurança significativas para a maioria dos casos de uso.

Em vez disso, use uma coleção para todos os locatários. Para um exemplo de como migrar de um modelo de coleção por locatário para um modelo de coleção única, veja Migrando de um modelo de coleção por locatário.

Considere as seguintes estratégias para mitigar possíveis problemas de desempenho com a abordagem recomendada.

Se você tiver muitos locatários com relativamente poucos documentos cada, ou se tiver problemas de desempenho devido à distribuição desigual de dados (alguns locatários grandes e muitos locatários pequenos), considere as estratégias a seguir.

Se você tiver muitos locatários (até 1 milhões) e cada locatário tiver relativamente poucos documentos (menos 10 de,000 documentos cada), use um flat índice em vez do índice hierárquico Navigable Small Worlds padrão. Para criar um índice plano, defina o indexingMethod campo como flat em sua definição de índice.

When each tenant has a small number of documents, queries filtered to a specific tenant are already searched exhaustively. In these cases, the Hierarchical Navigable Small Worlds graph provides no benefit but adds memory and maintenance overhead. Flat indexes eliminate this unnecessary overhead.

Os índices planos oferecem os seguintes benefícios para cargas de trabalho de vários inquilinos:

  • Otimizado para filtros seletivos: para queries altamente seletivas em que cada locatário tem um pequeno número de documentos, a verificação exaustiva já é o caminho mais rápido. Os índices planos suportam isso diretamente, melhorando a latência e a recuperação.

  • Desempenho previsível: a latência da query permanece dentro de uma faixa estreita, independentemente de qual locatário é direcionado, eliminando os efeitos de vizinhos ruidosos entre os locatários.

  • Eficiência de recursos: Os índices planos eliminam a sobrecarga de memória e manutenção associada à criação de grafos hierárquicos navegáveis em pequenos mundos.

Por exemplo, as seguintes definições de índice criam um índice plano com um campo de filtro tenant_id. Selecione o tipo autoEmbed se quiser que o MongoDB pesquisa vetorial gere automaticamente embedding usando modelos Voyage AI, ou o tipo vector se já tiver embedding:

Exemplo: Índice de embedding automatizado
{
"fields": [
{
"type": "autoEmbed",
"modality": "text",
"path": "<fieldToIndex>",
"model": "<embeddingModel>",
"indexingMethod": "flat"
},
{
"type": "filter",
"path": "tenant_id"
}
]
}
Exemplo: Índice de vetor
{
"fields": [
{
"type": "vector",
"path": "<fieldToIndex>",
"numDimensions": <numberOfDimensions>,
"similarity": "euclidean | cosine | dotProduct",
"indexingMethod": "flat"
},
{
"type": "filter",
"path": "tenant_id"
}
]
}

Observação

Os índices planos são compatíveis com quantização escalar e binária, quer você use o embedding automatizado com o tipo autoEmbed ou use embeddings existentes com o tipo vector. Sempre inclua o campo tenant_id como pré-filtro em suas query ao usar índices planos.

Para locatários maiores que têm mais 10 de,000 documentos cada, utilize índices hierárquicos navigable Small Worlds em visualizações MongoDB para separar locatários grandes de locatários menores:

  • Locatários grandes (1% principal):

    • Crie uma visualização para cada grande locatário.

    • Crie um índice hierárquico navegável de pequenos mundos para cada visualização.

    • Mantenha um registro de grandes locatários que você verifica no momento da query para direcionar as queries de forma adequada.

  • Pequenos Locatários (Locatários Remanescentes):

    • Crie uma única visualização para todos os pequenos locatários.

    • Crie um único índice plano para essa visualização.

    • Utilize o campo tenant_id como um pré-filtro para direcionar queries de forma adequada.

The following example demonstrates how to create views for large and small tenants by using mongosh:

Mantenha um registro de seus grandes locatários e seus valores tenant_id correspondentes, e então crie uma visualização para cada um desses locatários:

db.createView(
"<viewName>",
"<collectionName>",
[
{
"$match": {
"tenant_id": "<largeTenantId>"
}
}
]
)

Crie uma visualização para os pequenos locatários, com filtro para os grandes locatários:

db.createView(
"<viewName>",
"<collectionName>",
[
{
"$match": {
"tenant_id": {
"$nin": [ "<largeTenantId1>", "<largeTenantId2>", ... ]
}
}
}
]
)

Após criar as visualizações, crie os índices para cada visualização. Verifique o seguinte:

  • Ao especificar o nome da coleção para o índice, utilize o nome da visualização em vez do nome original da coleção.

  • Para grandes visualizações de locatários, crie um índice Hierarchical Navigable Small Worlds (o padrão).

  • For the small tenant view, create an index with the flat indexing method and include the tenant_id field as a pre-filter.

Consulte a página Criar índices para obter instruções sobre como criar índices.

If you have many tenants that each have a large number of documents, consider using a partition-based system by distributing data across shards.

Você pode usar o campo tenant_id como uma chave de fragmento para distribuir os dados em faixas específicas com base no ID do locatário. Para obter mais informações, consulte Fragmentação à distância.

Para migrar de um modelo de coleção por locatário para um modelo de coleção única, processe cada coleção de locatário e insira os documentos em uma nova coleção.

Script de amostra para migração de dados

For example, the following script uses the Node.js driver to migrate your data from a collection-per-tenant model to a single collection model. The script also includes a tenant_id field for each document based on the source collection's name.

migrar-coleções.js
import { MongoClient } from 'mongodb';
const uri = "<connectionString>";
const sourceDbName = "<sourceDatabaseName>";
const targetDbName = "<targetDatabaseName>";
const targetCollectionName = "<targetCollectionName>";
async function migrateCollections() {
const client = new MongoClient(uri);
try {
await client.connect();
const sourceDb = client.db(sourceDbName);
const targetDb = client.db(targetDbName);
const targetCollection = targetDb.collection(targetCollectionName);
const collections = await sourceDb.listCollections().toArray();
console.log(`Found ${collections.length} collections.`);
const BATCH_SIZE = 1000; // Define a suitable batch size based on your requirements
let totalProcessed = 0;
for (const collectionInfo of collections) {
const collection = sourceDb.collection(collectionInfo.name);
let documentsProcessed = 0;
let batch = [];
const tenantId = collectionInfo.name; // Uses the collection name as the tenant_id
const cursor = collection.find({});
for await (const doc of cursor) {
doc.tenant_id = tenantId; // Adds a tenant_id field to each document
batch.push(doc);
if (batch.length >= BATCH_SIZE) {
await targetCollection.insertMany(batch);
totalProcessed += batch.length;
documentsProcessed += batch.length;
console.log(`Processed ${documentsProcessed} documents from ${collectionInfo.name}. Total processed: ${totalProcessed}`);
batch = [];
}
}
if (batch.length > 0) {
await targetCollection.insertMany(batch);
totalProcessed += batch.length;
documentsProcessed += batch.length;
console.log(`Processed ${documentsProcessed} documents from ${collectionInfo.name}. Total processed: ${totalProcessed}`);
}
}
console.log(`Migration completed. Total documents processed: ${totalProcessed}`);
} catch (err) {
console.error('An error occurred:', err);
} finally {
await client.close();
}
}
await migrateCollections().catch(console.error);