Sqlserver
 sql >> Base de données >  >> RDS >> Sqlserver

Comment mettre en surbrillance les résultats d'une requête en texte intégral SQL Server

En développant l'idée d'Ishmael, ce n'est pas la solution finale, mais je pense que c'est une bonne façon de commencer.

Il faut d'abord récupérer la liste des mots qui ont été récupérés avec le moteur de texte intégral :

declare @SearchPattern nvarchar(1000) = 'FORMSOF (INFLECTIONAL, " ' + @SearchString + ' ")' 
declare @SearchWords table (Word varchar(100), Expansion_type int)
insert into @SearchWords
select distinct display_term, expansion_type
from sys.dm_fts_parser(@SearchPattern, 1033, 0, 0)
where special_term = 'Exact Match'

Il y a déjà pas mal de choses sur lesquelles on peut s'étendre, par exemple le modèle de recherche est assez basique; il existe également probablement de meilleures façons de filtrer les mots dont vous n'avez pas besoin, mais cela vous donne au moins une liste de mots souches, etc. qui seraient mis en correspondance par une recherche en texte intégral.

Une fois que vous avez obtenu les résultats dont vous avez besoin, vous pouvez utiliser RegEx pour analyser le jeu de résultats (ou de préférence seulement un sous-ensemble pour l'accélérer, bien que je n'aie pas encore trouvé un bon moyen de le faire). Pour cela, j'utilise simplement deux boucles while et un tas de tables et de variables temporaires :

declare @FinalResults table 
while (select COUNT(*) from @PrelimResults) > 0
begin
    select top 1 @CurrID = [UID], @Text = Text from @PrelimResults
    declare @TextLength int = LEN(@Text )
    declare @IndexOfDot int = CHARINDEX('.', REVERSE(@Text ), @TextLength - dbo.RegExIndexOf(@Text, '\b' + @FirstSearchWord + '\b') + 1)
    set @Text = SUBSTRING(@Text, case @IndexOfDot when 0 then 0 else @TextLength - @IndexOfDot + 3 end, 300)

    while (select COUNT(*) from @TempSearchWords) > 0
    begin
        select top 1 @CurrWord = Word from @TempSearchWords
        set @Text = dbo.RegExReplace(@Text, '\b' + @CurrWord + '\b',  '<b>' + SUBSTRING(@Text, dbo.RegExIndexOf(@Text, '\b' + @CurrWord + '\b'), LEN(@CurrWord) + 1) + '</b>')
        delete from @TempSearchWords where Word = @CurrWord
    end

    insert into @FinalResults
    select * from @PrelimResults where [UID] = @CurrID
    delete from @PrelimResults where [UID] = @CurrID
end

Plusieurs remarques :
1. Les boucles while imbriquées ne sont probablement pas le moyen le plus efficace de le faire, mais rien d'autre ne vient à l'esprit. Si je devais utiliser des curseurs, ce serait essentiellement la même chose ?
2. @FirstSearchWord ici fait référence à la première instance dans le texte de l'un des mots de recherche d'origine, donc essentiellement le texte que vous remplacez ne figurera que dans le résumé. Encore une fois, c'est une méthode assez basique, une sorte d'algorithme de recherche de cluster de texte serait probablement utile.
3. Pour obtenir RegEx en premier lieu, vous avez besoin de fonctions CLR définies par l'utilisateur.