SQL Server EF Core Sağlayıcısı'nda vektör araması

Uyarı

Vektör desteği EF Core 10.0'da sunulmuştur ve yalnızca SQL Server 2025 ve üzeri sürümlerde desteklenir.

SQL Server vektör veri türü, embeddings depolamaya olanak tanır. Bu, benzerlik açısından verimli bir şekilde aranabilecek anlam gösterimleridir ve anlamsal arama ve alma artırılmış oluşturma (RAG) gibi yapay zeka iş yüklerini güçlendirir.

Vektör özelliklerini ayarlama

vector veri türünü kullanmak için varlık türüne SqlVector<float> türünde bir .NET özelliği eklemeniz ve boyutları aşağıdaki gibi belirtmeniz yeterlidir:

public class Blog
{
    // ...

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

Özelliğiniz eklendikten ve veritabanında ilgili sütun oluşturulduktan sonra eklemeleri eklemeye başlayabilirsiniz. Ekleme oluşturma işlemi genellikle bir hizmet aracılığıyla veritabanının dışında yapılır ve bunu yapmanın ayrıntıları bu belgenin kapsamı dışındadır. Ancak, .NET Microsoft.Extensions.AI kitaplığı, ana sağlayıcılar için uygulamaları olan gömme oluşturuculara yönelik bir soyutlama olan IEmbeddingGenerator içerir.

Ekleme oluşturucunuzu seçtikten ve ayarladıktan sonra, ekleme oluşturmak ve bunları aşağıdaki gibi eklemek için kullanın:

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

Veritabanınıza kaydedilen eklemeleri yaptıktan sonra, bunlar üzerinde vektör benzerliği araması yapmaya hazır olursunuz.

Uyarı

EF Core 11'den başlayarak, vektör özellikleri varlıklar sorgulanırken varsayılan olarak yüklenmez, çünkü vektörler genellikle büyük olur ve nadiren geri okunması gerekir. EF Core 11'in öncesinde, vektör özellikleri her zaman diğer özellikler gibi yüklenirdi.

VECTOR_DISTANCE() ile tam arama

İşlev, EF.Functions.VectorDistance() iki vektör arasındaki tam uzaklığı hesaplar. Belirli bir kullanıcı sorgusu için benzerlik araması yapmak için kullanın:

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

Bu işlev, sorgu vektör ve tablodaki her satır arasındaki uzaklığı hesaplar ve en yakın eşleşmeleri döndürür. Bu, son derece doğru sonuçlar sağlasa da büyük veri kümeleri için yavaş olabilir çünkü SQL Server her biri için tüm satırları ve işlem uzaklıklarını taraması gerekir.

Uyarı

EF 10'daki yerleşik destek, önceki EFCore.SqlServer.VectorSearch uzantısının yerini alır ve veri türü kullanılmadan önce vektör araması yapılmasına vector izin verilir. EF 10'a yükseltme işleminin bir parçası olarak uzantıyı projelerinizden kaldırın.

Uyarı

VECTOR_SEARCH() ve vektör dizinleri şu anda SQL Server deneysel özelliklerdir ve değiştirilebilir. Bu özellikler için EF Core'daki API'ler de değiştirilebilir.

SQL Server'ın VECTOR_SEARCH() tablo değerli işlevi, vektör benzerliğine göre satırları döndürür. İki belirli vektör arasındaki uzaklığı hesaplayan aksine VECTOR_DISTANCE() , VECTOR_SEARCH() belirli bir sorgu vektöre en benzer vektörler için tablonun tamamında arama yapılır.

VectorSearch() kullanan yaklaşık en yakın komşu (ANN) araması gerçekleştirmek için DbSet üzerinde OrderBy() uzantı yöntemini kullanın ve Take(), WithApproximate() ile öğelerini zincirleyin:

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}");
}

Bu, aşağıdaki SQL'e çevrilir:

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(), VectorSearchResult<TEntity>'i döner ve bu da hem varlığa hem de hesaplanan mesafeye erişmenizi sağlar.

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

Bu, benzerlik puanını filtrelemenize, kullanıcılara sunmanıza vb. olanak tanır.

WithApproximate()

WithApproximate(), SQL Server büyük veri kümeleri için önemli ölçüde daha iyi performans sağlayan en yakın komşu (ANN) araması için vektör dizinini kullanma talimatı verir. WITH APPROXIMATE öğesinin SQL TOP yan tümcesine eklenmesine neden olur. WithApproximate(), döndürülecek sonuç sayısını belirten Take()'den sonra çağrılmalıdır.

WithApproximate() olmadan sorgu, vektör dizinini kullanmadan tüm satırları tarayan tam bir k-en yakın komşu (kNN) araması gerçekleştirir:

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

Vektör dizinleri

ile WithApproximate()yaklaşık arama kullanmak için vektör sütununuzda bir vektör dizini oluşturmanız gerekir. HasVectorIndex() Model yapılandırmanızda yöntemini kullanın:

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

Bu, aşağıdaki SQL geçişini oluşturur:

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

Vektör dizinleri için aşağıdaki uzaklık ölçümleri desteklenir:

Ölçü birimi Açıklama
cosine Kosinüs benzerliği (açısal uzaklık)
euclidean Öklid uzaklığı (L2 norm)
dot Noktalı ürün (negatif iç ürün)

Ekleme modelinize ve kullanım örneğinize en uygun ölçümü seçin. Kosinüs benzerliği genellikle metin ekleme işlemleri için kullanılırken, öklid uzaklığı genellikle görüntü ekleme işlemleri için kullanılır.

Karma arama , daha ilgili sonuçlar elde etmek için vektör benzerliği aramasını geleneksel tam metin aramasıyla birleştirir. Vektör araması, benzer içeriği bulma konusunda başarılı olurken, tam metin araması tam anahtar sözcük eşleştirmede daha iyidir. Her iki yaklaşımı da birleştirerek ve sonuçları birleştirmek için Karşılıklı Rank Fusion (RRF) kullanarak daha akıllı arama deneyimleri oluşturabilirsiniz.

Aşağıdaki örnek, EF Core kullanarak karma aramayı FreeTextTable() ve VectorSearch() öğelerini tek bir sorguda nasıl birleştireceğinizi göstermektedir.

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

Bu sorgu:

  1. Article üzerinde tam metin araması yapar
  2. Article üzerinde bir vektör araması gerçekleştirir ve elde edilen sonuçları FULL JOIN aracılığıyla tam metin arama sonuçlarıyla birleştirir
  3. Hem tam metin hem de anlamsal derecelendirmeyi birleştirerek RRF puanını hesaplar
  4. RRF puanına göre sıralar, istenen sayıda sonucu alır ve özgün Article varlıkları dışarıda projelendirir.

Sorgu aşağıdaki SQL'i oluşturur:

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