Sdílet prostřednictvím


Vektorové vyhledávání ve zprostředkovateli SQL Server EF Core

Poznámka:

Podpora vektorů byla zavedena v EF Core 10.0 a je podporována pouze s SQL Serverem 2025 a novějším.

Datový typ vektoru SQL Serveru umožňuje ukládání vložených hodnot, což jsou reprezentace významu, které lze efektivně prohledávat z hlediska podobnosti, což podporuje úlohy AI, jako je sémantické vyhledávání a načítání rozšířené generace (RAG).

Nastavení vlastností vektoru

Pokud chcete datový typ použít vector , jednoduše přidejte do typu entity vlastnost SqlVector<float> .NET, která určuje dimenze následujícím způsobem:

public class Blog
{
    // ...

    [Column(TypeName = "vector(1536)")]
    public SqlVector<float> Embedding { get; set; }
}

Po přidání vlastnosti a vytvoření odpovídajícího sloupce v databázi můžete začít vkládat embeddingy. Generování vložení se provádí mimo databázi, obvykle prostřednictvím služby. Podrobnosti k tomu nejsou v rozsahu této dokumentace. Knihovna .NET Microsoft.Extensions.AI však obsahuje IEmbeddingGenerator, což je abstrakce nad generátory vkládání, které mají implementace pro hlavní poskytovatele.

Jakmile zvolíte generátor vkládání a nastavíte ho, použijte ho k vygenerování vkládání a jejich vložení následujícím způsobem:

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();

Jakmile máte zachycení uložená do databáze, jste připraveni provádět vyhledávání podobností mezi vektory.

Přesné hledání pomocí VECTOR_DISTANCE()

Funkce EF.Functions.VectorDistance() vypočítá přesnou vzdálenost mezi dvěma vektory. Použijte ho k vyhledání podobnosti pro daný uživatelský dotaz:

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();

Tato funkce vypočítá vzdálenost mezi vektorem dotazu a každým řádkem v tabulce a vrátí nejbližší shody. I když to poskytuje dokonale přesné výsledky, může být pomalé u velkých datových sad, protože SQL Server musí prohledat všechny řádky a výpočetní vzdálenosti pro každou z nich.

Poznámka:

Integrovaná podpora v EF 10 nahrazuje předchozí rozšíření EFCore.SqlServer.VectorSearch , které umožňovalo provádět vektorové vyhledávání před zavedením datového vector typu. V rámci upgradu na EF 10 odeberte rozšíření z projektů.

Výstraha

VECTOR_SEARCH() a vektorové indexy jsou v současné době experimentálními funkcemi SQL Serveru a můžou se změnit. Rozhraní API v EF Core pro tyto funkce se mohou také změnit.

U velkých datových sad může být výpočet přesných vzdáleností pro každý řádek extrémně pomalý. SQL Server 2025 zavádí podporu přibližného vyhledávání prostřednictvím vektorového indexu, který poskytuje mnohem lepší výkon na úkor vrácení položek, které jsou přibližně podobné – a ne přesně podobné – dotazu.

Vektorové indexy

Chcete-li použít VECTOR_SEARCH(), musíte vytvořit vektorový index ve sloupci vektoru. Použijte metodu HasVectorIndex() v konfiguraci modelu:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .HasVectorIndex(b => b.Embedding, "cosine");
}

Tím se vygeneruje následující migrace SQL:

CREATE VECTOR INDEX [IX_Blogs_Embedding]
    ON [Blogs] ([Embedding])
    WITH (METRIC = COSINE)

Pro indexy vektorů se podporují následující metriky vzdálenosti:

Ukazatel Description
cosine Kosinus podobnost (úhlová vzdálenost)
euclidean Euklidovská vzdálenost (L2 norma)
dot Tečkovaný součin (negativní vnitřní výrobek)

Zvolte metriku, která nejlépe odpovídá vašemu modelu vkládání a případu použití. Kosinus podobnost se běžně používá pro vkládání textu, zatímco euklidová vzdálenost se často používá pro vkládání obrázků.

Jakmile budete mít vektorový index, použijte metodu rozšíření VectorSearch() na 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}");
}

To se přeloží na následující SQL:

SELECT [v].[Id], [v].[Embedding], [v].[Name]
FROM VECTOR_SEARCH([Blogs], 'Embedding', @__embedding, 'metric = cosine', @__topN)

Parametr topN určuje maximální počet výsledků, které se mají vrátit.

VectorSearch() vrátí VectorSearchResult<TEntity>, což vám umožní přístup jak k entitě, tak k vypočítané vzdálenosti:

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();

Díky tomu můžete filtrovat skóre podobnosti, prezentovat ho uživatelům atd.

Hybridní vyhledávání kombinuje hledání vektorové podobnosti s tradičním fulltextovým vyhledáváním , aby poskytovalo relevantnější výsledky. Vektorové vyhledávání exceluje při hledání sémanticky podobného obsahu, zatímco fulltextové vyhledávání je lepší při přesné shodě klíčových slov. Kombinací obou přístupů a použití reciproční Rank Fusion (RRF) ke sloučení výsledků můžete vytvořit inteligentnější vyhledávací prostředí.

Následující příklad ukazuje, jak implementovat hybridní vyhledávání pomocí EF Core, kombinování FreeTextTable() a VectorSearch() v jednom dotazu:

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();

Tento dotaz:

  1. , Provede fulltextové vyhledávání na Article
  2. Provede vektorové vyhledávání na Article a zkombinuje výsledky s fulltextovými výsledky pomocí LEVÉHO PŘIPOJENÍ (LEFT JOIN).
  3. Vypočítá skóre RRF zkombinováním celého textu i sémantického pořadí.
  4. Řazení podle skóre RRF vezme požadovaný počet výsledků a vyloučí původní Article entity.

Poznámka:

Místo použití LEFT JOIN by pro tento scénář byl vhodnější FULL OUTER JOIN; umožní to zahrnout výsledky s vysokým hodnocením z obou stran vyhledávání do konečného výsledku, i když se tento výsledek vůbec nezobrazuje na druhé straně. Pokud má výsledek velmi vysoké skóre podobnosti vektorů, výše uvedený přístup LEFT JOIN se nikdy nezahrne do konečného výsledku, pokud tento výsledek nemá také vysoké fulltextové skóre. EF však v současné době nepodporuje FULL OUTER JOIN; upvote #37633, pokud chcete, aby to bylo podporováno.

Dotaz vytvoří následující 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