Sql-Server
SQL Server 全文搜尋 - .rtf 文件被 rtf 標籤錯誤地索引
varbinary(max)
我已經在我的 SQL Server DB 的列上設置了全文索引。我指定了一個類型列,其中包含文件的副檔名,例如“.doc”、“.pdf”等。但是,我注意到,當索引任何 .rtf 文件時,SQL 會包含文件中的所有元資訊(例如 RTF 標記“listoverridecount0”)。
這使索引膨脹很多,也意味著搜尋將匹配這些標籤(即我可以搜尋“listoverridecount0”並返回每個.rtf)。
.rtf 的 iFilter 是否有任何理由不會刪除 RTF 標籤?
當我執行這個:
SELECT * FROM sys.fulltext_document_types WHERE document_type = '.rtf';
我明白了:
document_type .rtf class_id C7310720-AC80-11D1-8DF3-00C04FB6EF4F path c:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\Binn\msfte.dll version 12.0.6828.0 manufacturer Microsoft Corporation
我已經送出了Microsoft Connect 錯誤,因為我似乎無法找到任何解決方法。這可能是 a) RTF iFilter 未刪除標籤時出錯,或 b) 全文索引問題。
我的 SQL Server 版本是:
微軟 SQL Server 2012 (SP1) - 11.0.3393.0 (X64) 2013 年 10 月 25 日 19:04:40 版權所有 (c) 微軟公司 Windows NT 6.2(內部版本 9200:)(管理程序)上的開發人員版(64 位)
我可以重現這個,但我認為你有幾個選擇:
- 不要太擔心全文索引膨脹。沒有多少人會搜尋“rtf1”、“pard”或“wmetafile0”,我認為它不會對你的表現產生太大影響。如果有人在搜尋“紅色”或“藍色”,您可能會遇到奇怪的衝突,但我認為這是相當低的風險。
- 清理字元串,例如使用我從這裡複製的 RegEx 。似乎做得很好。將其儲存在一個單獨的表中,其中帶有 stream_id(這是文件的唯一 id)和該表的全文索引:
-- Convert rtf to plain text SELECT CAST( file_stream AS VARCHAR(MAX) ) original , MDS.mdq.RegExReplace( CAST( file_stream AS VARCHAR(MAX) ), '\{\*?\\[^{}]+}|[{}]|\\\n?[A-Za-z]+\n?(?:-?\d+)?[ ]?', '', 1 ) FROM dbo.Documents
- 我從這裡改編的 CLR 函式的類似方法:
using System; using System.Data; using System.Data.SqlClient; using System.Data.SqlTypes; using Microsoft.SqlServer.Server; using System.Text; using System.Linq; // for TakeWhile public partial class UserDefinedFunctions { [Microsoft.SqlServer.Server.SqlFunction] public static SqlChars rtfToText( SqlChars inputRtf ) { // RTF function lifted from here and adapted for SQL CLR: // https://stackoverflow.com/questions/23277178/richtextbox-throws-outofmemory-on-azure bool slash = false; //indicates if backslash followed by the space bool figure_opened = false; //indicates if opening figure brace followed by the space bool figure_closed = false; //indicates if closing brace followed by the space bool first_space = false; //the else spaces are in plain text and must be included to the result if (inputRtf.Length < 4) return new SqlChars ( string.Empty ); int i = 0; i = inputRtf.ToString().IndexOf("\\pard"); if (i < 1) return new SqlChars(string.Empty); var builder = new StringBuilder(); for (int j = i; j < inputRtf.Length - 1; j++) { char ch = inputRtf[j]; char nextCh = inputRtf[j + 1]; if (ch == '\\' && nextCh == 'p') // appends \n if \pard, except for first { if (j > i && j < inputRtf.Length - 4) { string fiveChars = inputRtf.ToString().Substring(j, 5); if (fiveChars.Equals("\\pard")) { builder.Append("\n"); } } } if (ch == '\\' && nextCh == 'u') // to deal correctly with special characters { string fourChars = inputRtf.ToString().Substring(j + 2, 4); string digits = new string(fourChars.TakeWhile(char.IsDigit).ToArray()); char specialChar = (char)int.Parse(digits); builder.Append(specialChar); j += digits.Length + 5; continue; } if (ch == '\\' && nextCh == '{') // if the text contains symbol '{' { slash = false; figure_opened = false; figure_closed = false; first_space = false; builder.Append('{'); j++; continue; } else if (ch == '\\' && nextCh == '}') // if the text contains symbol '}' { slash = false; figure_opened = false; figure_closed = false; first_space = false; builder.Append('}'); j++; continue; } else if (ch == '\\' && nextCh == '\\') // if the text contains symbol '\' { slash = false; figure_opened = false; figure_closed = false; first_space = false; builder.Append('\\'); j++; continue; } else if (ch == '\\') // we are looking at the backslash { first_space = true; slash = true; } else if (ch == '{') { first_space = true; figure_opened = true; } else if (ch == '}') { first_space = true; figure_closed = true; } else if (ch == ' ') { slash = false; figure_opened = false; figure_closed = false; } if (!slash && !figure_opened && !figure_closed) { if (!first_space) { builder.Append(ch); } else { first_space = false; } } } // Return return new SqlChars(builder.ToString()); } };
我確信這不是世界上最高效的 CLR 函式,但它在我測試的大約 100 個文件上做得很好,有一些失敗了。
如果您在連接項目上聽到任何回音,請告訴我們。
我不確定您使用的是什麼版本的 MSSQL,但是這個連結有幫助嗎?SQL 過濾器它查看 SQL Server 中設置的各種過濾器,也許 .rtf 過濾器沒有正確載入?