Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Utilisez la recherche vectorielle dans Azure DocumentDB avec la bibliothèque cliente Node.js. Stockez et interrogez efficacement les données vectorielles.
Ce guide de démarrage rapide utilise un exemple de jeu de données d’hôtel dans un fichier JSON avec des vecteurs du text-embedding-ada-002 modèle. Le jeu de données comprend des noms d’hôtel, des emplacements, des descriptions et des incorporations vectorielles.
Recherchez l’exemple de code sur GitHub.
Prerequisites
Un abonnement Azure
- Si vous n’avez pas d’abonnement Azure, créez un compte gratuit
Un cluster Azure DocumentDB existant
- Si vous n’avez pas de cluster, créez un cluster
Pare-feu configuré pour autoriser l’accès à votre adresse IP cliente
-
text-embedding-ada-002modèle déployé
Utilisez l’environnement Bash dans Azure Cloud Shell. Pour obtenir plus d’informations, consultez Démarrage d’Azure Cloud Shell.
Si vous préférez exécuter des commandes de référence CLI localement, installez Azure CLI. Si vous exécutez sur Windows ou macOS, envisagez d’exécuter Azure CLI dans un conteneur Docker. Pour plus d’informations, consultez Comment exécuter Azure CLI dans un conteneur Docker.
Si vous utilisez une installation locale, connectez-vous à Azure CLI à l’aide de la commande az login. Pour terminer le processus d’authentification, suivez les étapes affichées dans votre terminal. Pour obtenir d’autres options de connexion, consultez S’authentifier auprès d’Azure à l’aide d’Azure CLI.
Lorsque vous y êtes invité, installez l’extension Azure CLI lors de la première utilisation. Pour plus d’informations sur les extensions, consultez Utiliser et gérer des extensions avec Azure CLI.
Exécutez az version pour rechercher la version et les bibliothèques dépendantes installées. Pour effectuer une mise à niveau vers la dernière version, exécutez az upgrade.
TypeScript : Installez TypeScript globalement :
npm install -g typescript
Créer un projet Node.js
Créez un répertoire pour votre projet et ouvrez-le dans Visual Studio Code :
mkdir vector-search-quickstart code vector-search-quickstartDans le terminal, initialisez un projet Node.js :
npm init -y npm pkg set type="module"Installez les packages nécessaires :
npm install mongodb @azure/identity openai @types/node-
mongodb: pilote Node.js MongoDB -
@azure/identity: Bibliothèque d’identités Azure pour l’authentification sans mot de passe -
openai: Bibliothèque de client OpenAI pour créer des vecteurs -
@types/node: définitions de types pour Node.js
-
Créez un
.envfichier à la racine de votre projet pour les variables d’environnement :# Azure OpenAI Embedding Settings AZURE_OPENAI_EMBEDDING_MODEL=text-embedding-ada-002 AZURE_OPENAI_EMBEDDING_API_VERSION=2023-05-15 AZURE_OPENAI_EMBEDDING_ENDPOINT= EMBEDDING_SIZE_BATCH=16 # MongoDB configuration MONGO_CLUSTER_NAME= # Data file DATA_FILE_WITH_VECTORS=HotelsData_toCosmosDB_Vector.json EMBEDDED_FIELD=text_embedding_ada_002 EMBEDDING_DIMENSIONS=1536 LOAD_SIZE_BATCH=100Remplacez les valeurs de substitution dans le fichier
.envpar vos propres informations.-
AZURE_OPENAI_EMBEDDING_ENDPOINT: URL de votre point de terminaison de ressource Azure OpenAI -
MONGO_CLUSTER_NAME: Nom de votre ressource
-
Ajoutez un
tsconfig.jsonfichier pour configurer TypeScript :{ "compilerOptions": { "target": "ES2020", "module": "NodeNext", "moduleResolution": "nodenext", "declaration": true, "outDir": "./dist", "strict": true, "esModuleInterop": true, "skipLibCheck": true, "noImplicitAny": false, "forceConsistentCasingInFileNames": true, "sourceMap": true, "resolveJsonModule": true, }, "include": [ "src/**/*" ], "exclude": [ "node_modules", "dist" ] }Copiez le
HotelsData_toCosmosDB_Vector.jsonfichier de données brutes avec des vecteurs à la racine de votre projet.
Créer des scripts npm
Modifiez le package.json fichier et ajoutez ces scripts :
Utilisez ces scripts pour compiler des fichiers TypeScript et exécuter l’implémentation d’index DiskANN.
"scripts": {
"build": "tsc",
"start:diskann": "node --env-file .env dist/diskann.js"
}
Créer des fichiers de code pour la recherche vectorielle
Créez un src répertoire pour vos fichiers TypeScript. Ajoutez deux fichiers : diskann.ts et utils.ts pour l’implémentation d’index DiskANN :
mkdir src
touch src/diskann.ts
touch src/utils.ts
Créer du code pour la recherche vectorielle
Collez le code suivant dans le diskann.ts fichier.
import path from 'path';
import { readFileReturnJson, getClientsPasswordless, insertData, printSearchResults } from './utils.js';
// ESM specific features - create __dirname equivalent
import { fileURLToPath } from "node:url";
import { dirname } from "node:path";
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const config = {
query: "quintessential lodging near running trails, eateries, retail",
dbName: "Hotels",
collectionName: "hotels_diskann",
indexName: "vectorIndex_diskann",
dataFile: process.env.DATA_FILE_WITH_VECTORS!,
batchSize: parseInt(process.env.LOAD_SIZE_BATCH! || '100', 10),
embeddedField: process.env.EMBEDDED_FIELD!,
embeddingDimensions: parseInt(process.env.EMBEDDING_DIMENSIONS!, 10),
deployment: process.env.AZURE_OPENAI_EMBEDDING_MODEL!,
};
async function main() {
const { aiClient, dbClient } = getClientsPasswordless();
try {
if (!aiClient) {
throw new Error('AI client is not configured. Please check your environment variables.');
}
if (!dbClient) {
throw new Error('Database client is not configured. Please check your environment variables.');
}
await dbClient.connect();
const db = dbClient.db(config.dbName);
const collection = await db.createCollection(config.collectionName);
console.log('Created collection:', config.collectionName);
const data = await readFileReturnJson(path.join(__dirname, "..", config.dataFile));
const insertSummary = await insertData(config, collection, data);
console.log('Created vector index:', config.indexName);
// Create the vector index
const indexOptions = {
createIndexes: config.collectionName,
indexes: [
{
name: config.indexName,
key: {
[config.embeddedField]: 'cosmosSearch'
},
cosmosSearchOptions: {
kind: 'vector-diskann',
dimensions: config.embeddingDimensions,
similarity: 'COS', // 'COS', 'L2', 'IP'
maxDegree: 20, // 20 - 2048, edges per node
lBuild: 10 // 10 - 500, candidate neighbors evaluated
}
}
]
};
const vectorIndexSummary = await db.command(indexOptions);
// Create embedding for the query
const createEmbeddedForQueryResponse = await aiClient.embeddings.create({
model: config.deployment,
input: [config.query]
});
// Perform the vector similarity search
const searchResults = await collection.aggregate([
{
$search: {
cosmosSearch: {
vector: createEmbeddedForQueryResponse.data[0].embedding,
path: config.embeddedField,
k: 5
}
}
},
{
$project: {
score: {
$meta: "searchScore"
},
document: "$$ROOT"
}
}
]).toArray();
// Print the results
printSearchResults(insertSummary, vectorIndexSummary, searchResults);
} catch (error) {
console.error('App failed:', error);
process.exitCode = 1;
} finally {
console.log('Closing database connection...');
if (dbClient) await dbClient.close();
console.log('Database connection closed');
}
}
// Execute the main function
main().catch(error => {
console.error('Unhandled error:', error);
process.exitCode = 1;
});
Ce module principal fournit les fonctionnalités suivantes :
- Inclut les fonctions utilitaires
- Crée un objet de configuration pour les variables d’environnement
- Crée des clients pour Azure OpenAI et DocumentDB
- Se connecte à MongoDB, crée une base de données et une collection, insère des données et crée des index standard
- Crée un index vectoriel à l’aide d’IVF, HNSW ou DiskANN
- Crée un encodage pour un texte de requête d'exemple avec le client OpenAI. Vous pouvez modifier la requête en haut du fichier
- Exécute une recherche vectorielle à l’aide de l’incorporation et imprime les résultats
Créer des fonctions utilitaires
Collez le code suivant dans utils.ts:
import { MongoClient, OIDCResponse, OIDCCallbackParams } from 'mongodb';
import { AzureOpenAI } from 'openai/index.js';
import { promises as fs } from "fs";
import { AccessToken, DefaultAzureCredential, TokenCredential, getBearerTokenProvider } from '@azure/identity';
// Define a type for JSON data
export type JsonData = Record<string, any>;
export const AzureIdentityTokenCallback = async (params: OIDCCallbackParams, credential: TokenCredential): Promise<OIDCResponse> => {
const tokenResponse: AccessToken | null = await credential.getToken(['https://ossrdbms-aad.database.windows.net/.default']);
return {
accessToken: tokenResponse?.token || '',
expiresInSeconds: (tokenResponse?.expiresOnTimestamp || 0) - Math.floor(Date.now() / 1000)
};
};
export function getClients(): { aiClient: AzureOpenAI; dbClient: MongoClient } {
const apiKey = process.env.AZURE_OPENAI_EMBEDDING_KEY!;
const apiVersion = process.env.AZURE_OPENAI_EMBEDDING_API_VERSION!;
const endpoint = process.env.AZURE_OPENAI_EMBEDDING_ENDPOINT!;
const deployment = process.env.AZURE_OPENAI_EMBEDDING_MODEL!;
const aiClient = new AzureOpenAI({
apiKey,
apiVersion,
endpoint,
deployment
});
const dbClient = new MongoClient(process.env.MONGO_CONNECTION_STRING!, {
// Performance optimizations
maxPoolSize: 10, // Limit concurrent connections
minPoolSize: 1, // Maintain at least one connection
maxIdleTimeMS: 30000, // Close idle connections after 30 seconds
connectTimeoutMS: 30000, // Connection timeout
socketTimeoutMS: 360000, // Socket timeout (for long-running operations)
writeConcern: { // Optimize write concern for bulk operations
w: 1, // Acknowledge writes after primary has written
j: false // Don't wait for journal commit
}
});
return { aiClient, dbClient };
}
export function getClientsPasswordless(): { aiClient: AzureOpenAI | null; dbClient: MongoClient | null } {
let aiClient: AzureOpenAI | null = null;
let dbClient: MongoClient | null = null;
// For Azure OpenAI with DefaultAzureCredential
const apiVersion = process.env.AZURE_OPENAI_EMBEDDING_API_VERSION!;
const endpoint = process.env.AZURE_OPENAI_EMBEDDING_ENDPOINT!;
const deployment = process.env.AZURE_OPENAI_EMBEDDING_MODEL!;
if (apiVersion && endpoint && deployment) {
const credential = new DefaultAzureCredential();
const scope = "https://cognitiveservices.azure.com/.default";
const azureADTokenProvider = getBearerTokenProvider(credential, scope);
aiClient = new AzureOpenAI({
apiVersion,
endpoint,
deployment,
azureADTokenProvider
});
}
// For Cosmos DB with DefaultAzureCredential
const clusterName = process.env.MONGO_CLUSTER_NAME!;
if (clusterName) {
const credential = new DefaultAzureCredential();
dbClient = new MongoClient(
`mongodb+srv://${clusterName}.global.mongocluster.cosmos.azure.com/`, {
connectTimeoutMS: 30000,
tls: true,
retryWrites: true,
authMechanism: 'MONGODB-OIDC',
authMechanismProperties: {
OIDC_CALLBACK: (params: OIDCCallbackParams) => AzureIdentityTokenCallback(params, credential),
ALLOWED_HOSTS: ['*.azure.com']
}
}
);
}
return { aiClient, dbClient };
}
export async function readFileReturnJson(filePath: string): Promise<JsonData[]> {
console.log(`Reading JSON file from ${filePath}`);
const fileAsString = await fs.readFile(filePath, "utf-8");
return JSON.parse(fileAsString);
}
export async function writeFileJson(filePath: string, jsonData: JsonData): Promise<void> {
const jsonString = JSON.stringify(jsonData, null, 2);
await fs.writeFile(filePath, jsonString, "utf-8");
console.log(`Wrote JSON file to ${filePath}`);
}
export async function insertData(config, collection, data) {
console.log(`Processing in batches of ${config.batchSize}...`);
const totalBatches = Math.ceil(data.length / config.batchSize);
let inserted = 0;
let updated = 0;
let skipped = 0;
let failed = 0;
for (let i = 0; i < totalBatches; i++) {
const start = i * config.batchSize;
const end = Math.min(start + config.batchSize, data.length);
const batch = data.slice(start, end);
try {
const result = await collection.insertMany(batch, { ordered: false });
inserted += result.insertedCount || 0;
console.log(`Batch ${i + 1} complete: ${result.insertedCount} inserted`);
} catch (error: any) {
if (error?.writeErrors) {
// Some documents may have been inserted despite errors
console.error(`Error in batch ${i + 1}: ${error?.writeErrors.length} failures`);
failed += error?.writeErrors.length;
inserted += batch.length - error?.writeErrors.length;
} else {
console.error(`Error in batch ${i + 1}:`, error);
failed += batch.length;
}
}
// Small pause between batches to reduce resource contention
if (i < totalBatches - 1) {
await new Promise(resolve => setTimeout(resolve, 100));
}
}
const indexColumns = [
"HotelId",
"Category",
"Description",
"Description_fr"
];
for (const col of indexColumns) {
const indexSpec = {};
indexSpec[col] = 1; // Ascending index
await collection.createIndex(indexSpec);
}
return { total: data.length, inserted, updated, skipped, failed };
}
export function printSearchResults(insertSummary, indexSummary, searchResults) {
if (!searchResults || searchResults.length === 0) {
console.log('No search results found.');
return;
}
searchResults.map((result, index) => {
const { document, score } = result as any;
console.log(`${index + 1}. HotelName: ${document.HotelName}, Score: ${score.toFixed(4)}`);
//console.log(` Description: ${document.Description}`);
});
}
Ce module utilitaire fournit les fonctionnalités suivantes :
-
JsonData: interface pour la structure de données -
scoreProperty: Emplacement du score dans les résultats de requête en fonction de la méthode de recherche vectorielle -
getClients: crée et retourne des clients pour Azure OpenAI et Azure DocumentDB -
getClientsPasswordless: crée et retourne des clients pour Azure OpenAI et Azure DocumentDB à l’aide de l’authentification sans mot de passe. Activer RBAC sur les deux ressources et se connecter à Azure CLI -
readFileReturnJson: lit un fichier JSON et retourne son contenu sous la forme d’un tableau d’objetsJsonData -
writeFileJson: écrit un tableau d’objetsJsonDatadans un fichier JSON -
insertData: insère des données dans des lots dans une collection MongoDB et crée des index standard sur des champs spécifiés -
printSearchResults: imprime les résultats d’une recherche vectorielle, y compris le score et le nom de l’hôtel
S’authentifier auprès d’Azure CLI
Connectez-vous à Azure CLI avant d’exécuter l’application afin qu’elle puisse accéder en toute sécurité aux ressources Azure.
az login
Générer et exécuter l’application
Générez les fichiers TypeScript, puis exécutez l’application :
La journalisation et la sortie de l’application indiquent :
- Création de regroupements et état d’insertion des données
- Création d'un index vectoriel
- Résultats de recherche avec des noms d’hôtel et des scores de similarité
Created collection: hotels_diskann
Reading JSON file from C:\Users\<username>\repos\samples\cosmos-db-vector-samples\data\HotelsData_toCosmosDB_Vector.json
Processing in batches of 100...
Batch 1 complete: 50 inserted
Created vector index: vectorIndex_diskann
1. HotelName: Roach Motel, Score: 0.8399
2. HotelName: Royal Cottage Resort, Score: 0.8385
3. HotelName: Economy Universe Motel, Score: 0.8360
4. HotelName: Foot Happy Suites, Score: 0.8354
5. HotelName: Country Comfort Inn, Score: 0.8346
Closing database connection...
Database connection closed
Afficher et gérer des données dans Visual Studio Code
Sélectionnez l’extension DocumentDB dans Visual Studio Code pour vous connecter à votre compte Azure DocumentDB.
Affichez les données et les index dans la base de données Hotels.
Nettoyer les ressources
Supprimez le groupe de ressources, le compte DocumentDB et la ressource Azure OpenAI lorsque vous n’en avez pas besoin pour éviter des coûts supplémentaires.