Как сделать выделение результатов из полнотекстового запроса SQL Server
-
09-06-2019 - |
Вопрос
У нас есть веб-приложение, которое использует SQL Server 2008 в качестве базы данных.Наши пользователи могут выполнять полнотекстовый поиск по определенным столбцам в базе данных.Полнотекстовая функциональность SQL Server, похоже, не обеспечивает поддержку выделения совпадений.Нужно ли нам создавать это самим или, возможно, есть какая-то библиотека или знания о том, как это сделать?
Кстати, приложение написано на C #, поэтому a.Сетевое решение было бы идеальным, но не обязательным, поскольку мы могли бы перевести.
Решение
Развивая идею Ишмаэля, скажу, что это не окончательное решение, но я думаю, что это хороший способ начать.
Во-первых, нам нужно получить список слов, которые были извлечены с помощью полнотекстового движка:
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
здесь to относится к первому экземпляру в тексте одного из исходных поисковых слов, поэтому, по сути, текст, который вы заменяете, будет только в резюме.Опять же, это довольно простой метод, вероятно, был бы удобен какой-нибудь алгоритм поиска текстовых кластеров.
3.Чтобы получить регулярное выражение в первую очередь, вам нужны пользовательские функции CLR.
Другие советы
Похоже, вы могли бы проанализировать выходные данные нового Хранимая процедура SQL Server 2008 sys.dm_fts_parser и используйте регулярное выражение, но я не рассматривал его слишком внимательно.
Возможно, вы упускаете суть базы данных в этом экземпляре.Его задача состоит в том, чтобы возвращать вам данные, которые удовлетворяют условиям, которые вы им предоставили.Я думаю, вы захотите реализовать выделение, вероятно, используя регулярное выражение в вашем веб-элементе управления.
Вот что может показать быстрый поиск.
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>$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