Back to "Fixer le site's Search: PostgreSQL FullMSC2Text Search M SK3and Where It BreaksMST4"

This is a viewer only at the moment see the article on how this works.

To update the preview hit Ctrl-Alt-R (or ⌘-Alt-R on Mac) or Enter to refresh. The Save icon lets you save the markdown file to disk

This is a preview from the server running through my markdig pipeline

ASP.NET PostgreSQL RRF Search

Fixer le site's Search: PostgreSQL FullMSC2Text Search M SK3and Where It BreaksMST4

Wednesday, 14 January 2026

La recherche est l’une de ces fonctions que tout le monde sous-estime. Il semble trivial jusqu’à ce que les utilisateurs réels commencent à écrire des questions réelles. de façon conceptuelle correct but textually wrong. Lorsque la recherche a échoué dans ces cas, les utilisateurs ne pensent pas que le site est bloqué.

Il est également sométhique que ' plague sur ce site depuis sa création. Recherche ouverte, ont travaillé sur PostgreSQL à la recherche de textes complets avec elle' sa fantaisie stuff vector mais n'a jamais été vraiment heureux avec elle abusé je suis particulièrement maintenant en train de construire un outil de recherche dans lucideRAG well I thought I should FINALLY fix it. Que ce soit ou non, c’est une autre question.

Cet article n’est pas sur la construction d’un moteur de recherche à partir du zéro, ., mais sur la correction des bords étroits de PostgreSQL complet, -, de la recherche textuelle dans un système de production réel.., j’aborderai les échecs spécifiques que j’ai rencontrés et ,, pourquoi ils se sont produits, MSC7 et les corrections pragmatiques requises pour faire en sorte que la recherche se comporte comme les utilisateurs l’attendent déjà.

Renforcement des travaux antérieurs: Cet article étend la Mise en œuvre de la recherche sémantique qui a ajouté une recherche hybride avec la fusion de rangs réciproques (RRF). Cet article antérieur couvrait les fondements -combinant PostgreSQL fullM SK3text search with Qdrant vector searchMSC4 Ce article corrige les cas étroits que la mise en œuvre a manqués

L’infrastructure de recherche sémantique sert à deux fins : et fournit la couche de récupération pour Avocat GPT Système RAG -un assistant à l'écriture qui rédige de nouveaux postes en utilisant le site'le contenu existant comme base de connaissances . Pour des plongées plus poussées dans la technologie sous-jacente, voir Établissement d’une partie "avocat GPTM SK1 – sur les embeddings et la recherche par vecteur.

Les problèmes

1. Les résultats vides montrent des articles aléatoires

Lorsque une recherche n'a révélé aucun résultat, le système a montré des articles anciens au hasard plutôt que des suggestions utiles . Cela violait le principe de la moindre surprise - les utilisateurs attendaient soit des résultats pertinents, soit un résultat clair MSC3 aucune correspondance trouvéeMSC4 message avec des messages récents en tant que suggestionsMST5 Ceci a fait apparaître que la recherche avait fonctionné SMC6 simplement malS MC7

La solution: Modifié BlogSearchService.HybridSearchWithPagingAsync() pour détecter quand la recherche retourne des résultats nuls et revenir à l’affichage de nouveaux postes commandés par date descendante. Ajout d’un NoMatchFound Le groupe de travail a examiné les questions suivantes : BasePagingModel de sorte que l'interface puisse afficher un message approprié comme "No match found. Avez-vous dit un de ces messages?

// No match found - return recent posts as suggestions
if (noMatchFound)
{
    Log.Logger.Information("No search results for '{Query}', returning recent posts as suggestions", query);
    return await GetRecentPostsAsSuggestions(targetLanguage, startDate, endDate, page, pageSize);
}

2. Acronymes comme "DiSE" WerenM SK3t Correspondant

PostgreSQL' sa configuration par défaut de recherche textuelle en anglaise indexe techniquement les acronymes, mais la normalisation et le démarrage rendent les termes significatifs peu fiables dans la pratiqueM SK4 Quand vous recherchez MSC5DiSEMska6, il est ramené à "diseMka8 puis le dictionnaire anglais peut l'abandonner ou attribuer un faible poidsMske9 ce qui fait que la recherche entièreMKA10texte manque des articles qui contiennent clairement |MKA11DiSeMSKA12 dans le titre et le contenuM KA13

La solution: Ajout de détection d'acronymes (termes ≤6 caractères avec lettres majusculesM SK3 et case-insensitive substring fallback à l'aide de PostgreSQL ILIKE. Il s'agit de compléter la recherche complète -texte plutôt que de le remplacer (voir les considérations sur le rendement ci-dessous pour savoir pourquoi cela est acceptable

// Detect if query looks like an acronym or short term
var isAcronymLike = query.Length <= 6 && query.Any(char.IsUpper);

// Add substring search for acronyms
searchQuery = searchQuery.Where(x =>
    EF.Functions.ILike(x.Title, $"%{acronym}%")
    || EF.Functions.ILike(x.PlainTextContent, $"%{acronym}%"));

3. Termes techniques comportant des caractères spéciaux Recherche défectueuse

Les recherches pour "ASPM SK1NET" ou "CMSC4 seraient échouées parce que le parser de la recherche textuelle PostgreSQL' traite les périodes et les symboles de hash comme des délimiteursMSSK6 en divisant |"\ASP\M SK8\NET"\ en |"\Asp\MST11\ et |m"\NET+MST13 as tokens distinctsMST14 Cela signifiait que la recherche du terme exact ne fonctionnerait pas.

La solution: Création d’un SearchQueryParser qui reconnaît les termes techniques communs et les remplace par des versions recherchables:

private static readonly Dictionary<string, string> TechnicalTerms = new(StringComparer.OrdinalIgnoreCase)
{
    ["asp.net"] = "aspnet",
    ["c#"] = "csharp",
    [".net"] = "dotnet",
    ["f#"] = "fsharp",
    ["node.js"] = "nodejs",
    // ... more terms
};

4. Demandes similaires à "ASPM SK2NET et Alpine" Ne fonctionnent pas

PostgreSQL traite "et" comme mot d'arrêt et le supprime des recherches.

La solution: Mise en œuvre d’un analyseur de recherche Google de type - qui gère intelligentement les mots stop et appuie des exploitants de recherche avancés

Les solutions

Opérations de recherche Google-Style

J'ai mis en œuvre un SearchQueryParser classe qui analyse les demandes avec l’appui de:

  1. Phrases citées: "exact match" - recherche la phrase exacte
  2. Conditions exclues: -unwanted - exclut les résultats contenant ce terme
  3. Cartes sauvages: ASP* - correspond aux matches "ASP",
  4. Conditions techniques: Manipule automatiquement "ASPM SK2NET", "CMSC5 ≥".NET" etc.

Le parteur utilise un modèle de regex compilé pour marquer la demande:

[GeneratedRegex(@"""([^""]+)""|(-)?(\S+)", RegexOptions.Compiled)]
private static partial Regex QueryTokenRegex();

public ParsedQuery Parse(string query)
{
    var matches = QueryTokenRegex().Matches(processedQuery);

    foreach (Match match in matches)
    {
        // Quoted phrase
        if (match.Groups[1].Success)
        {
            var phrase = match.Groups[1].Value.Trim();
            result.Phrases.Add(phrase);
            continue;
        }

        // Excluded term (starts with -)
        if (match.Groups[2].Success)
        {
            var term = match.Groups[3].Value.Trim();
            result.ExcludeTerms.Add(term.ToLowerInvariant());
            continue;
        }

        // Regular term or wildcard
        var token = match.Groups[3].Value.Trim();
        if (token.Contains('*'))
        {
            result.WildcardTerms.Add(token.Replace("*", ""));
        }
        else if (!StopWords.Contains(token))
        {
            result.IncludeTerms.Add(token.ToLowerInvariant());
        }
    }
}

Établissement de l'esquisse PostgreSQL

Le parteur produit des données structurées qui sont ensuite converties en PostgreSQL. to_tsquery car nous générons une syntaxe structurée - et non websearch_to_tsquery car nous avons déjà analysé les opérateurs eux-mêmes, ce qui nous donne plus de contrôle sur la façon dont les termes sont combinés.

public string BuildTsQuery(ParsedQuery parsed)
{
    var queryParts = new List<string>();

    // Add include terms with AND
    foreach (var term in parsed.IncludeTerms)
    {
        queryParts.Add(term);
    }

    // Add wildcard terms with :* suffix
    foreach (var term in parsed.WildcardTerms)
    {
        queryParts.Add($"{term}:*");
    }

    return queryParts.Count > 0 ? string.Join(" & ", queryParts) : string.Empty;
}

Pourquoi ne pas simplement utiliser websearch_to_tsquery? Parce qu’il ne fonctionne toujours pas sur le plan technique, acronymes, et domaineM SK2syntaxe spécifique MSC3et n’offre aucun crochets pour la classement hybride ou les défaillances . En nous analysant nous-mêmesMska5, nous pouvons traiter ces cas avant qu’ils ne parviennent à PostgreSQLMske6

Enhanced BuildSearchQuery

L'article 5 de la Loi sur l'immigration et le statut des réfugiés BuildSearchQuery la méthode a été complètement rédigée pour utiliser la structure de demande parlée. Notez que baseQuery already filters by language, date range, and visibility - weM SK3re adding searchMska4specific conditions on topM Ska5

private IOrderedQueryable<BlogPostEntity> BuildSearchQuery(
    string query,
    string language,
    DateTime? startDate,
    DateTime? endDate,
    string order)
{
    var parsed = _queryParser.Parse(query);
    IQueryable<BlogPostEntity> searchQuery = baseQuery;

    // Handle phrases (exact substring matching)
    foreach (var phrase in parsed.Phrases)
    {
        searchQuery = searchQuery.Where(x =>
            EF.Functions.ILike(x.Title, $"%{phrase}%")
            || EF.Functions.ILike(x.PlainTextContent, $"%{phrase}%")
            || x.Categories.Any(c => EF.Functions.ILike(c.Name, $"%{phrase}%")));
    }

    // Build tsquery for include terms and wildcards
    var tsQuery = _queryParser.BuildTsQuery(parsed);

    // Apply full-text search if we have terms
    if (!string.IsNullOrWhiteSpace(tsQuery))
    {
        searchQuery = searchQuery.Where(x =>
            x.SearchVector.Matches(EF.Functions.ToTsQuery("english", tsQuery))
            || x.Categories.Any(c =>
                EF.Functions.ToTsVector("english", c.Name)
                    .Matches(EF.Functions.ToTsQuery("english", tsQuery))));
    }

    // Handle acronyms with case-insensitive substring search
    // This supplements full-text search (additive OR), not replaces it
    var acronymTerms = parsed.IncludeTerms
        .Concat(parsed.WildcardTerms)
        .Where(t => _queryParser.IsAcronymLike(t))
        .ToList();

    foreach (var acronym in acronymTerms)
    {
        searchQuery = searchQuery.Where(x =>
            EF.Functions.ILike(x.Title, $"%{acronym}%")
            || EF.Functions.ILike(x.PlainTextContent, $"%{acronym}%"));
    }

    // Handle excluded terms (must NOT contain these)
    foreach (var excludeTerm in parsed.ExcludeTerms)
    {
        searchQuery = searchQuery.Where(x =>
            !EF.Functions.ILike(x.Title, $"%{excludeTerm}%")
            && !EF.Functions.ILike(x.PlainTextContent, $"%{excludeTerm}%")
            && !x.Categories.Any(c => EF.Functions.ILike(c.Name, $"%{excludeTerm}%")));
    }

    return orderedQuery;
}

Exemples de recherche

Voici quelques exemples de la fonctionnalité de recherche améliorée:

Recherche fondamentale

DiSE

✅ Maintenant, les articles correspondent à "DiSEM SK2 dans le titre ou le contenu.

Conditions techniques

ASP.NET

✅ Trouver des articles sur ASPM SK1NET (convert automatiquement en SSK3aspnet" pour une recherche complèteMSC5texte

Recherche de phrases

"semantic search"

✅ Trouve la phrase exacte " recherche sémantiqueM SK2 dans les articles

Conditions exclues

ASP.NET -Core

✅ Trouve les articles ASPM SK1NET mais exclut ceux qui mentionnent "Core"

Cartes sauvages

ASP*

✅ Correspondences "ASP", "A SPNETM SK4

Demande complexe

"full text search" PostgreSQL -MySQL

✅ Trouve des articles avec une phrase exacte "recherche de texte complet" ET mentions de PostgreSQLM SK3, mais À L'exclusion des articles qui mentionnent MySQL

Exemple avant et après

Demande de renseignements: ASP.NET and Alpine

Avant (brokenM SK1

  • "ASP.NETM SK2 divisé en "AspMSC4 + |
  • "etM SK1 supprimés comme mot d'arrêt
  • Résultat: Seules les recherches pour M SK1Alpine"

Après (fixedM SK1

  • Convert à "aspnet"
  • "et" préservés intelligentement dans le cadre de l'intention d'une demande d'utilisateur
  • "AlpineM SK1 recherche normale
  • Résultat: Trouve des articles sur ASP.NET et Alpine

Intégration du classement RRF

La recherche s’intègre à la fusion de rangs réciproques (RRFM SK1 telle qu’elle est mise en œuvre dans le article de recherche sémantique antérieure. Le RRF ici est utilisé pour classement, ne se rappelle pas - il combine déjà les résultats obtenus à partir de BMM SK3 complets- recherche textuelle et recherche sémantique vectorielle

// Fuse using RRF with category/freshness boosts
var fusedDtos = _ranker.FuseResults(bm25Results, vectorResults, query);

L'algorithme RRF utilise 1/(k+rank) où k=60 combine les résultats provenant de multiples sources , puis applique des stimulations pourM SK2

  • Correspondance des catégories: +2.0
  • Match de titre: +1.0
  • La fraîcheur: Dégradation exponentielle au cours d’une année 1

Pour la mise en œuvre complète du RRF et comment fonctionne la recherche hybride, voir Recherche sémantique en action. Pour des plongées plus profondes dans les emplacements et la similitude du vecteurM SK1 voir Établissement d’une partie "avocat GPTM SK1 -. La même infrastructure permet à l’utilisateur de faire une recherche face à - et à la récupération RAG pour AI-à l’aide d’un écriture assistéeM SK3

Architecture technique

Injection de dépendance

Les nouveaux éléments sont enregistrés comme services:

services.AddSingleton<SearchQueryParser>();
services.AddSingleton<SearchRanker>();
services.AddScoped<BlogSearchService>();

SearchQueryParser et SearchRanker sont des singletons parce qu’ils' sont instérétés , fil- sécuritaireM SK3 et peuvent Ãatre réutilisées dans toutes les demandesMSC4 BlogSearchService est scoped parce qu’il accédera au contexte de la base de données.

Flux de demandes

  1. L'utilisateur entre une demande de recherche → Contrôleur de recherche
  2. Partage de la demande → SearchQueryParser se divise en composants structurels
  3. Recherche sémantique (si activée) → Base de données du vecteur Qdrant avec embeddings ONNX
  4. PostgreSQL complet-recherche de texte ( toujours disponibleM SK2 → BMM SK1connaissance des mots clés fondée
  5. Fusion RRF → Combine les deux ensembles de résultats avec la catégorieM SK1accroissement de la fraîcheur
  6. Aucun résultat → Retourne les articles récents comme suggestions

La même composante de recherche sémantique est également utilisée par Avocat GPT système permettant de récupérer des articles d’un blog antérieur pertinents pour AI-assisted writing. Voir Partie 4 pour plus de détails sur le pipeline d’ingestion.

Système de base de données

La recherche se fonde sur une présomption antérieure SearchVector dans la colonne BlogPosts Tableau:

ALTER TABLE mostlylucid."BlogPosts"
ADD COLUMN "SearchVector" tsvector
GENERATED ALWAYS AS (
    to_tsvector('english',
        coalesce("Title", '') || ' ' ||
        coalesce("PlainTextContent", '')
    )
) STORED;

CREATE INDEX idx_blog_posts_search_vector
ON mostlylucid."BlogPosts"
USING GIN ("SearchVector");

Le GIN (Index inversé généralisé) fournit une recherche rapide et complète de textes -à travers les grandes corporations de texteM SK3

Considérations relatives au rendement

Pourquoi ILIKE pour les acronymes?

Pendant ILIKE (caseM SK1insensitive LIKE) est plus lente que le texte complet -recherche de texte M SK4 ilMSC5est nécessaire pour les acronymes car

  1. Full-text search normalizes/stems termsM SK2 breaking short uppercase strings
  2. Les acronymes sont généralement courts (≤6 caractèresM SK1 limitant l'impact sur la performance
  3. La condition n'est ajoutée que lorsque nécessaire (acronymes détectésM SK1

Cette approche ne serait pas adaptée à la recherche arbitraire de sous-strings sur des millions de lignes.

Répartition de la densité des couvertures PostgreSQL (ts_rank_cd)

PostgreSQL offre deux fonctions de classement pour la recherche complète

  • ts_rank: Fréquence de l'expression de base ( Combien de fois les termes apparaissent?
  • ts_rank_cd: Répartition de la densité de couverture (de quelle façon les termes se présentent ensemble

Nous utilisons ts_rank_cd car elle fournit Relevance similaire à BM25- en tenant compte de la proximité du terme:

// Order by cover density ranking - rewards term proximity
orderedQuery = searchQuery.OrderByDescending(x =>
    x.SearchVector.RankCoverDensity(EF.Functions.ToTsQuery("english", tsQuery)));

Pourquoi? ts_rank_cd est supérieur:

Metrique ts_rank ts_rank_cd
Algorithme Fréquence à terme Densité de couverture MSC2proximité MSC3 SMC4
Demandes de mots multiples- Compte les termes séparément Termes de récompense apparaissant ensemble
Exemple: M SK1contenants de docker" Article avec "docker" 50 points élevés à plusieurs reprises
Rendement Fast Marginally slowerM SK2 still levers GIN index
Le comportement Compte simple Moyenne BMM SK2

Il s’agit d’un Optimisation rapide de la victoire - meilleure classement de la pertinence avec application zéro-computation à niveauM SK2 Tous les rangs se font dans PostgreSQL en utilisant l’indice GIN existant sur SearchVector.

Références:

Optimisations supplémentaires du rendement

Au-delà de fixer la fonctionnalité de recherche, plusieurs améliorations clés améliorent le rendement:

1. Cache linguistique

Les langues disponibles changent rarement mais ont été demandées à chaque demande de recherche. Maintenant cachée avec double-enroulement vérifiéM SK2

private static readonly TimeSpan LanguageCacheDuration = TimeSpan.FromHours(1);
private static List<string>? _cachedLanguages;
private static DateTime _languageCacheExpiry = DateTime.MinValue;
private static readonly SemaphoreSlim _cacheLock = new(1, 1);

Incidences: Élimine la question de base de données 1 par demande de recherche

2. Demandes d'ILIKE en série

Code original utilisé foreach loops créant plusieurs clauses WHERE. Maintenant battues en expressions uniques:

// BEFORE: Multiple WHERE clauses
foreach (var acronym in acronymTerms)
{
    searchQuery = searchQuery.Where(x =>
        EF.Functions.ILike(x.Title, $"%{acronym}%"));
}

// AFTER: Single batched WHERE
if (acronymTerms.Count > 0)
{
    searchQuery = searchQuery.Where(x =>
        acronymTerms.Any(acronym =>
            EF.Functions.ILike(x.Title, $"%{acronym}%")));
}

Incidences: SQL plus propre, ~5-10% plus rapide pour les demandes à plusieurs datesM SK3

3. Index de couverture pour les demandes courantes

Indice partiel avec colonnes INCLUDE pour les modèles d’accès fréquents:

CREATE INDEX idx_blog_posts_search_covering
ON mostlylucid."BlogPosts" ("LanguageId", "IsHidden", "ScheduledPublishDate")
INCLUDE ("Id", "Slug", "Title", "PublishedDate")
WHERE "IsHidden" = false;

Incidences: Enable index-scans seulement - PostgreSQL n’a pas besoin d’avoir accès à l’échelon de tableaux ', mais de réduire I/O par 20-30% pour les demandes courantes

4. Retiré Inclut des éléments inutiles

EF Core's Include() charge les entités de navigation complètes. Supprimé lorsque seules les propriétés de navigation sont utilisées dans les clauses DE QUOIM SK1

// BEFORE: Loads full LanguageEntity into memory
.Include(x => x.LanguageEntity)
.Where(x => x.LanguageEntity.Name == "en")

// AFTER: EF translates navigation property without loading entity
.Where(x => x.LanguageEntity.Name == "en")

Incidences: ~5-10% réduction de la mémoireM SK2 moins de données transférées de la base de données.

Références:

Stratégie d'optimisation des demandes

Recherche construit Où les clauses sont incrémentiellement utilisées EF Core's expression tree composition:

IQueryable<BlogPostEntity> searchQuery = baseQuery;

// Each filter added conditionally - PostgreSQL optimizes the final query
if (parsed.Phrases.Count > 0) { searchQuery = searchQuery.Where(...); }
if (!string.IsNullOrWhiteSpace(tsQuery)) { searchQuery = searchQuery.Where(...); }
if (acronymTerms.Count > 0) { searchQuery = searchQuery.Where(...); }

Il s'agit d'une une seule demande SQL optimisée rather than multiple round trips. PostgreSQL' le planificateur de demande peut utiliser les statistiques et les indices efficacement lorsqu’il voit la clause WHERE complète

Résumé du rendement

Impact cumulatif de toutes les optimizations:

Optimisation Impact de la latence MSC2 Impact du chargement DB MSC3
Cache de langues Minimale CMS2 CMS3 demandeC MS4requête MCMS5
Supprimer InclureM SK1 3 4 Moins transfert de données
Batch ILIKE -5-10% ≥ Cleaner SQL MSC4
Indice d'indice de couverture MSC2 MSC3 IndicesMSc4scans seulement SMC5
tsM SK1rank_cd semblable MSC4 Importance accrue MSC5
Établissement de la cache ( paramètres routiers ) M NM SK4A P Prévient les données bloquées R

Amélioration totale prévue: 30-50% recherche plus rapide avec une charge de base de données nettement réduite.

Les leçons apprises

  1. Don't assume full-text search handles everything: Les cases à bord comme les acronymes et les caractères spéciaux nécessitent une manipulation spéciale

  2. Combiner plusieurs approches: Recherche textuelle complèteM SK1 recherche sémantique (BM25) + recherche semantice SSK5vectorsMSC6 + les retraits de sous-strings offrent une meilleure couverture que n'importe quelle méthode unique.

  3. Les attentes des utilisateurs formées par Google: Soutenir les phrases citéesM SK1 exclusions , et cartes vives rend la recherche plus naturelle parce que les utilisateurs sont déjà familiers avec ces opérateurs.

  4. Fournir des répercussions utiles: Lorsque la recherche se révèle insuffisante , ne montrent rien' ne font pas apparaître aucun message - montrent les articles récents et indiquent clairement qu'aucun match n'a été trouvéM SK4

  5. Parse, don't hack: Un analyseur de demande approprié est plus propre et plus entretenable qu’une série d’ manipulations à chaînes.

  6. Leverage PostgreSQL's construits-in ranking: Usage ts_rank_cd au lieu de ts_rank pour le BM25-relevance similaireM SK1Le classement de la densité de couverture tient compte de la proximité du terme -une victoire rapide qui améliore la qualité des résultats avec une application zéro

  7. Profil avant l'optimisation: Les lacunes de l’analyse des SFT1obvious" ne constituaient pas le problème réel . Les recherches linguistiquesMSC7 incluent excessivementM SK8 et les indices manquants ont eu un impact plus important que prévuMST9

  8. Opérations de base de données par lots: Multiple foreach loops créant des clauses distinctes POURQUOI les clauses génèrent un SQL suboptimal. Usage Any() ou All() pour les expressions uniques.

Améliorations à venir

Possibilités d’amélioration pour l’avenir, catégorisée par préoccupationM SK1

Amélioration de la recherche:

  • Correspondance floue: Distance de Levenshtein pour la tolérance au typo
  • Expansion synonyme:

Amélioration de l'analyse:

  • Filtration des catégories: category:ASP.NET opérateur
  • Répartition des dates: after:2025-01-01 opérateur

Réfinitions du classement:

  • Éclaircissement des résultats: Afficher les parties de texte correspondantes dans les résultats
  • Cliquer-à travers le suivi: Apprenez à partir du comportement des utilisateurs pour améliorer le classement

Observabilité:

  • Analyse de la recherche: Suivi des demandes populaires et recherches manquantes pour identifier les lacunes

Conclusion

Fabrication de bâtiments- recherche de classe exige la fixation des cases en bordure et Optimisation de la performance. Cet article a porté sur les deux éléments suivants : : fixer PostgreSQL complet, - cases de recherche à bord du texte, | ( acronymes, , termes techniques, ◦ , | Google, ─ - | exploitants de style, ‒ ) | et mettre en œuvre des améliorations clés de la rendement. ts_rank_cd).

La mise en œuvre 30-50% recherche plus rapide tout en réduisant la charge de base de données grâce à:

  • Classement de la densité de couverture (ts_rank_cd) pour une meilleure pertinence
  • Cachement linguistique éliminant les demandes répétées
  • Expressions ILIKE battues pour SQL plus propre
  • Couverture des indices permettant les scans d'index-seulement
  • Remplacement du noyau EF inutile inclut

L’influence clé: aucune approche unique ne traite de tous les cas . PostgreSQL FTS excelle en ce qui concerne le matchage des mots-clés, la recherche sémantique traite des demandes conceptuellesM SK3 et les reculs ciblés atteignent les cases à bordMSC4 La couche d’analyse propre l’intègre ensembleMST5 traite les opérateurs et les termes techniques avant qu’ils ne parviennent aux moteurs de rechercheM ST6

L’infrastructure de recherche sémantique sert à deux fins:

  • Utilisateur- Face à la recherche: Combine le mot clé et la combinaison sémantique pour obtenir de meilleurs résultats
  • Récupération du RAG: Fait fonctionner Avocat GPT assistant à l'écriture

Articles connexes:

Documentation officielle:

Tous les codes disponibles dans le blog's GitHub repository.

logo

© 2026 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.