Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
Observação
O suporte a vector foi introduzido no EF Core 10.0 e é suportado apenas com o SQL Server 2025 e versões superiores.
O tipo de dado vetorial SQL Server permite armazenar embeddings, que são representações de significado que podem ser pesquisadas de forma eficiente quanto à semelhança, alimentando cargas de trabalho de IA como a geração aumentada de pesquisa e recuperação semântica (RAG).
Configuração das propriedades vetoriais
Para usar o tipo de dado vector, basta adicionar uma propriedade .NET do tipo SqlVector<float> ao seu tipo de entidade, especificando as dimensões da seguinte forma:
public class Blog
{
// ...
[Column(TypeName = "vector(1536)")]
public SqlVector<float> Embedding { get; set; }
}
Depois que sua propriedade for adicionada e a coluna correspondente criada no banco de dados, você poderá começar a inserir incorporações. A geração de incorporação é feita fora do banco de dados, geralmente por meio de um serviço, e os detalhes para fazer isso estão fora do escopo desta documentação. No entanto, a biblioteca .NET Microsoft.Extensions.AI contém IEmbeddingGenerator, que é uma abstração sobre geradores de embedding que tem implementações para os principais fornecedores.
Depois de escolheres o teu gerador de embedding e o configurares, usa-o para gerar embeddings e insere-os da seguinte forma:
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();
Depois de ter os embeddings guardados na sua base de dados, está pronto para realizar uma pesquisa vetorial por similaridade sobre eles.
Observação
A partir do EF Core 11, as propriedades vetoriais não são carregadas por padrão ao consultar entidades, uma vez que os vetores são tipicamente grandes e raramente necessitam de ser lidos. Antes do EF Core 11, as propriedades vetoriais eram sempre carregadas como qualquer outra propriedade.
Pesquisa exata com VECTOR_DISTANCE()
A EF.Functions.VectorDistance() função calcula a distância exata entre dois vetores. Use-o para realizar uma pesquisa de similaridade para uma determinada consulta de utilizador:
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 função calcula a distância entre o vetor de consulta e cada linha da tabela, depois devolve as correspondências mais próximas. Embora isto forneça resultados perfeitamente precisos, pode ser lento para conjuntos de dados grandes porque o SQL Server tem de analisar todas as linhas e calcular distâncias para cada uma.
Observação
O suporte interno no EF 10 substitui a extensão EFCore.SqlServer.VectorSearch anterior, que permitia executar a pesquisa vetorial antes que o vector tipo de dados fosse introduzido. Como parte da atualização para o EF 10, remova a extensão dos seus projetos.
Pesquisa com VECTOR_SEARCH()
Advertência
Os índices VECTOR_SEARCH() e vetoriais são atualmente características experimentais em SQL Server e estão sujeitos a alterações. As APIs do EF Core para estas funcionalidades também estão sujeitas a alterações.
A função com valor de tabela VECTOR_SEARCH() do SQL Server obtém linhas com base na similaridade vetorial. Diferente VECTOR_DISTANCE() — que calcula a distância entre dois vetores específicos — VECTOR_SEARCH() procura numa tabela inteira os vetores mais semelhantes a um dado vetor de consulta.
Utilize o método de extensão VectorSearch() no seu DbSet e encadeie OrderBy(), Take() e WithApproximate() para realizar uma pesquisa aproximada do vizinho mais próximo (ANN) que utiliza um índice vetorial:
var results = await context.Blogs
.VectorSearch(b => b.Embedding, embedding, "cosine")
.OrderBy(r => r.Distance)
.Take(5)
.WithApproximate()
.ToListAsync();
foreach (var result in results)
{
Console.WriteLine($"Blog {result.Value.Id} with distance {result.Distance}");
}
Isso se traduz no seguinte SQL:
SELECT TOP(@__p_1) WITH APPROXIMATE [b].[Id], [b].[Name], [v].[Distance]
FROM VECTOR_SEARCH(
TABLE = [Blogs] AS [b],
COLUMN = [Embedding],
SIMILAR_TO = @__embedding_0,
METRIC = 'cosine'
) AS [v]
ORDER BY [v].[Distance]
VectorSearch() devolve VectorSearchResult<TEntity>, que permite aceder tanto à entidade como à distância calculada:
var searchResults = await context.Blogs
.VectorSearch(b => b.Embedding, embedding, "cosine")
.Where(r => r.Distance < 0.05)
.OrderBy(r => r.Distance)
.Select(r => new { Blog = r.Value, Distance = r.Distance })
.Take(3)
.WithApproximate()
.ToListAsync();
Isto permite-te filtrar pela pontuação de similaridade, apresentá-la aos utilizadores, etc.
WithApproximate()
WithApproximate() instrui SQL Server a usar o índice vetorial para pesquisa aproximada de vizinho mais próximo (ANN), o que proporciona um desempenho significativamente melhor para conjuntos de dados grandes. Faz com que WITH APPROXIMATE seja adicionada à cláusula SQL TOP.
WithApproximate() deve ser chamado após Take(), que especifica o número de resultados a devolver.
Sem WithApproximate(), a consulta realiza uma pesquisa exata dos k vizinhos mais próximos (kNN) que varre todas as linhas, sem usar o índice vetorial:
// Exact kNN search (no vector index used)
var blogs = await context.Blogs
.VectorSearch(b => b.Embedding, embedding, "cosine")
.OrderBy(r => r.Distance)
.Take(5)
.ToListAsync();
Índices vetoriais
Para usar pesquisa aproximada com WithApproximate(), deve criar um índice vetorial na sua coluna vetorial. Use o HasVectorIndex() método na configuração do seu modelo:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasVectorIndex(b => b.Embedding, "cosine");
}
Isto irá gerar a seguinte migração SQL:
CREATE VECTOR INDEX [IX_Blogs_Embedding]
ON [Blogs] ([Embedding])
WITH (METRIC = COSINE)
As seguintes métricas de distância são suportadas para índices vetoriais:
| Métrico | Descrição |
|---|---|
cosine |
Similaridade de cosseno (distância angular) |
euclidean |
Distância euclidiana (norma L2) |
dot |
Produto escalar (produto interno negativo) |
Escolha a métrica que melhor se adequa ao seu modelo de embedding e ao seu caso de uso. A similaridade do cosseno é frequentemente utilizada para embeddings de texto, enquanto a distância euclidiana é geralmente usada para embeddings de imagem.
Pesquisa híbrida
A pesquisa híbrida combina a pesquisa por similaridade vetorial com a pesquisa tradicional em texto completo para fornecer resultados mais relevantes. A pesquisa vetorial destaca-se por encontrar conteúdos semanticamente semelhantes, enquanto a pesquisa em texto completo é melhor na correspondência exata de palavras-chave. Ao combinar ambas as abordagens e usar a Fusão de Classificação Recíproca (RRF) para fundir os resultados, pode construir experiências de pesquisa mais inteligentes.
O exemplo seguinte mostra como implementar pesquisa híbrida usando EF Core, combinando FreeTextTable() e VectorSearch() numa única 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")
.OrderBy(r => r.Distance)
.Take(k)
.WithApproximate(),
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 uma pesquisa em texto completo em
Article - Realiza uma pesquisa vetorial em
Articlee combina os resultados com os resultados da pesquisa em texto completo através de um LEFT JOIN - Calcula a pontuação RRF combinando tanto o texto completo como a classificação semântica
- Ordena por pontuação RRF, seleciona o número desejado de resultados e extrai as entidades originais
Article.
Observação
Em vez de usar uma UNIÃO À ESQUERDA, uma UNIÃO EXTERIOR COMPLETA seria mais adequada para este cenário; Isto permitiria que resultados de alta classificação de qualquer um dos lados de pesquisa fossem incluídos no resultado final, mesmo que esse resultado não apareça de todo do outro lado. Com a abordagem LEFT JOIN acima, se um resultado tiver uma pontuação de similaridade vetorial muito alta, nunca é incluído no resultado final se esse resultado não tiver também uma pontuação alta no texto completo. No entanto, o EF atualmente não suporta FULL OUTER JOIN; vote a favor #37633 se gostaria de ver isso suportado.
A consulta produz o seguinte SQL:
SELECT TOP(@__p_4) [a0].[Id], [a0].[Content], [a0].[Title]
FROM FREETEXTTABLE([Articles], *, @__textualQuery_0, @__k_1) AS [f]
LEFT JOIN (
SELECT TOP(@__k_1) WITH APPROXIMATE [a].[Id], [a].[Content], [a].[Title], [v].[Distance]
FROM VECTOR_SEARCH(
TABLE = [Articles] AS [a],
COLUMN = [Embedding],
SIMILAR_TO = @__queryEmbedding_2,
METRIC = 'cosine'
) AS [v]
ORDER BY [v].[Distance]
) AS [t] ON [f].[KEY] = [t].[Id]
ORDER BY 1.0E0 / CAST(@__k_1 + [f].[RANK] AS float) + ISNULL(1.0E0 / (CAST(@__k_1 AS float) + [t].[Distance]), 0.0E0) DESC