إشعار
يتطلب الوصول إلى هذه الصفحة تخويلاً. يمكنك محاولة تسجيل الدخول أو تغيير الدلائل.
يتطلب الوصول إلى هذه الصفحة تخويلاً. يمكنك محاولة تغيير الدلائل.
استخدم البحث المتجه في Azure DocumentDB مع مكتبة العملاء Node.js. تخزين البيانات المتجهة والاستعلام عنها بكفاءة.
يستخدم هذا التشغيل السريع عينة من مجموعة بيانات الفندق في ملف JSON مع متجهات من text-embedding-3-small النموذج. تتضمن مجموعة البيانات أسماء الفنادق والمواقع والأوصاف وتضمينات المتجهات.
ابحث عن نموذج التعليمات البرمجية على GitHub.
Prerequisites
اشتراك Azure
- إذا لم يكن لديك اشتراك Azure، فقم بإنشاء حساب مجاني
مجموعة Azure DocumentDB موجودة
-
تم تكوين النطاق المخصص
text-embedding-3-smallتم نشر النموذج
استخدم بيئة Bash في Azure Cloud Shell. لمزيد من المعلومات، راجع بدء استخدام Azure Cloud Shell.
إذا كنت تفضل تشغيل أوامر مرجع CLI محلياً قم بتثبيت CLI Azure. إذا كنت تعمل على نظام تشغيل Windows أو macOS، ففكر في تشغيل Azure CLI في حاوية Docker. لمزيد من المعلومات، راجع كيفية تشغيل Azure CLI في حاوية Docker.
إذا كنت تستخدم تثبيت محلي، يُرجى تسجيل الدخول إلى Azure CLI مستخدمًا أمر az login. لإنهاء عملية المصادقة، اتبع الخطوات المعروضة في جهازك. للحصول على خيارات تسجيل الدخول الأخرى، راجع المصادقة على Azure باستخدام Azure CLI.
عندما يُطلب منك، قم بتثبيت ملحق Azure CLI عند الاستخدام لأول مرة. لمزيد من المعلومات حول الملحقات، راجع استخدام الملحقات وإدارتها باستخدام Azure CLI.
يُرجى تشغيل إصدار az للوصول إلى الإصدار والمكتبات التابعة التي تم تثبيتها. للتحديث لآخر إصدار، يُرجى تشغيل تحديث az.
TypeScript: تثبيت TypeScript عالميا:
npm install -g typescript
إنشاء ملف بيانات باستخدام المتجهات
أنشئ مجلد بيانات جديد لملف بيانات الفندق:
mkdir dataانسخ
Hotels_Vector.jsonملف البيانات الخام باستخدام المتجهات إلى الدليل الخاص بكdata.
إنشاء مشروع Node.js
أنشئ مجلد شقيقة جديد لمشروعك، على نفس مستوى مجلد البيانات، وافتحه في كود Visual Studio:
mkdir vector-search-quickstart code vector-search-quickstartفي المحطة الطرفية، قم بتهيئة مشروع Node.js:
npm init -y npm pkg set type="module"قم بتثبيت الحزم المطلوبة:
npm install mongodb @azure/identity openai @types/node-
mongodbبرنامج تشغيل MongoDB Node.js: -
@azure/identityمكتبة هوية Azure للمصادقة بدون كلمة مرور: -
openaiمكتبة عميل OpenAI لإنشاء متجهات: -
@types/nodeتعريفات النوع ل Node.js:
-
قم بإنشاء
.envملف في جذر المشروع لمتغيرات البيئة:# Identity for local developer authentication with Azure CLI AZURE_TOKEN_CREDENTIALS=AzureCliCredential # Azure OpenAI Embedding Settings AZURE_OPENAI_EMBEDDING_MODEL=text-embedding-3-small 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=../data/Hotels_Vector.json FIELD_TO_EMBED=Description EMBEDDED_FIELD=DescriptionVector EMBEDDING_DIMENSIONS=1536 LOAD_SIZE_BATCH=100استبدل قيم العناصر النائبة في الملف
.envبمعلوماتك الخاصة:-
AZURE_OPENAI_EMBEDDING_ENDPOINTعنوان URL لنقطة نهاية مورد Azure OpenAI: -
MONGO_CLUSTER_NAME: اسم موردك
-
أضف ملفا
tsconfig.jsonلتكوين 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" ] }
إنشاء برامج نصية npm
قم بتحرير الملف package.json وإضافة هذه البرامج النصية:
استخدم هذه البرامج النصية لتجميع ملفات TypeScript وتشغيل تنفيذ فهرس DiskANN.
"scripts": {
"build": "tsc",
"start:diskann": "node --env-file .env dist/diskann.js"
}
إنشاء ملفات التعليمات البرمجية للبحث المتجه
قم بإنشاء src دليل لملفات TypeScript الخاصة بك. أضف ملفين: diskann.ts ولتنفيذ utils.ts فهرس DiskANN:
mkdir src
touch src/diskann.ts
touch src/utils.ts
إنشاء رمز للبحث المتجه
الصق الكود التالي في الملف diskann.ts .
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;
});
توفر هذه الوحدة الرئيسية هذه الميزات:
- يتضمن وظائف الأداة المساعدة
- إنشاء كائن تكوين لمتغيرات البيئة
- ينشئ عملاء ل Azure OpenAI و DocumentDB
- يتصل ب MongoDB ، وينشئ قاعدة بيانات ومجموعة ، ويدرج البيانات ، وينشئ فهارس قياسية
- ينشئ فهرس متجه باستخدام IVF أو HNSW أو DiskANN
- ينشئ تضمينا لعينة نص استعلام باستخدام عميل OpenAI. يمكنك تغيير الاستعلام في أعلى الملف
- تشغيل بحث متجه باستخدام التضمين وطباعة النتائج
إنشاء وظائف الأداة المساعدة
الصق الكود التالي في 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 mongoConnectionString = process.env.MONGO_CONNECTION_STRING!;
if (!apiKey || !apiVersion || !endpoint || !deployment || !mongoConnectionString) {
throw new Error('Missing required environment variables: AZURE_OPENAI_EMBEDDING_KEY, AZURE_OPENAI_EMBEDDING_API_VERSION, AZURE_OPENAI_EMBEDDING_ENDPOINT, AZURE_OPENAI_EMBEDDING_MODEL, MONGO_CONNECTION_STRING');
}
const aiClient = new AzureOpenAI({
apiKey,
apiVersion,
endpoint,
deployment
});
const dbClient = new MongoClient(mongoConnectionString, {
// 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;
// Validate all required environment variables upfront
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 clusterName = process.env.MONGO_CLUSTER_NAME!;
if (!apiVersion || !endpoint || !deployment || !clusterName) {
throw new Error('Missing required environment variables: AZURE_OPENAI_EMBEDDING_API_VERSION, AZURE_OPENAI_EMBEDDING_ENDPOINT, AZURE_OPENAI_EMBEDDING_MODEL, MONGO_CLUSTER_NAME');
}
console.log(`Using Azure OpenAI Embedding API Version: ${apiVersion}`);
console.log(`Using Azure OpenAI Embedding Deployment/Model: ${deployment}`);
const credential = new DefaultAzureCredential();
// For Azure OpenAI with DefaultAzureCredential
{
const scope = "https://cognitiveservices.azure.com/.default";
const azureADTokenProvider = getBearerTokenProvider(credential, scope);
aiClient = new AzureOpenAI({
apiVersion,
endpoint,
deployment,
azureADTokenProvider
});
}
// For DocumentDB with DefaultAzureCredential (uses signed-in user)
{
dbClient = new MongoClient(
`mongodb+srv://${clusterName}.mongocluster.cosmos.azure.com/`, {
connectTimeoutMS: 120000,
tls: true,
retryWrites: false,
maxIdleTimeMS: 120000,
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}`);
});
}
توفر وحدة الأداة المساعدة هذه الميزات:
-
JsonDataواجهة لبنية البيانات: -
scorePropertyموقع النتيجة في نتائج الاستعلام استنادا إلى طريقة البحث المتجه: -
getClients: ينشئ ويعيد العملاء ل Azure OpenAI و Azure DocumentDB -
getClientsPasswordless: ينشئ ويعيد العملاء ل Azure OpenAI و Azure DocumentDB باستخدام المصادقة بدون كلمة مرور. تمكين RBAC على كلا المواردين وتسجيل الدخول إلى Azure CLI -
readFileReturnJsonيقرأ ملف JSON ويعيد محتوياته كمصفوفة منJsonDataالكائنات: -
writeFileJsonيكتب مصفوفة منJsonDataالكائنات إلى ملف JSON: -
insertDataإدراج البيانات على دفعات في مجموعة MongoDB وإنشاء فهارس قياسية في حقول محددة: -
printSearchResultsطباعة نتائج بحث متجه، بما في ذلك النتيجة واسم الفندق:
المصادقة باستخدام Azure CLI
قم بتسجيل الدخول إلى Azure CLI قبل تشغيل التطبيق حتى يتمكن التطبيق من الوصول إلى موارد Azure بأمان.
az login
يستخدم الكود مصادقة المطور المحلي للوصول إلى Azure DocumentDB وAzure OpenAI باستخدام الدالة getClientsPasswordless من utils.ts. عند تعيين AZURE_TOKEN_CREDENTIALS=AzureCliCredential، هذا الإعداد يخبر الدالة باستخدام بيانات اعتماد Azure CLI للمصادقة بشكل حتمية. تعتمد الوظيفة على DefaultAzureCredential من @azure/identity للعثور على بيانات اعتماد Azure الخاصة بك في البيئة. تعرف أكثر على كيفية مصادقة تطبيقات جافاسكريبت على خدمات Azure باستخدام مكتبة Azure Identity.
بناء وتشغيل التطبيق
قم بإنشاء ملفات TypeScript، ثم قم بتشغيل التطبيق:
يظهر تسجيل التطبيق وإخراجه:
- إنشاء المجموعة وحالة إدراج البيانات
- إنشاء فهرس المتجهات
- نتائج البحث مع أسماء الفنادق ودرجات التشابه
Using Azure OpenAI Embedding API Version: 2023-05-15
Using Azure OpenAI Embedding Deployment/Model: text-embedding-3-small-2
Created collection: hotels_diskann
Reading JSON file from \documentdb-samples\ai\data\Hotels_Vector.json
Processing in batches of 50...
Batch 1 complete: 50 inserted
Created vector index: vectorIndex_diskann
1. HotelName: Royal Cottage Resort, Score: 0.4991
2. HotelName: Country Comfort Inn, Score: 0.4785
3. HotelName: Nordick's Valley Motel, Score: 0.4635
4. HotelName: Economy Universe Motel, Score: 0.4461
5. HotelName: Roach Motel, Score: 0.4388
Closing database connection...
Database connection closed
عرض البيانات وإدارتها في Visual Studio Code
اختر إضافة DocumentDB في كود Visual Studio للاتصال بحساب Azure DocumentDB الخاص بك.
عرض البيانات والفهارس في قاعدة بيانات الفنادق.
تنظيف الموارد
احذف مجموعة الموارد، وحساب DocumentDB، ومورد Azure OpenAI عندما لا تحتاجها لتجنب التكاليف الإضافية.