如何突出显示SQL Server全文查询的结果

时间:2020-03-05 18:55:04  来源:igfitidea点击:

我们有一个使用SQL Server 2008作为数据库的Web应用程序。我们的用户能够对数据库中的特定列进行全文搜索。 SQL Server的全文功能似乎不提供对突出显示突出显示的支持。我们是否需要自己构建它,或者周围是否有一些图书馆或者有关如何做到这一点的知识?

顺便说一句,该应用程序是用Cso编写的。.Net解决方案将是理想的选择,但不是必需的,因为我们可以翻译。

解决方案

回答

我们可能在此实例中缺少数据库的要点。它的工作是将满足我们条件的数据返回给我们。我认为我们可能希望在Web控件中使用正则表达式来实现突出显示。

快速搜索会发现以下内容。

http://www.dotnetjunkies.com/PrintContent.aspx?type=article&id=195E323C-78F3-4884-A5AA-3A1081AC3B35

回答

一些细节:

search_kiemeles=replace(lcase(search),"""","")
            do while not rs.eof  'The search result loop
                hirdetes=rs("hirdetes")
                data=RegExpValueA("([A-Za-z?üó?úéá?í?üó?úéá?í0-9]+)",search_kiemeles)   'Give back all the search words in an array, I need non-english characters also
                For i=0 to Ubound(data,1)
                    hirdetes = RegExpReplace(hirdetes,"("&NoAccentRE(data(i))&")","<em></em>")
                Next
                response.write hirdetes
                rs.movenext
            Loop
            ...

功能

'All Match to Array
Function RegExpValueA(patrn, strng)
    Dim regEx
    Set regEx = New RegExp   ' Create a regular expression.
    regEx.IgnoreCase = True   ' Set case insensitivity.
    regEx.Global = True
    Dim Match, Matches, RetStr
    Dim data()
    Dim count
    count = 0
    Redim data(-1)  'VBSCript Ubound array bug workaround
    if isnull(strng) or strng="" then
        RegExpValueA = data
        exit function
    end if
    regEx.Pattern = patrn   ' Set pattern.
    Set Matches = regEx.Execute(strng)   ' Execute search.
    For Each Match in Matches   ' Iterate Matches collection.
        count = count + 1
        Redim Preserve data(count-1)
      data(count-1) = Match.Value
    Next
    set regEx = nothing
    RegExpValueA = data
End Function

'Replace non-english chars
Function NoAccentRE(accent_string)
    NoAccentRE=accent_string
    NoAccentRE=Replace(NoAccentRE,"a","§")
    NoAccentRE=Replace(NoAccentRE,"á","§")
    NoAccentRE=Replace(NoAccentRE,"§","[aá]")
    NoAccentRE=Replace(NoAccentRE,"e","§")
    NoAccentRE=Replace(NoAccentRE,"é","§")
    NoAccentRE=Replace(NoAccentRE,"§","[eé]")
    NoAccentRE=Replace(NoAccentRE,"i","§")
    NoAccentRE=Replace(NoAccentRE,"í","§")
    NoAccentRE=Replace(NoAccentRE,"§","[ií]")
    NoAccentRE=Replace(NoAccentRE,"o","§")
    NoAccentRE=Replace(NoAccentRE,"ó","§")
    NoAccentRE=Replace(NoAccentRE,"?","§")
    NoAccentRE=Replace(NoAccentRE,"?","§")
    NoAccentRE=Replace(NoAccentRE,"§","[oó??]")
    NoAccentRE=Replace(NoAccentRE,"u","§")
    NoAccentRE=Replace(NoAccentRE,"ú","§")
    NoAccentRE=Replace(NoAccentRE,"ü","§")
    NoAccentRE=Replace(NoAccentRE,"?","§")
    NoAccentRE=Replace(NoAccentRE,"§","[uúü?]")
end function

回答

看起来我们可以解析新的SQL Server 2008存储过程sys.dm_fts_parser的输出并使用regex,但我并没有对其进行仔细研究。

回答

扩展Ishmael的想法,这不是最终的解决方案,但我认为这是一个很好的起点。

首先,我们需要获取使用全文本引擎检索到的单词的列表:

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'

已经有很多可以扩展的内容,例如搜索模式是非常基本的。也可能有更好的方法来过滤掉不需要的单词,但至少它会为我们提供词干列表等,这些词可与全文搜索匹配。

获得所需的结果后,我们可以使用RegEx解析结果集(或者最好只是一个子集来加速结果集,尽管我还没有找到一种好的方法)。为此,我仅使用两个while循环和一堆临时表和变量:

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

几点注意事项:
1.嵌套的while循环可能不是最有效的方法,但是没想到。如果我要使用游标,那基本上是同一回事吗?
2.这里的@FirstSearchWord指的是原始搜索词之一的文本中的第一个实例,因此,实际上,我们要替换的文本只会出现在摘要中。同样,这是一个非常基本的方法,某种文本簇查找算法可能会派上用场。
3.首先要获得RegEx,我们需要CLR用户定义的函数。