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.

Büyük veri kümeleri için, her satır için tam uzaklıkları hesaplama işlemi çok yavaş olabilir. SQL Server 2025,approximatevector dizini aracılığıyla arama desteği sunar. Bu, sorguya tam olarak benzer değil, yaklaşık olarak benzer öğeleri döndürme pahasına çok daha iyi performans sağlar.

Vektör dizinleri

Kullanmak için VECTOR_SEARCH(), 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.

Vektör dizininiz olduktan sonra, VectorSearch() uzantı yöntemini kullanın DbSet:

var blogs = await context.Blogs
    .VectorSearch(b => b.Embedding, embedding, "cosine", topN: 5)
    .ToListAsync();

foreach (var (blog, score) in blogs)
{
    Console.WriteLine($"Blog {blog.Id} with score {score}");
}

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

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

topN parametresi, döndürülecek en fazla sonuç sayısını belirtir.

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", topN: 5)
    .Where(r => r.Distance < 0.05)
    .Select(r => new { Blog = r.Value, Distance = r.Distance })
    .ToListAsync();

Bu, benzerlik puanını filtrelemenize, kullanıcılara sunmanıza vb. olanak tanı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)
    // 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();

Bu sorgu:

  1. Article üzerinde tam metin araması yapar
  2. Üzerinde Article vektör araması yapar ve LEFT JOIN aracılığıyla sonuçları 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.

Uyarı

LEFT JOIN kullanmak yerine, SOL JOIN bu senaryo için daha uygun olacaktır; bu, diğer tarafta hiç görünmese bile, her iki arama tarafındaki yüksek derecelendirmeli sonuçların nihai sonuca dahil edilmesine izin verir. Yukarıdaki LEFT JOIN yaklaşımıyla, bir sonuç çok yüksek vektör benzerlik puanına sahipse, sonuç aynı zamanda yüksek bir tam metin puanına sahip değilse, nihai sonuda asla dahil edilmez. Ancak, EF şu anda FULL OUTER JOIN'i desteklemiyor; eğer bu desteği görmek istiyorsanız #37633 için oy kullanabilirsiniz.

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

SELECT TOP(@p3) [a0].[Id], [a0].[Content], [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