2008-09-16 121 views
8

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

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

+0

http://www.sqlperformance.com/2012/09/t-sql-queries/hit-highlighting-in-full-text-search – 2012-09-25 13:56:25

回答

3

伊斯梅尔的想法不断扩展,这不是最终的解决方案,但我认为这是一个很好的开始。

首先,我们需要获取已经检索与全文引擎的单词列表:

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

1

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

这是一个快速搜索将显示的内容。

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

+3

感谢您的回复。虽然我意识到突出显示不在数据库的范围之内,但也许数据库应该提供命中位置等,而不必依赖于正则表达式等,当你考虑词干,停止词等的影响时,这可能是困难/不准确的。 。 – 2008-09-16 23:32:37

1

一些细节:

  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