Kommentar
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Anmärkning
Vektorstöd introducerades i EF Core 10.0 och stöds endast med SQL Server 2025 och senare.
Datatypen SQL Server vektor gör det möjligt att lagra embeddings, vilket är representationer av innebörden som effektivt kan sökas efter likheter, vilket driver AI-arbetsbelastningar som semantisk sökning och hämtningsförhöjd generation (RAG).
Konfigurera vektoregenskaper
Om du vill använda datatypen vector lägger du helt enkelt till en .NET-egenskap av typen SqlVector<float> till din entitetstyp och anger dimensionerna enligt följande:
public class Blog
{
// ...
[Column(TypeName = "vector(1536)")]
public SqlVector<float> Embedding { get; set; }
}
När egenskapen har lagts till och motsvarande kolumn har skapats i databasen kan du börja infoga inbäddningar. Inbäddningsgenereringen görs utanför databasen, vanligtvis via en tjänst, och informationen för att göra detta ligger utanför omfånget för den här dokumentationen. Men biblioteket .NET Microsoft.Extensions.AI innehåller IEmbeddingGenerator, vilket är en abstraktion över inbäddningsgeneratorer som har implementeringar för de större leverantörerna.
När du har valt inbäddningsgeneratorn och konfigurerat den använder du den för att generera inbäddningar och infoga dem på följande sätt:
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();
När du har sparat inbäddningar i databasen är du redo att utföra vektorlikhetssökning över dem.
Anmärkning
Från och med EF Core 11 läses inte vektoregenskaper in som standard vid frågor mot entiteter, eftersom vektorer vanligtvis är stora och sällan behöver läsas tillbaka. Före EF Core 11 lästes vektoregenskaper alltid in som andra egenskaper.
Exakt sökning med VECTOR_DISTANCE()
Funktionen EF.Functions.VectorDistance() beräknar det exakta avståndet mellan två vektorer. Använd den för att utföra likhetssökning för en viss användarfråga:
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();
Den här funktionen beräknar avståndet mellan frågevektorn och varje rad i tabellen och returnerar sedan de närmaste matchningarna. Även om detta ger helt korrekta resultat kan det vara långsamt för stora datauppsättningar eftersom SQL Server måste söka igenom alla rader och beräkningsavstånd för var och en.
Anmärkning
Det inbyggda stödet i EF 10 ersätter det tidigare EFCore.SqlServer.VectorSearch-tillägget , som gjorde det möjligt att utföra vektorsökning innan vector datatypen introducerades. Som en del av uppgraderingen till EF 10 tar du bort tillägget från dina projekt.
Söker med VECTOR_SEARCH()
Varning
VECTOR_SEARCH() och vektorindex är för närvarande experimentella funktioner i SQL Server och kan komma att ändras. API:erna i EF Core för dessa funktioner kan också ändras.
SQL Server VECTOR_SEARCH() tabellvärdesfunktion hämtar rader baserat på vektorlikhet. Till skillnad från VECTOR_DISTANCE() – som beräknar avståndet mellan två specifika vektorer – VECTOR_SEARCH() söker en hel tabell efter de mest liknande vektorerna till en viss frågevektor.
Använd tilläggsmetoden VectorSearch() för DbSet, och kedja OrderBy(), Take() och WithApproximate() för att utföra en ungefärlig sökning efter närmaste granne (ANN) med hjälp av ett vektorindex:
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}");
}
Detta översätts till följande 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() returnerar VectorSearchResult<TEntity>, vilket gör att du kan komma åt både entiteten och det beräknade avståndet:
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();
På så sätt kan du filtrera på likhetspoängen, presentera den för användare osv.
WithApproximate()
WithApproximate() instruerar SQL Server att använda vektorindexet för ungefärlig sökning efter närmaste granne (ANN), vilket ger betydligt bättre prestanda för stora datamängder. Det gör att WITH APPROXIMATE läggs till i SQL-satsen TOP.
WithApproximate() måste anropas efter Take(), vilket anger hur många resultat som ska returneras.
Utan WithApproximate()utför frågan en exakt k-närmaste granne-sökning (kNN) som söker igenom alla rader, utan att använda vektorindexet:
// 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();
Vektorindex
Om du vill använda ungefärlig sökning med WithApproximate()måste du skapa ett vektorindex i vektorkolumnen.
HasVectorIndex() Använd metoden i modellkonfigurationen:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasVectorIndex(b => b.Embedding, "cosine");
}
Detta genererar följande SQL-migrering:
CREATE VECTOR INDEX [IX_Blogs_Embedding]
ON [Blogs] ([Embedding])
WITH (METRIC = COSINE)
Följande avståndsmått stöds för vektorindex:
| Mätvärde | Beskrivning |
|---|---|
cosine |
Cosinisk likhet (vinkelavstånd) |
euclidean |
Euklidiska avstånd (L2-norm) |
dot |
Skalärprodukt (negativ inre produkt) |
Välj det mått som bäst matchar din inbäddningsmodell och användningsfall. Cosinuslikhet används ofta för textinbäddningar, medan euklidiska avstånd ofta används för bildinbäddningar.
Hybridsökning
Hybridsökning kombinerar vektorlikhetssökning med traditionell fulltextsökning för att ge mer relevanta resultat. Vektorsökning utmärker sig för att hitta semantiskt liknande innehåll, medan fulltextsökning är bättre på exakt nyckelordsmatchning. Genom att kombinera båda metoderna och använda Reciprocal Rank Fusion (RRF) för att sammanfoga resultaten kan du skapa mer intelligenta sökupplevelser.
I följande exempel visas hur du implementerar hybridsökning med HJÄLP av EF Core, kombinerar FreeTextTable() och VectorSearch() i en enda fråga:
var k = 20;
string textualQuery = ...;
SqlVector<float> queryEmbedding = ...;
var results = await context.Articles
// Perform full-text search
.FreeTextTable<Article, int>(textualQuery, topN: k)
.Join(
context.Articles,
fts => fts.Key,
a => a.Id,
(fts, a) => new { Article = a, fts.Rank })
// Perform vector (semantic) search, joining the results of both searches together
.FullJoin(
context.Articles.VectorSearch(b => b.Embedding, queryEmbedding, "cosine")
.OrderBy(r => r.Distance)
.Take(k)
.WithApproximate(),
fts => fts.Article.Id,
vs => vs.Value.Id,
(fts, vs) => new
{
Article = fts != null ? fts.Article : vs.Value,
FullTextRank = fts == null ? null : (int?)fts.Rank,
VectorDistance = vs == null ? null : (double?)vs.Distance
})
// Apply Reciprocal Rank Fusion (RRF) to combine the results
.Select(x => new
{
x.Article,
RrfScore = (x.FullTextRank == null ? 0.0 : 1.0 / (k + x.FullTextRank.Value))
+ (x.VectorDistance == null ? 0.0 : 1.0 / (k + x.VectorDistance.Value))
})
.OrderByDescending(x => x.RrfScore)
.Take(10)
.Select(x => x.Article)
.ToListAsync();
Den här frågan:
- Utför en fulltextsökning på
Article - Utför en vektorsökning på
Articleoch kombinerar resultatet med sökresultatet i fulltext via en FULLSTÄNDIG KOPPLING - Beräknar RRF-poängen genom att kombinera både den fullständiga texten och den semantiska rangordningen
- Beställningar sorteras efter RRF-poäng, antal önskade resultat hämtas och originalentiteterna projiceras.
Frågan genererar följande SQL:
SELECT TOP(@__p_4) COALESCE([a].[Id], [t].[Id]) AS [Id], COALESCE([a].[Content], [t].[Content]) AS [Content], COALESCE([a].[Title], [t].[Title]) AS [Title]
FROM FREETEXTTABLE([Articles], *, @__textualQuery_0, @__k_1) AS [f]
INNER JOIN [Articles] AS [a] ON [f].[KEY] = [a].[Id]
FULL 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 [a].[Id] = [t].[Id]
ORDER BY ISNULL(1.0E0 / CAST(@__k_1 + [f].[RANK] AS float), 0.0E0) + ISNULL(1.0E0 / (CAST(@__k_1 AS float) + [t].[Distance]), 0.0E0) DESC