كيفية القيام بتمييز النتائج من استعلام النص الكامل لـ SQL Server
-
09-06-2019 - |
سؤال
لدينا تطبيق ويب يستخدم SQL Server 2008 كقاعدة بيانات.يستطيع مستخدمونا إجراء عمليات بحث عن النص الكامل في أعمدة معينة في قاعدة البيانات.لا يبدو أن وظيفة النص الكامل لـ SQL Server توفر دعمًا لتمييز النتائج.هل نحتاج إلى بناء هذا بأنفسنا أم أنه ربما توجد مكتبة أو معرفة حول كيفية القيام بذلك؟
راجع للشغل، التطبيق مكتوب بلغة C#، لذا سيكون حل .Net مثاليًا ولكنه ليس ضروريًا حيث يمكننا ترجمته.
المحلول
التوسع في فكرة إسماعيل، ليس الحل النهائي، ولكن أعتقد أنها طريقة جيدة للبدء.
نحتاج أولاً إلى الحصول على قائمة الكلمات التي تم استرجاعها باستخدام محرك النص الكامل:
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 لتحليل مجموعة النتائج (أو يفضل مجموعة فرعية فقط لتسريعها، على الرغم من أنني لم أكتشف بعد طريقة جيدة للقيام بذلك).لهذا أستخدم ببساطة حلقتين من الوقت ومجموعة من الجداول والمتغيرات المؤقتة:
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.ربما لا تكون الحلقات المتداخلة هي الطريقة الأكثر فعالية للقيام بذلك، ولكن لا شيء آخر يتبادر إلى الذهن.إذا كنت سأستخدم المؤشرات، فهل سيكون نفس الشيء في الأساس؟
2. @FirstSearchWord
هنا يشير إلى المثال الأول في نص إحدى كلمات البحث الأصلية، لذا فإن النص الذي تستبدله سيكون موجودًا في الملخص فقط.مرة أخرى، إنها طريقة أساسية تمامًا، ومن المحتمل أن يكون هناك نوع من خوارزمية العثور على مجموعة نصية مفيدة.
3.للحصول على RegEx في المقام الأول، تحتاج إلى وظائف CLR المعرفة من قبل المستخدم.
نصائح أخرى
يبدو أنه يمكنك تحليل إخراج الجديد الإجراء المخزن لـ SQL Server 2008 sys.dm_fts_parser واستخدم التعبير العادي، لكنني لم أنظر إليه عن كثب.
ربما تفتقد نقطة قاعدة البيانات في هذه الحالة.وظيفتها هي إعادة البيانات إليك التي تفي بالشروط التي قدمتها لها.أعتقد أنك سوف ترغب في تنفيذ التمييز على الأرجح باستخدام regex في عنصر التحكم في الويب الخاص بك.
وهنا شيء سيكشفه البحث السريع.
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