Freigeben über


Full-Text Suche im SQL Server EF Core Provider

SQL Server bietet Volltext-Suchfunktionen , die eine anspruchsvolle Textsuche über einfache LIKE Muster hinaus ermöglichen. Die Volltextsuche unterstützt linguistische Übereinstimmungen, inflectionale Formen, Näherungssuche und gewichtete Rangfolge.

Der SQL Server-Anbieter von EF Core unterstützt sowohl Volltext-Such-Prädikate (zum Filtern) als auch Tabellenwertfunktionen (zum Filtern mit Rangfolge).

Bevor Sie die Volltextsuche verwenden, müssen Sie einen Volltextkatalog in Ihrer Datenbank und einen Volltextindex für die Spalten erstellen, die Sie durchsuchen möchten.

Hinweis

Volltextkatalog und Indexverwaltung in Migrationen wurde in EF Core 11 eingeführt.

Sie können Volltextkataloge und Indizes direkt in Ihrem EF-Modell konfigurieren. Wenn Sie eine Migration hinzufügen, generiert EF den entsprechenden SQL-Befehl, um die Kataloge und Indizes für Sie zu erstellen (oder zu ändern).

Definieren Sie zunächst einen Volltextkatalog für das Modell, und konfigurieren Sie dann einen Volltextindex für Ihren Entitätstyp:

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

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

Die HasKeyIndex() Methode gibt den eindeutigen, nicht nullfähigen, einspaltigen Index an, der als Volltextschlüssel für die Tabelle verwendet wird (in der Regel der Primärschlüsselindex). OnCatalog() weist den Volltextindex einem bestimmten Katalog zu.

Sie können auch mehrere Spalten und zusätzliche Optionen konfigurieren, z. B. Sprachen pro Spalte und Änderungsnachverfolgung:

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

Der Volltextkatalog kann auch als Standardkatalog und mit Akzentempfindlichkeit konfiguriert werden:

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

Weitere Informationen finden Sie in der Volltext-Suchdokumentation zu SQL Server.

Volltext-Prädikate

EF Core unterstützt die Prädikate FREETEXT() und CONTAINS(), welche in Where() Klauseln zum Filtern von Ergebnissen verwendet werden.

FREETEXT()

FREETEXT() führt einen weniger strengen Abgleich durch und sucht nach Wörtern basierend auf ihrer Bedeutung, einschließlich flektierter Formen (z. B. Verbformen und Substantivpluralen):

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

Dies bedeutet:

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

Sie können optional einen Sprachbegriff angeben:

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

CONTAINS()

CONTAINS() führt präzisere Übereinstimmungen durch und unterstützt anspruchsvollere Suchkriterien, einschließlich Präfixbegriffen, Näherungssuche und gewichteten Ausdrücken:

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

Dies bedeutet:

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

Weitere Informationen zur CONTAINS() Abfragesyntax finden Sie in der SQL Server CONTAINS-Dokumentation.

Funktionen für volltextuelle Tabellenwerte

Hinweis

Volltext-Tabellenwertfunktionen werden in EF Core 11 eingeführt.

Während die oben genannten Prädikate zum Filtern nützlich sind, stellen sie keine Bewertungsinformationen bereit. Die Tabellenwertfunktionen FREETEXTTABLE() und CONTAINSTABLE() von SQL Server geben sowohl übereinstimmende Zeilen als auch einen Ranking-Score zurück, der angibt, wie gut jede Zeile der Suchabfrage entspricht.

FreeTextTable()

FreeTextTable() ist die Tabellenwert-Funktionsversion von FreeText(). Sie gibt zurück FullTextSearchResult<TEntity>, die sowohl die Entität als auch den Rangfolgewert enthält:

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

Beachten Sie, dass Sie die generischen Typparameter angeben müssen; Article entspricht dem durchsuchten Entitätstyp, wobei int der Volltextsuchschlüssel angegeben ist, der beim Erstellen des Indexes angegeben wird und von FREETEXTTABLE()dem zurückgegeben wird.

Im obigen Abschnitt werden automatisch alle Spalten durchsucht, die für die Volltextsuche registriert sind, und es werden die obersten 10 Übereinstimmungen zurückgegeben. Sie können auch eine bestimmte Spalte für die Suche bereitstellen:

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

... oder mehrere Spalten:

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() ist die Tabellenwert-Funktionsversion von Contains(), die die gleiche komplexe Suchsyntax unterstützt und gleichzeitig Bewertungsinformationen bereitstellt:

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

Einschränken der Ergebnisse

Beide Tabellenwertfunktionen unterstützen einen topN Parameter, um die Anzahl der Ergebnisse zu begrenzen:

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

Angeben einer Sprache

Beide Tabellenwertfunktionen unterstützen die Angabe eines Sprachbegriffs für den linguistischen Abgleich:

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

Gründe für die Verwendung von Prädikaten im Vergleich zu Tabellenwertfunktionen

Funktion Prädikate (FreeText(), Contains()) Tabellenwertfunktionen (FreeTextTable(), ContainsTable())
Stellt rangfolgen bereit ❌ Nein ✅ Ja
Leistung bei großen Ergebnismengen Besser zum Filtern Besser für Rangfolge und Sortierung
Kombinieren mit anderen Entitäten Über Verknüpfungen Integriertes Entitätsergebnis
Verwendung in Where() Klausel ✅ Ja ❌ Nein (als Quelle verwenden)

Verwenden Sie Prädikate, wenn Sie einfach Ergebnisse basierend auf Volltext-Suchkriterien filtern müssen. Verwenden Sie Tabellenwertfunktionen, wenn Sie Bewertungsinformationen benötigen, um Ergebnisse nach Relevanz zu sortieren oder Relevanzbewertungen für Benutzer anzuzeigen.