Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Замечание
Поддержка векторов была введена в EF Core 10.0 и поддерживается только с SQL Server 2025 и более поздних версий.
Тип векторных данных SQL Server позволяет хранить векторные представления, которые используется для представления смысла и могут эффективно искаться по схожести, что позволяет использовать задачи искусственного интеллекта, такие как семантический поиск и создание на основе дополненного извлечения (RAG).
Настройка свойств вектора
Чтобы использовать тип данных vector, просто добавьте свойство .NET типа SqlVector<float> в тип сущности, указав измерения следующим образом:
public class Blog
{
// ...
[Column(TypeName = "vector(1536)")]
public SqlVector<float> Embedding { get; set; }
}
После добавления свойства и создания соответствующего столбца в базе данных, вы можете начать вставку встраиваний. Создание внедрения выполняется за пределами базы данных, как правило, через службу, и сведения об этом отсутствуют в этой документации. Однако библиотека .NET Microsoft.Extensions.AI содержит IEmbeddingGenerator, которая представляет собой абстракцию поверх генераторов встраиваний и имеет реализации для основных поставщиков.
Выбрав генератор встраивания и настроив его, используйте его для создания встраиваний и вставки этих встраиваний следующим образом:
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();
Как только векторные представления будут сохранены в вашу базу данных, вы сможете выполнить поиск по векторному сходству.
Замечание
Начиная с EF Core 11 свойства векторов по умолчанию не загружаются при запросе сущностей, так как векторы обычно большие и редко требуются для чтения обратно. До EF Core 11 свойства вектора всегда загружались, как и любое другое свойство.
Точный поиск с помощью VECTOR_DISTANCE()
Функция EF.Functions.VectorDistance() вычисляет точное расстояние между двумя векторами. Используйте его для выполнения поиска сходства для заданного запроса пользователя:
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();
Эта функция вычисляет расстояние между вектором запроса и каждой строкой в таблице, а затем возвращает ближайшие совпадения. Хотя это обеспечивает совершенно точные результаты, для больших наборов данных это может быть медленно, так как SQL Server должен сканировать все строки и вычислять расстояния для каждой из них.
Замечание
Встроенная поддержка в EF 10 заменяет предыдущее расширение EFCore.SqlServer.VectorSearch , которое позволило выполнять векторный поиск до vector появления типа данных. В рамках обновления до EF 10 удалите расширение из проектов.
Поиск с помощью VECTOR_SEARCH()
Предупреждение
VECTOR_SEARCH() и векторные индексы в настоящее время являются экспериментальными функциями в SQL Server и подлежат изменению. Api в EF Core для этих функций также могут быть изменены.
VECTOR_SEARCH() табличная функция SQL Server возвращает строки на основе сходства векторов. В отличие VECTOR_DISTANCE() от того, что вычисляет расстояние между двумя конкретными векторами, VECTOR_SEARCH() выполняет поиск всей таблицы для наиболее похожих векторов заданного вектора запроса.
Используйте метод расширения VectorSearch() в вашем DbSet и последовательно вызовите OrderBy(), Take() и WithApproximate(), чтобы выполнить поиск приближённых ближайших соседей (ANN) с использованием векторного индекса:
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}");
}
Это преобразуется в следующий 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() возвращает значение VectorSearchResult<TEntity>, позволяющее получить доступ как к сущности, так и к вычисляемому расстоянию:
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();
Это позволяет отфильтровать оценку сходства, представить ее пользователям и т. д.
WithApproximate()
WithApproximate() указывает SQL Server использовать векторный индекс для поиска приблизительного ближайшего соседа (ANN), что обеспечивает значительно более высокую производительность для больших наборов данных. Это приводит к добавлению WITH APPROXIMATE в предложение SQL TOP.
WithApproximate() должен вызываться после Take(), который указывает количество возвращаемых результатов.
Без WithApproximate() этого запрос выполняет точный поиск k ближайших соседей (kNN), при котором сканируются все строки без использования векторного индекса:
// 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();
Векторные индексы
Чтобы использовать приблизительный поиск с WithApproximate(), необходимо создать векторный индекс для столбца с векторами. Используйте метод HasVectorIndex() в конфигурации вашей модели.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.HasVectorIndex(b => b.Embedding, "cosine");
}
При этом будет создана следующая миграция SQL:
CREATE VECTOR INDEX [IX_Blogs_Embedding]
ON [Blogs] ([Embedding])
WITH (METRIC = COSINE)
Для индексов векторов поддерживаются следующие метрики расстояния:
| Единица измерения | Описание |
|---|---|
cosine |
Сходство косинуса (угловое расстояние) |
euclidean |
Евклидово расстояние (L2-норма) |
dot |
Dot product (отрицательный внутренний продукт) |
Выберите метрику, которая лучше всего соответствует модели внедрения и варианту использования. Косинусное сходство часто используется для текстовых векторов, в то время как эвклидово расстояние часто используется для векторов изображений.
Гибридный поиск
Гибридный поиск объединяет векторный поиск подобия с традиционным полнотекстовый поиск , чтобы обеспечить более релевантные результаты. Векторный поиск превосходит в нахождении семантически аналогичного содержимого, в то время как полнотекстовый поиск лучше подходит для точного совпадения с ключевыми словами. Сочетая оба подхода и используя слияние с взаимным ранжированием (RRF) для объединения результатов, вы можете создавать более интеллектуальные поисковые системы.
В следующем примере показано, как реализовать гибридный поиск с помощью EF Core, сочетая FreeTextTable() и VectorSearch() в одном запросе:
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();
Этот запрос:
- Выполняет полнотекстовый поиск
Article - Выполняет векторный поиск по
Articleи объединяет полученные результаты с результатами полнотекстового поиска с помощью FULL JOIN - Вычисляет оценку RRF путем объединения полнотекстового и семантического ранжирования
- Упорядочение по оценке RRF выбирает требуемое количество результатов и извлекает из оригинальных сущностей
Article.
Запрос создает следующий 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