【问题标题】:How to do hit-highlighting of results from a SQL Server full-text query如何对 SQL Server 全文查询的结果进行高亮显示
【发布时间】:2010-09-09 07:19:22
【问题描述】:

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

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

【问题讨论】:

标签: sql-server full-text-search highlighting hit-highlighting


【解决方案1】:

在这种情况下,您可能错过了数据库的要点。它的工作是将满足你给它的条件的数据返回给你。我认为您可能希望在 Web 控件中使用正则表达式来实现突出显示。

这里有一些快速搜索会发现的东西。

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

【讨论】:

  • 感谢您的回复。虽然我意识到突出显示超出了数据库的范围,但也许数据库应该提供命中位置等,而不是不得不依赖正则表达式等,当您考虑词干、停用词等的影响时,这可能会很困难/不准确.
【解决方案2】:

一些细节:

            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>$1</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

【讨论】:

    【解决方案3】:

    看起来您可以解析新SQL Server 2008 stored procedure sys.dm_fts_parser 的输出并使用正则表达式,但我没有仔细研究过。

    【讨论】:

    • 您似乎对此很了解,是否有存储过程可以从原始文件内容中提取文本(应用文件类型“过滤器”)?
    【解决方案4】:

    扩展 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用户定义的函数。

    【讨论】:

      猜你喜欢
      • 2023-03-14
      • 1970-01-01
      • 1970-01-01
      • 2019-12-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多