因應專案需要,先前研究過 Lucene.Net。Lucene.Net 功能強大效能佳,又提供極高客製彈性,但缺點是得自己處理從 PDF、Word/Excel/PowerPoint 檔提取文字、管理索引排程,瑣碎工作不少。最後,我選擇到超市買牛奶而不自己養牛,決定借用 Windows Search 功能實作網站內容全文檢索,建個目錄把檔案放進去(txt、html、pdf、docx、xlsx、pptx 都成),將其納入索引範圍,在 .NET 程式建個 OleDbConnection,就可以下 SELECT ... FROM SYSTEMINDEX WHERE ... 指令完成全文檢索,很簡單吧?

網路上前人的教學文不少,我也樂得乘涼(感謝),但還是多少踩了一些坑,整理筆記如下。

【參考資源】

【基本範例】

private static void TestMSSearch()
{
    using (var cn = new OleDbConnection(
        @"Provider=Search.CollatorDSO;Extended Properties=""Application=Windows"""))
    {
        cn.Open();
        var cmd = cn.CreateCommand();
        cmd.CommandText = @"
SELECT 
System.ItemName,
System.ItemPathDisplay,
System.ItemDate,
System.Search.AutoSummary
FROM SystemIndex 
WHERE SCOPE ='file:C:/WWW/Files' 
AND CONTAINS('關鍵字', 1028)";
        var dr = cmd.ExecuteReader();
        while (dr.Read())
        {
            Console.WriteLine($"{dr[0]}({dr[1]}) @{dr[2]:MM/dd HH:mm}");
            Console.WriteLine($"{dr[3]}");
        }
    }
    Console.Read();
}

【實作眉角】

  1. 當 SQL 語法出錯,會遇到 E_FAIL(0x80004005) 錯誤,它跟存取被拒的系統錯誤代碼很像,不要被混淆了。欄位名稱敲錯還有「資料行不存在。」之類的提示,更嚴重的語法錯誤,如括號引號不對稱、無效的符號指令等,只會出現「發生一或多個錯誤」這種模糊提示,請仔細挑出 SQL 語法的毛病,不要花時間往權限方向偵錯。
  2. Windows Search 雖然可用 SQL 語法查詢,但支援程度有限,不要天真以為各式 T-SQL 語法都能搬來用。建議參考以下文件:
    Querying the Index with Windows Search SQL Syntax (Windows) 可支援的 SQL 語法
    SQL Features Unavailable in Microsoft Windows Search (Windows) 不支援的 SQL 語法
  3. Windows 10 1703 版的 Search Service 有個 Bug,DataReader.Read() 讀完最後一筆會噴出 0x80004005(-2147467259) 錯誤,未修正前的 Workaround 是用 try … catch … 把 DataReader.Read() 包起來,攔截 0x80004005 錯誤碼視為已無資料。
  4. 比對文字有兩個選擇 CONTAINS() 跟 FREETEXT(),以查詢"黑暗"為例,CONTAINS() 要文件出現"黑暗"字彙才算吻合,FREETEXT() 比較寬鬆,有"黑"也有"暗"就算數。
  5. 有時內容明明有關鍵字卻查不到,可能與分詞有關,但 Windows Search Service 不比 Lucene.Net 能任意客製調整,得把它當成傻瓜相機,方便但有極限。
  6. 我在中文版 Windows 10 測試 COTAINS("中文") 成功,移到英文版 Windows 2008 R2 時,發現用 ASP.NET 查不到中文關鍵字,查英文才有結果,直接用 LINQPad 跑同樣程式碼卻正常。最後我的解決方法是在 CONTAINS() 加上 LCID 參數,改成 CONTINS('中文', 1028) 避免語系設定造成影響。(註: 1028-Chinese, Taiwan, 1033-English, United States, 2052-Chinese, China)
  7. System.Search.AutoSummary 欄位是檔案一開始的一段純文字內容,並非出現關鍵字的片段,如果規格要求預覽包含關鍵字的文字內容,必須另外擷取成純文字再找出關鍵字,一切得 DIY。

Comments

Be the first to post a comment

Post a comment