Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
SQL Server предоставляет возможности полнотекстового поиска , которые обеспечивают сложный поиск текста за пределами простых LIKE шаблонов. Полнотекстовый поиск поддерживает лингвистическое сопоставление, инфлекционные формы, поиск по близости и взвешенное ранжирование.
Поставщик SQL Server EF Core поддерживает как предикаты полнотекстового поиска (для фильтрации), так и таблично-значимые функции (для фильтрации с ранжированием).
Настройка полнотекстового поиска
Прежде чем использовать полнотекстовый поиск, необходимо создать полнотекстовый каталог в базе данных и полнотекстовый индекс столбцов, которые требуется выполнить поиск.
Замечание
Полнотекстовый каталог и управление индексами в миграциях было введено в EF Core 11.
Вы можете настроить полнотекстовые каталоги и индексы непосредственно в модели EF. При добавлении миграции EF создаст соответствующий SQL для создания (или изменения) каталога и индекса.
Сначала определите полнотекстовый каталог в модели, а затем настройте полнотекстовый индекс для типа сущности:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.HasFullTextCatalog("ftCatalog");
modelBuilder.Entity<Article>()
.HasFullTextIndex(a => a.Contents)
.HasKeyIndex("PK_Articles")
.OnCatalog("ftCatalog");
}
Метод HasKeyIndex() задает уникальный, не допускающий значения NULL, индекс с одним столбцом, используемый в качестве полнотекстового ключа таблицы (обычно индекс первичного ключа).
OnCatalog() назначает полнотекстовый индекс определенному каталогу.
Можно также настроить несколько столбцов и дополнительные параметры, такие как языки столбцов и отслеживание изменений:
modelBuilder.Entity<Article>()
.HasFullTextIndex(a => new { a.Title, a.Contents })
.HasKeyIndex("PK_Articles")
.OnCatalog("ftCatalog")
.WithChangeTracking(FullTextChangeTracking.Manual)
.HasLanguage("Title", "English")
.HasLanguage("Contents", "French");
Полнотекстовый каталог также можно настроить в качестве каталога по умолчанию и с чувствительностью к акцентам:
modelBuilder.HasFullTextCatalog("ftCatalog")
.IsDefault()
.IsAccentSensitive(false);
Дополнительные сведения см. в документации по полнотекстовом поиску SQL Server.
Предикаты полнотекстового текста
EF Core поддерживает FREETEXT() и CONTAINS() предикаты, которые используются в Where() предложениях для фильтрации результатов.
FREETEXT()
FREETEXT() выполняет менее строгое сопоставление, поиск слов на основе их значения, включая инфлекционные формы (например, глагольные времена и множественные числа существительных):
var articles = await context.Articles
.Where(a => EF.Functions.FreeText(a.Contents, "veggies"))
.ToListAsync();
Это означает:
SELECT [a].[Id], [a].[Title], [a].[Contents]
FROM [Articles] AS [a]
WHERE FREETEXT([a].[Contents], N'veggies')
При необходимости можно указать термин языка:
var articles = await context.Articles
.Where(a => EF.Functions.FreeText(a.Contents, "veggies", "English"))
.ToListAsync();
CONTAINS()
CONTAINS() выполняет более точное сопоставление и поддерживает более сложные критерии поиска, включая префиксные термы, поиск по близости и взвешенные термы.
// Simple search
var articles = await context.Articles
.Where(a => EF.Functions.Contains(a.Contents, "veggies"))
.ToListAsync();
// Prefix search (words starting with "vegg")
var articles = await context.Articles
.Where(a => EF.Functions.Contains(a.Contents, "\"vegg*\""))
.ToListAsync();
// Phrase search
var articles = await context.Articles
.Where(a => EF.Functions.Contains(a.Contents, "\"fresh vegetables\""))
.ToListAsync();
Это означает:
SELECT [a].[Id], [a].[Title], [a].[Contents]
FROM [Articles] AS [a]
WHERE CONTAINS([a].[Contents], N'veggies')
Дополнительные сведения о синтаксисе запросов см. в CONTAINS()документации ПО SQL Server CONTAINS.
Функции с полнотекстовых табличными значениями
Замечание
В EF Core 11 вводятся табличные функции, возвращающие полнотекстовый результат.
Хотя приведенные выше предикаты полезны для фильтрации, они не предоставляют сведения о ранжировании. Табличные функции SQL Server FREETEXTTABLE() и CONTAINSTABLE() возвращают как соответствующие строки, так и оценку ранжирования, указывающую, насколько хорошо каждая строка соответствует поисковому запросу.
FreeTextTable()
FreeTextTable() — это версия FreeText()функции с табличным значением. Возвращается FullTextSearchResult<TEntity>, включающее как сущность, так и значение ранжирования:
var results = await context.Articles
.Join(
context.Articles.FreeTextTable<Article, int>("veggies", topN: 10),
a => a.Id,
ftt => ftt.Key,
(a, ftt) => new { Article = a, ftt.Rank })
.OrderByDescending(r => r.Rank)
.ToListAsync();
foreach (var result in results)
{
Console.WriteLine($"Article {result.Article.Id} with rank {result.Rank}");
}
Обратите внимание, что необходимо указать параметры универсального типа; Article соответствует типу сущности, для которого выполняется поиск, а int - это полнотекстовый ключ поиска, указанный при создании индекса, и который возвращается FREETEXTTABLE().
Приведенный выше автоматически выполняет поиск по всем столбцам, зарегистрированным для полнотекстового поиска, и возвращает первые 10 совпадений. Вы также можете указать определенный столбец для поиска:
var results = await context.Articles
.Join(
context.Articles.FreeTextTable<Article, int>(a => a.Contents, "veggies"),
a => a.Id,
ftt => ftt.Key,
(a, ftt) => new { Article = a, ftt.Rank })
.OrderByDescending(r => r.Rank)
.ToListAsync();
... или несколько столбцов:
var results = await context.Articles
.FreeTextTable(a => new { a.Title, a.Contents }, "veggies")
.Select(r => new { Article = r.Value, Rank = r.Rank })
.OrderByDescending(r => r.Rank)
.ToListAsync();
ContainsTable()
ContainsTable() — это версия Contains()функции с табличным значением, поддерживающая тот же сложный синтаксис поиска, а также предоставление сведений о ранжировании:
var results = await context.Articles
.Join(
context.Articles.ContainsTable<Article, int>( "veggies OR fruits"),
a => a.Id,
ftt => ftt.Key,
(a, ftt) => new { Article = a, ftt.Rank })
.OrderByDescending(r => r.Rank)
.ToListAsync();
Ограничение результатов
Обе функции с табличным значением поддерживают topN параметр, чтобы ограничить количество результатов:
var results = await context.Articles
.FreeTextTable(a => a.Contents, "veggies", topN: 10)
.Select(r => new { Article = r.Value, Rank = r.Rank })
.OrderByDescending(r => r.Rank)
.ToListAsync();
Указание языка
Обе функции с табличным значением поддерживают указание термина языка для лингвистического сопоставления:
var results = await context.Articles
.FreeTextTable(a => a.Contents, "veggies", languageTerm: "English")
.Select(r => new { Article = r.Value, Rank = r.Rank })
.ToListAsync();
Когда следует использовать предикаты и функции с табличным значением
| Функция | Предикаты (FreeText(), Contains()) |
Функции с табличным значением (FreeTextTable(), ContainsTable()) |
|---|---|---|
| Предоставляет ранжирование | ❌ Нет | ✅ Да |
| Производительность для больших наборов результатов | Лучше подходит для фильтрации | Лучше для ранжирования и сортировки |
| Объединение с другими сущностями | С помощью соединений | Результат встроенной сущности |
Использование в Where() предложении |
✅ Да | ❌ Нет (использовать в качестве источника) |
Используйте предикаты, если необходимо просто фильтровать результаты на основе условий полнотекстового поиска. Используйте функции с табличным значением, если вам нужна информация о ранжировании, чтобы упорядочить результаты по релевантности или отображать оценки релевантности для пользователей.