Udostępnij za pośrednictwem


Wyszukiwanie Full-Text w dostawcy EF Core dla SQL Server

Program SQL Server udostępnia funkcje wyszukiwania pełnotekstowego , które umożliwiają zaawansowane wyszukiwanie tekstu poza prostymi LIKE wzorcami. Wyszukiwanie pełnotekstowe obsługuje dopasowywanie językowe, formy fleksyjne, wyszukiwanie bliskości i klasyfikację ważoną.

Dostawca programu SQL Server platformy EF Core obsługuje zarówno predykaty wyszukiwania pełnotekstowego (na potrzeby filtrowania) jak i funkcje wartości tabeli (do filtrowania przy użyciu klasyfikacji).

Przed rozpoczęciem wyszukiwania pełnotekstowego należy utworzyć katalog pełnotekstowy w bazie danych oraz indeks pełnotekstowy w kolumnach, które chcesz wyszukać.

Uwaga / Notatka

W programie EF Core 11 wprowadzono zarządzanie wykazem pełnotekstowym i indeksem podczas migracji.

Katalogi i indeksy pełnotekstowe można skonfigurować bezpośrednio w modelu EF. Po dodaniu migracji program EF wygeneruje odpowiedni kod SQL w celu utworzenia (lub zmiany) katalogu i indeksu.

Najpierw zdefiniuj katalog pełnotekstowy w modelu, a następnie skonfiguruj indeks pełnotekstowy dla typu jednostki:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.HasFullTextCatalog("ftCatalog");

    modelBuilder.Entity<Article>()
        .HasFullTextIndex(a => a.Contents)
        .HasKeyIndex("PK_Articles")
        .OnCatalog("ftCatalog");
}

Metoda HasKeyIndex() określa unikatowy, niepusty indeks z jedną kolumną używany jako klucz pełnotekstowy dla tabeli (zazwyczaj indeks klucza podstawowego). OnCatalog() przypisuje indeks pełnotekstowy do określonego wykazu.

Można również skonfigurować wiele kolumn i dodatkowych opcji, takich jak języki poszczególnych kolumn i śledzenie zmian:

modelBuilder.Entity<Article>()
    .HasFullTextIndex(a => new { a.Title, a.Contents })
    .HasKeyIndex("PK_Articles")
    .OnCatalog("ftCatalog")
    .WithChangeTracking(FullTextChangeTracking.Manual)
    .HasLanguage("Title", "English")
    .HasLanguage("Contents", "French");

Katalog pełnotekstowy można również skonfigurować jako domyślny katalog, z czułością na akcenty.

modelBuilder.HasFullTextCatalog("ftCatalog")
    .IsDefault()
    .IsAccentSensitive(false);

Aby uzyskać więcej informacji, zobacz dokumentację wyszukiwania pełnotekstowego programu SQL Server.

Predykaty pełnotekstowe

EF Core obsługuje zarówno FREETEXT() predykaty, jak i CONTAINS(), które są używane w klauzulach Where() do filtrowania wyników.

FREETEXT()

FREETEXT() wykonuje mniej ścisłe dopasowywanie, wyszukując wyrazy na podstawie ich znaczenia, w tym odmiany (takie jak formy czasowników i liczby mnogiej rzeczowników):

var articles = await context.Articles
    .Where(a => EF.Functions.FreeText(a.Contents, "veggies"))
    .ToListAsync();

Przekłada się to na:

SELECT [a].[Id], [a].[Title], [a].[Contents]
FROM [Articles] AS [a]
WHERE FREETEXT([a].[Contents], N'veggies')

Opcjonalnie możesz określić termin języka:

var articles = await context.Articles
    .Where(a => EF.Functions.FreeText(a.Contents, "veggies", "English"))
    .ToListAsync();

CONTAINS()

CONTAINS() Wykonuje dokładniejsze dopasowywanie i obsługuje bardziej zaawansowane kryteria wyszukiwania, w tym prefiksy, wyszukiwanie według bliskości i ważone terminy:

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

Przekłada się to na:

SELECT [a].[Id], [a].[Title], [a].[Contents]
FROM [Articles] AS [a]
WHERE CONTAINS([a].[Contents], N'veggies')

Aby uzyskać więcej informacji na CONTAINS() temat składni zapytań, zobacz dokumentację funkcji CONTAINS w programie SQL Server.

Funkcje pełnotekstowe z wartościami tabeli

Uwaga / Notatka

Funkcje pełnotekstowe o wartości tabeli są wprowadzane w programie EF Core 11.

Powyższe predykaty są przydatne do filtrowania, ale nie udostępniają informacji o klasyfikacji. Funkcje zwracające tabelę programu SQL Server, takie jak FREETEXTTABLE() i CONTAINSTABLE(), zwracają zarówno pasujące wiersze, jak i wynik klasyfikacji, który wskazuje, jak dobrze każdy wiersz odpowiada zapytaniu wyszukiwania.

FreeTextTable()

FreeTextTable() to tabelawartościowa wersja FreeText()funkcji . Zwraca wartość FullTextSearchResult<TEntity>, która zawiera zarówno jednostkę, jak i wartość klasyfikacji:

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

Należy pamiętać, że należy podać parametry typu ogólnego; Article odpowiada wyszukiwanym typowi jednostki, gdzie int jest kluczem wyszukiwania pełnotekstowego określonym podczas tworzenia indeksu, który jest zwracany przez FREETEXTTABLE()element .

Powyższe polecenie automatycznie wyszukuje wszystkie kolumny zarejestrowane w celu wyszukiwania pełnotekstowego i zwraca 10 pierwszych dopasowań. Możesz również podać określoną kolumnę do wyszukiwania:

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

... lub wiele kolumn:

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() to wersja Contains()funkcji wartości tabeli , która obsługuje tę samą zaawansowaną składnię wyszukiwania, a jednocześnie udostępnia informacje o klasyfikacji:

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

Ograniczanie wyników

Funkcje zwracające tabelę obsługują parametr topN, który ogranicza liczbę wyników.

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

Określanie języka

Obie funkcje tabelaryczne obsługują ustalenie parametru językowego do dopasowywania językowego.

var results = await context.Articles
    .FreeTextTable(a => a.Contents, "veggies", languageTerm: "English")
    .Select(r => new { Article = r.Value, Rank = r.Rank })
    .ToListAsync();

Kiedy należy używać predykatów a funkcji wartości tabeli

Funkcja Predykaty (FreeText(), Contains()) Funkcje wartości tabeli (FreeTextTable(), ContainsTable())
Udostępnia klasyfikację ❌ Nie ✅ Tak
Wydajność dużych zestawów wyników Lepiej do filtrowania Lepsze do rankingowania i sortowania
Łączenie z innymi jednostkami Przez połączenia Wynik wbudowanej jednostki
Użyj w klauzuli Where() ✅ Tak ❌ Nie (użyj jako źródła)

Użyj predykatów, gdy wystarczy filtrować wyniki na podstawie kryteriów wyszukiwania pełnotekstowego. Użyj funkcji o wartości tabeli, gdy potrzebujesz informacji o klasyfikacji, aby uporządkować wyniki według istotności lub wyświetlić wyniki istotności dla użytkowników.