Ескертпе
Бұл бетке кіру үшін қатынас шегін айқындау қажет. Жүйеге кіруді немесе каталогтарды өзгертуді байқап көруге болады.
Бұл бетке кіру үшін қатынас шегін айқындау қажет. Каталогтарды өзгертуді байқап көруге болады.
Замечание
Поддержка векторов была введена в 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 Майкрософт.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 для этих функций также могут быть изменены.
Для больших наборов данных вычисление точных расстояний для каждой записи может быть чрезмерно медленным. SQL Server 2025 представляет поддержку приблизительного поиска с использованием векторного индекса, что обеспечивает гораздо более высокую производительность за счет возврата элементов, которые примерно похожи, а не точно соответствуют запросу.
Векторные индексы
Чтобы использовать VECTOR_SEARCH(), необходимо создать векторный индекс в столбце векторов. Используйте метод 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 (отрицательный внутренний продукт) |
Выберите метрику, которая лучше всего соответствует модели внедрения и варианту использования. Косинусное сходство часто используется для текстовых векторов, в то время как эвклидово расстояние часто используется для векторов изображений.
Поиск с помощью VECTOR_SEARCH()
После получения векторного VectorSearch() индекса используйте метод расширения для вашего 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}");
}
Это преобразуется в следующий SQL:
SELECT [v].[Id], [v].[Name], [v].[Distance]
FROM VECTOR_SEARCH([Blogs], 'Embedding', @__embedding, 'metric = cosine', @__topN)
Параметр topN задает максимальное количество возвращаемых результатов.
VectorSearch() возвращает значение VectorSearchResult<TEntity>, позволяющее получить доступ как к сущности, так и к вычисляемому расстоянию:
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();
Это позволяет отфильтровать оценку сходства, представить ее пользователям и т. д.
Гибридный поиск
Гибридный поиск объединяет векторный поиск подобия с традиционным полнотекстовый поиск , чтобы обеспечить более релевантные результаты. Векторный поиск превосходит в нахождении семантически аналогичного содержимого, в то время как полнотекстовый поиск лучше подходит для точного совпадения с ключевыми словами. Сочетая оба подхода и используя слияние с взаимным ранжированием (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)
// 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();
Этот запрос:
- Выполняет полнотекстовый поиск
Article - Выполняет векторный поиск на
Articleи объединяет результаты с результатами полнотекстового поиска с помощью LEFT JOIN. - Вычисляет оценку RRF путем объединения полнотекстового и семантического ранжирования
- Упорядочение по оценке RRF выбирает требуемое количество результатов и извлекает из оригинальных сущностей
Article.
Замечание
Вместо того, чтобы использовать LEFT JOIN, полное ВНЕШНЕЕ СОЕДИНЕНИЕ будет более подходящим для этого сценария; это позволит высокоранговые результаты из любой стороны поиска быть включены в окончательный результат, даже если этот результат не отображается вообще на другой стороне. При приведенном выше подходе LEFT JOIN, если результат имеет очень высокую оценку сходства векторов, он никогда не включается в окончательный результат, если этот результат также не имеет высокой полнотекстовой оценки. Однако EF в настоящее время не поддерживает ПОЛНОЕ ВНЕШНЕЕ СОЕДИНЕНИЕ; upvote #37633, если вы хотите, чтобы это поддерживалось.
Запрос создает следующий SQL:
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