Sqlserver
 sql >> Database >  >> RDS >> Sqlserver

Come eseguire l'evidenziazione dei risultati da una query full-text di SQL Server

Espandendo l'idea di Ismaele, non è la soluzione finale, ma penso che sia un buon modo per iniziare.

Per prima cosa dobbiamo ottenere l'elenco delle parole che sono state recuperate con il motore full-text:

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'

C'è già molto su cui si può espandere, ad esempio il modello di ricerca è piuttosto semplice; inoltre ci sono probabilmente modi migliori per filtrare le parole che non ti servono, ma almeno ti dà un elenco di parole staminali ecc. che sarebbero abbinate alla ricerca full-text.

Dopo aver ottenuto i risultati di cui hai bisogno, puoi utilizzare RegEx per analizzare il set di risultati (o preferibilmente solo un sottoinsieme per accelerarlo, anche se non ho ancora trovato un buon modo per farlo). Per questo uso semplicemente due cicli while e un mucchio di tabelle e variabili temporanee:

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

Diverse note:
1. I loop nidificati probabilmente non sono il modo più efficiente per farlo, tuttavia non viene in mente nient'altro. Se dovessi usare i cursori, sarebbe essenzialmente la stessa cosa?
2. @FirstSearchWord qui a si riferisce alla prima istanza nel testo di una delle parole di ricerca originali, quindi essenzialmente il testo che stai sostituendo sarà solo nel riepilogo. Ancora una volta, è un metodo piuttosto semplice, una sorta di algoritmo di ricerca di cluster di testo sarebbe probabilmente utile.
3. Per ottenere RegEx in primo luogo, sono necessarie le funzioni CLR definite dall'utente.