Sql-Server

使用儲存在另一個表中的單詞進行全文搜尋

  • January 4, 2022

有沒有辦法使用儲存在另一個表中的單詞進行全文搜尋?這是我的場景:

  • Table_A 包含使用者在“UserInput”欄位(和其他內容)中輸入的片語。我在這張表上有一個查看 UserInput 的全文索引。
  • Table_B 的一個欄位“Word”包含我想確保我的使用者沒有使用的一堆(超過 1k)單詞。

我試過這個查詢:

Select * 
From Table_A 
 Cross Join Table_B 
Where Contains(UserInput, Word)

但這不起作用。錯誤顯示“‘Word’ 附近的語法不正確”。SSMS 還抱怨說“期待 STRING、TEXT_LEX 或 VARIABLE”。

我還在 WHERE 語句中嘗試了 CHARINDEX 和 LIKE,但這些函式返回誤報,因為它們不查找整個單詞,而是查找字元串中的字元串。

如果全文不起作用,是否有任何其他方法可以幫助從 Table_A.UserInput 中的 Table_B.Word 中辨識整個單詞?

更新:

還嘗試了以下方法:

Declare @AllWords nvarchar(4000) = '';
Select @AllWords = @AllWords + Case When @AllWords = '' Then Word Else ' OR ' + Word End
From Table_B;
Set @AllWords = '''' + @AllWords + '''';
Select *
From Table_A
Where Contains(UserInput, @AllWords);

這似乎帶來了正確的結果,但我沒有辦法知道在 Table_A.UserInput 中找到了哪些單詞。

  1. 重申一下,您目前有一個包含單詞列表的表,您希望確保您的使用者不會使用 Table_A 進行搜尋。
  2. 您已經成功地使用包含您的壞詞列表的 Table_B 查詢 Table_A。
  3. 從第一點到第二點,您的最終目標是您想知道他們是否搜尋了那些壞詞,將返回什麼。什麼壞詞與 Table_A 中記錄的返回相關。

要解決第 3 點,您需要做的是 query sys.dm_fts_parser。Jefferson Elias 在 SQL Shack 上有一個很好的例子。我將發布相關位,以防它稍後被網際網路刪除或破壞:

如何檢查全文解析的結果

有兩種方法可以檢查全文功能如何根據文本的來源解析給定的文本。

文本的來源是一個字元串

如果您想快速檢查特定字元串的關鍵字,您可能需要使用 sys.dm_fts_parser 內置函式。

這是呼叫該函式的範例。

第一個參數是必須解析的字元串。第二個參數是語言標識符。在這裡,它設置為 0,這意味著它是中性的。hhird 參數是停止列表的標識符。這裡沒有使用停止列表。最後一個參數告訴這個函式是否對重音敏感。在這裡,我們要求不敏感。換句話說,此函式將獲取您在創建全文索引時提供的資訊。

select * from sys.dm_fts_parser(
   '" dsolkjfdskljfsd dfsd-MMM-236.127 dojfdslfkjds"',
   0,
   NULL,
   0
) ;

如果已使用全文索引創建表,我們將使用另一個名為 sys.dm_fts_index_keywords 的動態管理函式 (DMF),它以參數為參數:

它應該在其中查看的數據庫標識符 該數據庫中的對象標識符 它返回一個數據集,其中包含關鍵字的十六進製表示、其在純文字中的對應形式、找到關鍵字的列的標識符,最後是可以找到此關鍵字的文件數。

您將在下面找到一個 T-SQL 查詢,以取回我們的 dbo.DM_OBJECT_FILE 表中的全文功能找到的關鍵字,以及它的結果集。

select * 
From sys.dm_fts_index_keywords(DB_ID(),OBJECT_ID('dbo.DM_OBJECT_FILE'))

此方法應根據您的條件向您顯示將返回的內容。為了幫助解決第 1 點,您可能需要查看停用詞、停用詞列表和敘詞表功能,以幫助將 Table_B 中的單詞更改為可用單詞。或者,您可能需要實施觸發器以防止搜尋術語。

我想這段程式碼會起作用:

Declare @AllWords nvarchar(4000) = '';
Select @AllWords = @AllWords + Case When @AllWords = '' Then Word Else ' OR ' + Word End
From Table_B;
Set @AllWords = '''' + @AllWords + '''';
select * from sys.dm_fts_parser(
   @AllWords,
   0,
   NULL,
   0
) ;

@Shaulinator 的答案並不完全是我想要的,但他指出我認為動態管理視圖和功能(DMV、DMF)可以幫助解決我的問題。謝謝@Shaulinator。

在我的解決方案中,我將使用名為

sys.dm_fts_index_keywords_by_document

微軟的文件:https ://docs.microsoft.com/en-us/sql/relational-databases/system-dynamic-management-views/sys-dm-fts-index-keywords-by-document-transact-sql

總之,該函式提供了全文搜尋索引找到的所有關鍵字(去除了噪音/停用詞)的列表,並且還指向包含該關鍵字的行。

建議的解決方案:

-- Table_A stores input from users and it has a full-text search inde x on UserInput
-- Table_A(ID, UserInput)
-- Table_B stores the words that users should not be using
-- Table_B(Word)

-- This query will return the entries in Table_A that contain words that should not be used
-- and what was the word that should not be used.
Select ID, UserInput, Word
From sys.dm_fts_index_keywords_by_document(DB_ID(), OBJECT_ID('Table_A')) As X
  Inner Join Table_B On X.display_term = Table_B.Word
  Inner Join Table_A On X.document_id = Table_A.ID

一個忠告,這個查詢的性能不是那麼好。在我的場景中 Table_A 有 50K 行,sys.dm_fts_index_keywords_by_document 函式的結果返回 300K 行,Table_B 有 1035 行。

該查詢返回 11 行,平均需要 1.8 秒才能完成。如何改進這一點將因您的環境而異,這絕對是一個不同問題的主題。

引用自:https://dba.stackexchange.com/questions/198835