Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Observação
O suporte ao vetor foi introduzido no EF Core 10.0 e só tem suporte com o SQL Server 2025 e superior.
O tipo de dados de vetor do SQL Server permite armazenar inserções, que são representações de significado que podem ser pesquisadas com eficiência quanto à similaridade, alimentando cargas de trabalho de IA, como RAG (pesquisa semântica e geração aumentada por recuperação).
Configurando propriedades de vetor
Para usar o vector tipo de dados, basta adicionar uma propriedade .NET do tipo SqlVector<float> ao tipo de entidade, especificando as dimensões da seguinte maneira:
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 inserções. A geração de inserçã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 Microsoft.Extensions.AI do .NET contém IEmbeddingGenerator, que é uma abstração sobre geradores de embeddings e possui implementações para os principais provedores.
Depois de escolher o gerador de inserção e configurá-lo, use-o para gerar inserções e inseri-las da seguinte maneira:
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 salvar as inserções no banco de dados, você estará pronto para executar a pesquisa de similaridade de vetor sobre eles.
Pesquisa exata com VECTOR_DISTANCE()
A EF.Functions.VectorDistance() função calcula a distância exata entre dois vetores. Use-o para executar a pesquisa de similaridade para uma determinada consulta de usuário:
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();
Essa função calcula a distância entre o vetor de consulta e todas as linhas da tabela e retorna as correspondências mais próximas. Embora isso forneça resultados perfeitamente precisos, pode ser lento para grandes conjuntos de dados, pois o SQL Server deve verificar todas as linhas e distâncias de computação para cada um deles.
Observação
O suporte interno no EF 10 substitui a extensão EFCore.SqlServer.VectorSearch anterior, que permitia a execução da pesquisa de vetor antes da introdução do vector tipo de dados. Como parte da atualização para o EF 10, remova a extensão de seus projetos.
Pesquisa aproximada com VECTOR_SEARCH()
Aviso
VECTOR_SEARCH() e índices de vetor são atualmente recursos experimentais no SQL Server e estão sujeitos a alterações. As APIs no EF Core para esses recursos também estão sujeitas a alterações.
Para grandes conjuntos de dados, a computação de distâncias exatas para cada linha pode ser proibitivamente lenta. O SQL Server 2025 apresenta suporte para pesquisa aproximada por meio de um índice de vetor, que fornece um desempenho muito melhor em detrimento do retorno de itens que são aproximadamente semelhantes - em vez de exatamente semelhantes - à consulta.
Índices de vetor
Para usar VECTOR_SEARCH(), você deve criar um índice de vetor em sua coluna de vetor. Use o HasVectorIndex() método na configuração do modelo:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasVectorIndex(b => b.Embedding, "cosine");
}
Isso gerará a seguinte migração de SQL:
CREATE VECTOR INDEX [IX_Blogs_Embedding]
ON [Blogs] ([Embedding])
WITH (METRIC = COSINE)
As seguintes métricas de distância têm suporte para índices de vetor:
| Métrica | Descrição |
|---|---|
cosine |
Similaridade cosseno (distância angular) |
euclidean |
Distância euclidiana (norma L2) |
dot |
Produto Dot (produto interno negativo) |
Escolha a métrica que melhor corresponde ao modelo de inserção e ao caso de uso. A similaridade cossina é comumente usada para inserções de texto, enquanto a distância euclidiana é frequentemente usada para inserções de imagem.
Pesquisando com VECTOR_SEARCH()
Depois de ter um índice de vetor, use o VectorSearch() método de extensão no seu 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}");
}
Isso se traduz no seguinte SQL:
SELECT [v].[Id], [v].[Embedding], [v].[Name]
FROM VECTOR_SEARCH([Blogs], 'Embedding', @__embedding, 'metric = cosine', @__topN)
O topN parâmetro especifica o número máximo de resultados a serem retornados.
VectorSearch() retorna VectorSearchResult<TEntity>, o que permite acessar a entidade e a distância computada:
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();
Isso permite filtrar a pontuação de similaridade, apresentá-la aos usuários etc.
Pesquisa híbrida
A pesquisa híbrida combina a pesquisa de similaridade de vetor com a pesquisa de texto completo tradicional para fornecer resultados mais relevantes. A pesquisa de vetor se destaca em encontrar conteúdo semanticamente semelhante, enquanto a pesquisa de texto completo é melhor na correspondência exata da palavra-chave. Combinando abordagens e usando o RRF (Reciprocal Rank Fusion) para mesclar os resultados, você pode criar experiências de pesquisa mais inteligentes.
O exemplo a seguir mostra como implementar a pesquisa híbrida usando o EF Core, combinando FreeTextTable() e VectorSearch() em uma ú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", 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:
- Executa uma pesquisa de texto completo em
Article - Executa uma pesquisa vetorial
Articlee combina os resultados com os da pesquisa de texto completo por meio de um LEFT JOIN - Calcula a pontuação RRF combinando o texto completo e a classificação semântica
- Ordena por pontuação RRF, obtém o número desejado de resultados e extrai as entidades originais
Article.
Observação
Em vez de usar um LEFT JOIN, um FULL OUTER JOIN seria mais adequado para esse cenário; isso permitiria que os resultados de alta relevância de ambos os lados da pesquisa fossem incluídos no resultado final, mesmo que esse resultado não apareça do outro lado. Com a abordagem LEFT JOIN acima, se um resultado tiver uma pontuação de similaridade de vetor muito alta, ele nunca será incluído no resultado final se esse resultado também não tiver uma pontuação de texto completo alta. No entanto, o EF atualmente não dá suporte a FULL OUTER JOIN; vote a favor #37633 se isso for algo que você gostaria de ver suportado.
A consulta produz o seguinte 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