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.
Nota:
La compatibilidad con vectores se introdujo en EF Core 10.0 y solo se admite con SQL Server 2025 y versiones posteriores.
El tipo de datos vectorial de SQL Server permite almacenar incrustaciones, que son representaciones de significado que se pueden buscar de forma eficaz en busca de similitud, potenciando las cargas de trabajo de IA, como la búsqueda semántica y la generación aumentada de recuperación (RAG).
Configuración de propiedades vectoriales
Para usar el tipo de datos vector, basta con agregar una propiedad .NET de tipo SqlVector<float> a su tipo de entidad, especificando las dimensiones como se indica a continuación:
public class Blog
{
// ...
[Column(TypeName = "vector(1536)")]
public SqlVector<float> Embedding { get; set; }
}
Una vez agregada la propiedad y la columna correspondiente creada en la base de datos, puede empezar a insertar incrustaciones. La generación de inserción se realiza fuera de la base de datos, normalmente a través de un servicio, y los detalles para hacerlo están fuera del ámbito de esta documentación. Sin embargo, la biblioteca Microsoft.Extensions.AI de .NET contiene IEmbeddingGenerator, que es una abstracción sobre los generadores de 'embedding' que tiene implementaciones para los principales proveedores.
Una vez que haya elegido el generador de inserción y lo haya configurado, úselo para generar inserciones e insertarlas de la siguiente manera:
IEmbeddingGenerator<string, Embedding<float>> embeddingGenerator = /* Set up your preferred embedding generator */;
var embedding = await embeddingGenerator.GenerateVectorAsync("Some text to be vectorized");
context.Blogs.Add(new Blog
{
Name = "Some blog",
Embedding = new SqlVector<float>(embedding)
});
await context.SaveChangesAsync();
Una vez que tenga las incrustaciones guardadas en la base de datos, estará listo para realizar una búsqueda de similitud vectorial con ellas.
Búsqueda exacta con VECTOR_DISTANCE()
La EF.Functions.VectorDistance() función calcula la distancia exacta entre dos vectores. Úselo para realizar una búsqueda de similitud para una consulta de usuario determinada:
var sqlVector = new SqlVector<float>(await embeddingGenerator.GenerateVectorAsync("Some user query to be vectorized"));
var topSimilarBlogs = await context.Blogs
.OrderBy(b => EF.Functions.VectorDistance("cosine", b.Embedding, sqlVector))
.Take(3)
.ToListAsync();
Esta función calcula la distancia entre el vector de consulta y cada fila de la tabla y, a continuación, devuelve las coincidencias más cercanas. Aunque esto proporciona resultados perfectamente precisos, puede ser lento para grandes conjuntos de datos, ya que SQL Server debe examinar todas las filas y calcular las distancias para cada una.
Nota:
La compatibilidad integrada en EF 10 reemplaza a la extensión EFCore.SqlServer.VectorSearch anterior, que permitía realizar la búsqueda de vectores antes de que se introdujera el vector tipo de datos. Como parte de la actualización a EF 10, elimine la extensión de sus proyectos.
Búsqueda aproximada con VECTOR_SEARCH()
Advertencia
VECTOR_SEARCH() Los índices vectoriales son características experimentales actualmente en SQL Server y están sujetas a cambios. Las API de EF Core para estas características también están sujetas a cambios.
En el caso de grandes conjuntos de datos, calcular distancias exactas para cada fila puede ser prohibitivamente lenta. SQL Server 2025 presenta compatibilidad con la búsqueda aproximada a través de un índice vectorial, lo que proporciona un rendimiento mucho mejor a costa de devolver elementos que son aproximadamente similares, en lugar de ser exactamente similares, a la consulta.
Índices vectoriales
Para usar VECTOR_SEARCH(), debe crear un índice vectorial en la columna vectorial. Utilice el método HasVectorIndex() en la configuración del modelo.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasVectorIndex(b => b.Embedding, "cosine");
}
Esto generará la siguiente migración de SQL:
CREATE VECTOR INDEX [IX_Blogs_Embedding]
ON [Blogs] ([Embedding])
WITH (METRIC = COSINE)
Se admiten las siguientes métricas de distancia para los índices vectoriales:
| Métrica | Descripción |
|---|---|
cosine |
Similitud de coseno (distancia angular) |
euclidean |
Distancia euclidiana (norma L2) |
dot |
Producto de punto (producto interno negativo) |
Elija la métrica que mejor coincida con el modelo de inserción y el caso de uso. La similitud de coseno se usa normalmente para incrustaciones de texto, mientras que la distancia euclidiana se usa a menudo para las incrustaciones de imágenes.
Buscar con VECTOR_SEARCH()
Una vez que tenga un índice vectorial, use el método de extensión VectorSearch() sobre DbSet.
var blogs = await context.Blogs
.VectorSearch(b => b.Embedding, "cosine", embedding, topN: 5)
.ToListAsync();
foreach (var (blog, score) in blogs)
{
Console.WriteLine($"Blog {blog.Id} with score {score}");
}
Esto se traduce en el siguiente código SQL:
SELECT [v].[Id], [v].[Embedding], [v].[Name]
FROM VECTOR_SEARCH([Blogs], 'Embedding', @__embedding, 'metric = cosine', @__topN)
El topN parámetro especifica el número máximo de resultados que se van a devolver.
VectorSearch() devuelve VectorSearchResult<TEntity>, que permite tener acceso a la entidad y a la distancia calculada:
var searchResults = await context.Blogs
.VectorSearch(b => b.Embedding, "cosine", embedding, topN: 5)
.Where(r => r.Distance < 0.05)
.Select(r => new { Blog = r.Value, Distance = r.Distance })
.ToListAsync();
Esto le permite filtrar por la puntuación de similitud, presentarla a los usuarios, etc.
Búsqueda híbrida
La búsqueda híbrida combina la búsqueda de similitud vectorial con la búsqueda de texto completo tradicional para ofrecer resultados más relevantes. La búsqueda de vectores se destaca al buscar contenido semánticamente similar, mientras que la búsqueda de texto completo es mejor en coincidencia exacta de palabras clave. Al combinar ambos enfoques y usar La fusión de clasificación recíproca (RRF) para combinar los resultados, puede crear experiencias de búsqueda más inteligentes.
En el ejemplo siguiente se muestra cómo implementar la búsqueda híbrida mediante EF Core, combinando FreeTextTable() y VectorSearch() en una sola consulta:
var k = 20;
string textualQuery = ...;
SqlVector<float> queryEmbedding = ...;
var results = await context.Articles
// Perform full-text search
.FreeTextTable<Article, int>(textualQuery, topN: k)
// Perform vector (semantic) search, joining the results of both searches together
.LeftJoin(
context.Articles.VectorSearch(b => b.Embedding, queryEmbedding, "cosine", topN: k),
fts => fts.Key,
vs => vs.Value.Id,
(fts, vs) => new
{
Article = vs.Value,
FullTextRank = fts.Rank,
VectorDistance = (double?)vs.Distance
})
// Apply Reciprocal Rank Fusion (RRF) to combine the results
.Select(x => new
{
x.Article,
RrfScore = (1.0 / (k + x.FullTextRank)) + (1.0 / (k + x.VectorDistance) ?? 0.0)
})
.OrderByDescending(x => x.RrfScore)
.Take(10)
.Select(x => x.Article)
.ToListAsync();
Esta consulta:
- Realiza una búsqueda de texto completo en
Article - Realiza una búsqueda vectorial en
Articley combina los resultados con los resultados de búsqueda de texto completo a través de LEFT JOIN. - Calcula la puntuación de RRF combinando el texto completo y la clasificación semántica.
- Ordena por puntuación de RRF, obtiene el número deseado de resultados y muestra las entidades originales
Article.
Nota:
En lugar de usar LEFT JOIN, un FULL OUTER JOIN sería más adecuado para este escenario; esto permitiría que los resultados altamente clasificados de cualquiera de los lados de la búsqueda se incluyan en el resultado final, incluso si ese resultado no aparece en absoluto en el otro lado. Con el enfoque LEFT JOIN anterior, si un resultado tiene una puntuación de similitud vectorial muy alta, nunca se incluye en el resultado final si ese resultado tampoco tiene una puntuación de texto completo alta. Sin embargo, EF no admite actualmente FULL OUTER JOIN; vote a favor de #37633 si es algo que le gustaría ver admitido.
La consulta genera el siguiente código SQL:
SELECT TOP(@p3) [a0].[Id], [a0].[Content], [a0].[Embedding], [a0].[Title]
FROM FREETEXTTABLE([Articles], *, @p, @p1) AS [f]
LEFT JOIN VECTOR_SEARCH(
TABLE = [Articles] AS [a0],
COLUMN = [Embedding],
SIMILAR_TO = @p2,
METRIC = 'cosine',
TOP_N = @p3
) AS [v] ON [f].[KEY] = [a0].[Id]
ORDER BY 1.0E0 / CAST(10 + [f].[RANK] AS float) + ISNULL(1.0E0 / (10.0E0 + [v].[Distance]), 0.0E0) DESC