Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
Aprenda a usar la búsqueda de vectores en Azure Cosmos DB para almacenar y consultar datos vectoriales de forma eficaz. En este inicio rápido se proporciona una visita guiada de técnicas de búsqueda de vectores clave mediante una aplicación de ejemplo .NET en GitHub.
La aplicación usa un conjunto de datos de hotel de ejemplo en un archivo JSON con vectores calculados del text-embedding-3-small modelo. Los datos del hotel incluyen nombres de hotel, ubicaciones, descripciones e incrustaciones vectoriales.
Prerrequisitos
- Una suscripción de Azure
- Si no tiene una suscripción de Azure, cree una cuenta free
- SDK de .NET 8.0 o posterior
- Azure CLI para desarrolladores (azd)
- Visual Studio Code
Dependencias de la aplicación
La aplicación usa los siguientes paquetes NuGet:
-
Azure.Identity: biblioteca de identidades de Azure para la autenticación sin contraseña con Microsoft Entra ID -
Azure.AI.OpenAI: Azure biblioteca cliente de OpenAI para comunicarse con modelos de IA y crear incrustaciones de vectores -
Microsoft.Extensions.Configuration: gestión de la configuración para los ajustes de la aplicación -
Microsoft.Azure.Cosmos: biblioteca cliente de Azure Cosmos DB para la conectividad y las operaciones de base de datos -
Newtonsoft.Json: biblioteca de serialización y deserialización de JSON popular
Autenticación en Azure
La aplicación de ejemplo usa la autenticación sin contraseña a través de DefaultAzureCredential y Microsoft Entra ID.
Inicie sesión en Azure usando una herramienta compatible como CLI de Azure o Azure PowerShell antes de ejecutar la aplicación para que pueda acceder a los recursos de Azure de manera segura.
Nota:
Asegúrese de que su identidad autenticada tiene los roles de plano de datos necesarios tanto en la cuenta de Azure Cosmos DB como en el recurso de Azure OpenAI.
Aprovisionamiento y configuración de los recursos de la aplicación
Para ejecutar la aplicación de .NET, deberá aprovisionar los recursos Azure necesarios y configurar la aplicación de ejemplo para conectarse a ellos. Este proyecto está configurado para usar la CLI de Azure Developer (azd) para aprovisionar automáticamente los recursos Azure necesarios.
Aprovisionamiento de los recursos
Para aprovisionar recursos:
En un terminal, clone el repositorio de ejemplo:
git clone https://github.com/Azure-Samples/cosmos-db-vector-samples.gitVaya a la carpeta raíz del repositorio clonado (donde
azure.yamlse encuentra), por ejemplo:cd cosmos-db-vector-samplesEjecute el siguiente comando:
azd up
Siga las indicaciones para seleccionar la suscripción y el entorno de Azure.
Qué está provisionado:
-
Azure Cosmos DB: cuenta sin servidor con la base de datos y los contenedores de
Hotels -
Azure OpenAI: Recurso con implementaciones para:
- Modelo de inserción:
text-embedding-3-small - Modelo de chat:
gpt-4.1-mini
- Modelo de inserción:
- Identidad administrada: identidad asignada por el usuario para el acceso seguro.
- Asignaciones de roles de Azure RBAC que permiten el acceso sin contraseña de Microsoft Entra ID para que la identidad administrada tenga acceso a Azure Cosmos DB y Azure OpenAI.
Configuración de la aplicación
Actualice los valores del marcador de posición appsettings.json con los suyos propios.
{
"AzureOpenAI": {
"EmbeddingModel": "text-embedding-3-small",
"ApiVersion": "2023-05-15",
"Endpoint": "https://<your-openai-endpoint>.openai.azure.com"
},
"DataFiles": {
"WithoutVectors": "../../../../data/HotelsData_toCosmosDB.JSON",
"WithVectors": "../../../../data/HotelsData_toCosmosDB_Vector.json"
},
"Embedding": {
"FieldToEmbed": "Description",
"EmbeddedField": "DescriptionVector",
"Dimensions": 1536,
"BatchSize": 16
},
"CosmosDb": {
"Endpoint": "https://<your-cosmosdb-endpoint>.documents.azure.com:443/",
"DatabaseName": "Hotels"
},
"VectorSearch": {
"Query": "quintessential lodging near running trails, eateries, retail",
"TopK": 5
}
}
Compila y ejecuta el proyecto
La aplicación de ejemplo rellena los datos de ejemplo vectorizados en una base de datos de Azure Cosmos DB y le permite ejecutar diferentes tipos de consultas de búsqueda. Cada consulta usa un contenedor diferente dentro de la base de datos.
Use el
dotnet runcomando para iniciar la aplicación:dotnet runLa aplicación imprime un menú para seleccionar las opciones de base de datos y búsqueda:
=== Cosmos DB Vector Samples Menu === Please enter your choice (0-5): 1. Create embeddings for data 2. Show all database indexes 3. Run Flat vector search 4. Run Quantized Flat vector search 5. Run DiskANN vector search 0. ExitEscriba
3y presione Entrar.Una vez que la aplicación rellena la base de datos y ejecuta la búsqueda, verá los cinco hoteles principales que coinciden con la consulta de búsqueda vectorial seleccionada y sus puntuaciones de similitud.
El registro y la salida de la aplicación muestran:
- Estado de creación y inserción de datos de contenedor
- Confirmación de creación de índices vectoriales
- Resultados de búsqueda con nombres de hotel, ubicaciones y puntuaciones de similitud
Salida de ejemplo (abreviada por brevedad):
Starting Flat vector search workflow Container 'hotels_flat' checked Vector index ready. Executing Flat vector search for top 5 results Search Results (5 found using Flat): 1. Royal Cottage Resort (Similarity: 0.4991) 2. Country Comfort Inn (Similarity: 0.4786) 3. Nordick's Valley Motel (Similarity: 0.4635) 4. Economy Universe Motel (Similarity: 0.4461) 5. Roach Motel (Similarity: 0.4388)
Exploración del código de la aplicación
En las secciones siguientes se proporcionan detalles sobre los servicios y el código más importantes de la aplicación de ejemplo. Visit the GitHub repo para explorar el código completo de la aplicación.
Exploración del servicio de búsqueda
El VectorSearchService coordina una búsqueda de similitud vectorial de extremo a extremo utilizando técnicas de búsqueda Flat, QuantizedFlat y DiskANN con incrustaciones de Azure OpenAI.
using Azure.AI.OpenAI;
using Azure.Identity;
using CosmosDbVectorSamples.Models;
using Microsoft.Azure.Cosmos;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System.Reflection;
namespace CosmosDbVectorSamples.Services.VectorSearch;
/// <summary>
/// Service for performing vector similarity searches using Cosmos DB NoSQL.
/// </summary>
public class VectorSearchService
{
private readonly ILogger<VectorSearchService> _logger;
private readonly AzureOpenAIClient _openAIClient;
private readonly CosmosDbService _cosmosService;
private readonly AppConfiguration _config;
public VectorSearchService(ILogger<VectorSearchService> logger, CosmosDbService cosmosService, AppConfiguration config)
{
_logger = logger;
_cosmosService = cosmosService;
_config = config;
_openAIClient = new AzureOpenAIClient(new Uri(_config.AzureOpenAI.Endpoint), new DefaultAzureCredential());
}
/// <summary>
/// Executes a complete vector search workflow: data setup, index creation, query embedding, and search
/// </summary>
public async Task RunSearchAsync(VectorIndexType indexType)
{
try
{
_logger.LogInformation($"Starting {indexType} vector search workflow");
// Setup container (simulating collection behavior)
var collectionSuffix = indexType switch
{
VectorIndexType.Flat => "flat",
VectorIndexType.QuantizedFlat => "quantizedflat",
VectorIndexType.DiskANN => "diskann",
_ => throw new ArgumentException($"Unknown index type: {indexType}")
};
var containerName = $"hotels_{collectionSuffix}";
// Create/Update Vector Index (Ensure container exists first)
await _cosmosService.CreateVectorIndexAsync(
_config.CosmosDb.DatabaseName, containerName,
_config.Embedding.EmbeddedField, indexType, _config.Embedding.Dimensions);
// Get Container
var container = await _cosmosService.GetContainerAsync(_config.CosmosDb.DatabaseName, containerName);
// Load data from file if collection is empty
var assemblyLocation = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? string.Empty;
var dataFilePath = Path.Combine(assemblyLocation, _config.DataFiles.WithVectors);
await _cosmosService.LoadDataIfNeededAsync(container, dataFilePath);
_logger.LogInformation($"Vector index ready. Waiting for indexing to catch up...");
await Task.Delay(5000);
// Create embedding for the query
var embeddingClient = _openAIClient.GetEmbeddingClient(_config.AzureOpenAI.EmbeddingModel);
var queryEmbedding = (await embeddingClient.GenerateEmbeddingAsync(_config.VectorSearch.Query)).Value.ToFloats().ToArray();
_logger.LogInformation($"Generated query embedding with {queryEmbedding.Length} dimensions");
// Execute Cosmos NoSQL Vector Search
var queryText = $@"
SELECT TOP @topK
c AS Document,
VectorDistance(c.{_config.Embedding.EmbeddedField}, @embedding) AS Score
FROM c
ORDER BY VectorDistance(c.{_config.Embedding.EmbeddedField}, @embedding)";
var queryDef = new QueryDefinition(queryText)
.WithParameter("@topK", _config.VectorSearch.TopK)
.WithParameter("@embedding", queryEmbedding);
using var iterator = container.GetItemQueryIterator<SearchResult>(queryDef);
var results = new List<SearchResult>();
_logger.LogInformation($"Executing {indexType} vector search for top {_config.VectorSearch.TopK} results");
while (iterator.HasMoreResults)
{
var response = await iterator.ReadNextAsync();
results.AddRange(response);
}
// Print the results
if (results.Count == 0)
{
_logger.LogInformation("❌ No search results found. Check query terms and data availability.");
}
else
{
_logger.LogInformation($"\n✅ Search Results ({results.Count} found using {indexType}):");
for (int i = 0; i < results.Count; i++)
{
var result = results[i];
var hotelName = result.Document?.HotelName ?? "Unknown Hotel";
_logger.LogInformation($" {i + 1}. {hotelName} (Similarity: {result.Score:F4})");
}
}
}
catch (Exception ex)
{
_logger.LogError(ex, $"{indexType} vector search failed");
throw;
}
}
}
En el código anterior, VectorSearchService realiza las siguientes tareas:
- Determina los nombres de contenedor e índice en función del algoritmo solicitado.
- Crea u obtiene el contenedor de Azure Cosmos DB y carga datos JSON si está vacío.
- Compila las opciones de índice específicas del algoritmo (Flat / QuantizedFlat / DiskANN) y garantiza que el índice vectorial existe.
- Genera una inserción para la consulta configurada a través de Azure OpenAI.
- Construye y ejecuta el flujo de trabajo de búsqueda por agregación
- Deserializa e imprime los resultados
Exploración del servicio Azure Cosmos DB
El CosmosDBService administra las interacciones con Azure Cosmos DB para controlar tareas como cargar datos, creación de índices vectoriales, enumeración de índices e inserciones masivas para la búsqueda de vectores de hotel.
using Azure.Identity;
using CosmosDbVectorSamples.Models;
using Microsoft.Azure.Cosmos;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System.Net;
using System.Collections.ObjectModel;
namespace CosmosDbVectorSamples.Services;
public class CosmosDbService
{
private readonly ILogger<CosmosDbService> _logger;
private readonly AppConfiguration _config;
private readonly CosmosClient _client;
public CosmosDbService(ILogger<CosmosDbService> logger, IConfiguration configuration)
{
_logger = logger;
_config = new AppConfiguration();
configuration.Bind(_config);
var options = new CosmosClientOptions
{
SerializerOptions = new CosmosSerializationOptions
{
PropertyNamingPolicy = CosmosPropertyNamingPolicy.Default,
IgnoreNullValues = true
},
// Allow bulk execution for data loading
AllowBulkExecution = true
};
_client = new CosmosClient(_config.CosmosDb.Endpoint, new DefaultAzureCredential(), options);
}
public Task<Container> GetContainerAsync(string databaseName, string containerName)
{
return Task.FromResult(_client.GetContainer(databaseName, containerName));
}
public async Task CreateVectorIndexAsync(string databaseName, string containerName, string vectorField, VectorIndexType indexType, int dimensions)
{
var database = _client.GetDatabase(databaseName);
_logger.LogInformation($"Ensuring container '{containerName}' exists with vector index '{indexType}'...");
var properties = new ContainerProperties(containerName, "/HotelId");
// Define Vector Embedding Policy
var embeddings = new Collection<Embedding>
{
new Embedding
{
Path = "/" + vectorField,
DataType = VectorDataType.Float32,
DistanceFunction = DistanceFunction.Cosine,
Dimensions = dimensions
}
};
properties.VectorEmbeddingPolicy = new VectorEmbeddingPolicy(embeddings);
// Define Indexing Policy
properties.IndexingPolicy.VectorIndexes.Clear();
var cosmosIndexType = indexType switch
{
VectorIndexType.Flat => Microsoft.Azure.Cosmos.VectorIndexType.Flat,
VectorIndexType.QuantizedFlat => Microsoft.Azure.Cosmos.VectorIndexType.QuantizedFlat,
VectorIndexType.DiskANN => Microsoft.Azure.Cosmos.VectorIndexType.DiskANN,
_ => Microsoft.Azure.Cosmos.VectorIndexType.Flat
};
properties.IndexingPolicy.VectorIndexes.Add(new VectorIndexPath
{
Path = "/" + vectorField,
Type = cosmosIndexType
});
// Use CreateContainerIfNotExistsAsync to behave like TS app (matches on GET if exists)
await database.CreateContainerIfNotExistsAsync(properties);
_logger.LogInformation($"Container '{containerName}' checked/created.");
}
public async Task<int> LoadDataIfNeededAsync(Container container, string dataFilePath)
{
try
{
// TypeScript app does NOT check 'SELECT COUNT(1)' first.
// It simply tries to load data and relies on 409 Conflict for existing items.
// Removed the pre-check to match TypeScript behavior.
_logger.LogInformation($"Loading data from {dataFilePath}...");
var jsonContent = await File.ReadAllTextAsync(dataFilePath);
var items = JsonConvert.DeserializeObject<List<HotelData>>(jsonContent);
if (items == null || items.Count == 0)
{
_logger.LogWarning("No data found in file.");
return 0;
}
var tasks = new List<Task>();
foreach (var item in items)
{
// Ensure ID is set
if (string.IsNullOrEmpty(item.Id))
{
item.Id = !string.IsNullOrEmpty(item.HotelId) ? item.HotelId : Guid.NewGuid().ToString();
}
// Matches TypeScript behavior: Try Create, assume failure on conflict (409) means "already exists"
tasks.Add(container.CreateItemAsync(item, new PartitionKey(item.HotelId))
.ContinueWith(t =>
{
if (t.IsFaulted)
{
var cosmosEx = t.Exception?.InnerException as CosmosException;
if (cosmosEx?.StatusCode == HttpStatusCode.Conflict)
{
// Item already exists (409 Conflict), which is fine.
// We swallow this error to match TypeScript "try/catch -> continue" behavior
}
else
{
_logger.LogError($"Failed to insert item {item.HotelId}: {t.Exception?.InnerException?.Message}");
}
}
}));
}
await Task.WhenAll(tasks);
_logger.LogInformation($"Loaded {items.Count} items (skipping existing).");
return items.Count;
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to load data");
throw;
}
}
public async Task ShowAllIndexesAsync()
{
// Simple implementation to list databases and containers
// Not implemented fully for brevity but good to have signature match
try {
var iterator = _client.GetDatabaseQueryIterator<DatabaseProperties>();
while (iterator.HasMoreResults)
{
foreach (var db in await iterator.ReadNextAsync())
{
_logger.LogInformation($"Database: {db.Id}");
var containerIterator = _client.GetDatabase(db.Id).GetContainerQueryIterator<ContainerProperties>();
while (containerIterator.HasMoreResults)
{
foreach (var container in await containerIterator.ReadNextAsync())
{
_logger.LogInformation($"\tContainer: {container.Id}");
if (container.VectorEmbeddingPolicy != null)
{
foreach(var embed in container.VectorEmbeddingPolicy.Embeddings)
{
_logger.LogInformation($"\t\tVector Embedding: {embed.Path} ({embed.Dimensions}, {embed.DistanceFunction})");
}
}
if (container.IndexingPolicy.VectorIndexes != null)
{
foreach(var idx in container.IndexingPolicy.VectorIndexes)
{
_logger.LogInformation($"\t\tVector Index: {idx.Path} ({idx.Type})");
}
}
}
}
}
}
}
catch(Exception ex)
{
_logger.LogError(ex, "Error listing indexes");
}
}
}
En el código anterior, CosmosDBService realiza las siguientes tareas:
- Lee la configuración y compila un cliente sin contraseña con credenciales de Azure
- Proporciona referencias de base de datos o contenedor a petición
- Crea un índice de búsqueda vectorial solo si aún no existe.
- Enumera todas las bases de datos que no son del sistema, sus contenedores y los índices de cada contenedor
- Inserta datos de ejemplo si el contenedor está vacío y agrega índices auxiliares.
Visualización y administración de datos en Visual Studio Code
- Instale la extensión Azure Cosmos DB y C# en Visual Studio Code.
- Conéctese a la cuenta de Azure Cosmos DB mediante la extensión Azure Cosmos DB.
- Vea los datos e índices en la base de datos Hotels.
Limpieza de recursos
Cuando ya no necesite la API de la cuenta NoSQL, puede eliminar el grupo de recursos correspondiente.
Vaya al grupo de recursos que creó anteriormente en el portal de Azure.
Sugerencia
En esta guía de inicio rápido, se recomienda el nombre
msdocs-cosmos-quickstart-rg.Seleccione Eliminar grupo de recursos.
En el cuadro de diálogo ¿Está seguro de que desea eliminar ?, escriba el nombre del grupo de recursos y, a continuación, seleccione Eliminar.