vivo 敏感詞匹配系統的設計與實踐

vivo網際網路技術發表於2021-12-06

一、前言

諦聽系統是vivo的內容稽核平臺,保障了vivo各網際網路產品持續健康的發展。諦聽支援稽核多種內容型別,但日常主要稽核的內容是文字,下圖是一個完整的文字稽核流程,包括名單匹配、敏感詞匹配、AI機器稽核、人工稽核四個環節。待稽核文字需要順次通過名單匹配、敏感詞匹配、AI機器稽核三個流程,若結果為嫌疑則需要人工稽核,否則將直接給出確定的結果。

敏感詞匹配功能可以迅速地匹配文字中的敏感詞彙,演算法平均耗時為50ms,因其簡單、快速、直接、靈活的特點,成為了稽核人員對抗垃圾文字的利器。然而身處資訊爆炸時代的網民們非常“優秀”,他們源源不斷的發明各種新詞、諧音詞來繞過敏感詞檢測。例如某些使用者會使用“啋票”、“採漂”等詞彙來規避敏感詞“彩票”,其中“啋票”不僅是諧音詞,還包含多音字,常規的模式匹配演算法很難保證完全命中。這不僅給運營規則帶來挑戰,也對匹配演算法的精準度、漏殺率提出了要求。

本文將從演算法選型入手,結合兩個實際場景來介紹諦聽系統的敏感詞匹配演算法。其中第二節介紹了底層演算法選型思路,第三節介紹了兩種實際場景下提升敏感詞精準度、降低漏殺率的方案。

二、演算法選型

敏感詞匹配功能依託於模式匹配演算法。模式匹配的定義是,給定一個子串,在某個字串中找出與該子串相同的所有子串。其中給定的子串被稱為模式串,被匹配的字串被稱為目標串。基於多個模式串進行匹配的演算法被稱為多模式匹配演算法,目前成熟的多模式匹配演算法有AC自動機和WM。

2.1 多模式匹配演算法對比

諦聽的敏感詞匹配業務有如下特點:

1)詞庫量大,需要維護和載入百萬級別的詞庫(模式串);

2)敏感詞與業務特性、國家政策相關性強,無法統一約定長度、字首等特徵。

WM演算法對模式串的長度和字首存在一定的要求,可能會影響業務的使用。雖然AC自動機載入耗時長,記憶體佔用大,但敏感詞載入並不頻繁,且伺服器記憶體資源充足,所以我們最終選用AC自動機作為底層演算法。

2.2 AC自動機演算法介紹

AC自動機演算法(Aho–Corasick演算法)是一種字串搜尋演算法,可以同時將目標串與所有模式串進行匹配,演算法均攤情況下具有近似於線性的時間複雜度。AC自動機的匹配原理有兩個核心概念:Trie字典樹Fail指標。下面以模式串集合{“she”, “he”, “shers”, “his”, “era”}為例,來介紹這兩個概念。

AC自動機演算法啟動時,需要將所有的模式串載入到記憶體中,構建成一個Trie字典樹。例如下圖是以模式串集合{“she”, “he”, “shers”, “his”, “era”}構建的字典樹,樹中每個節點代表一個字元,從根節點到某一個節點的路徑,即可表示一個模式串,且紅色節點表示一個字串的終結,例如圖中最右邊子樹上的三個節點,可代表模式串“era”。從字典樹的根節點出發,可以快速的查詢到某個模式串。此外,擁有相同字首的模式串會合併到同一個子樹中,例如中間子樹表示模式串“he”、 “his”,這兩個字串分別是“h”節點的一個分支。AC自動機在搜尋這類字串時,可以節省匹配的次數。

AC自動機在Trie樹的基礎上,為每個節點加入了Fail指標,上圖使用虛線畫出了部分節點的Fail指標,未畫出虛線的節點,其Fail指標指向根節點。演算法在某個節點匹配失敗時,可以通過該指標轉移到其他包含相同字首的分支上繼續匹配。例如匹配目標串“shis”時,對於前兩個字元“sh”,Trie字典樹匹配到左邊字數的“h”節點上,由於該節點的子節點是字元“e”,與目標串的下一個字元“i”不匹配,因此演算法通過Fail指標轉移到中間子樹的“h”節點上繼續匹配,最終命中字串“his”。

上述的Trie字典樹與Fail指標組成了AC自動機的資料模型。AC自動機匹配目標串時,會按順序從目標串中取出字元,從Trie字典樹的根節點出發,在子結點中尋找與該字元匹配的結點,若能找到,則轉移到該節點,若找不到,則轉移到Fail指標指向的節點。當狀態轉移到圖中的紅色節點時,就是命中了一個模式串。下圖展示了AC自動機對目標串“merashisnx”進行匹配的過程。

三、諦聽系統實踐

諦聽系統基於AC自動機演算法構建了一套敏感詞匹配服務,將敏感詞作為模式串,文字內容作為目標串,可以實現常用的中、英文敏感詞匹配。但是實際的業務有很多細分的場景,普通的AC自動機演算法已不能滿足業務使用需求,因此我們探索了組合敏感詞匹配和拼音敏感詞匹配兩種匹配方式,下面分別介紹。

3.1 組合敏感詞

常規的敏感詞匹配演算法通常匹配單個詞或者短句,但某些詞單獨出現時並不違規,只有在與幾個特定的詞同時出現時,才能判定為違規。例如“澳門”、“博彩”、“網站”,這幾個詞,單獨出現都是沒問題的,但是在這句話中:“歡迎登入澳門XX博彩官方網站”,就是違規的賭博廣告。針對這樣的場景,我們實現了“組合敏感詞”匹配方案,運營人員可以將這幾個詞配置成一個組合“澳門+博彩+網站”,只有這三個詞同時出現時,敏感詞服務才會判定這個組合命中。

組合敏感詞的匹配演算法依然基於AC自動機演算法。由於AC自動機只能判斷單個詞的命中情況,因此我們將組合敏感詞分割成單個敏感詞,並維護各敏感詞與組合間的對映關係,在AC自動機演算法執行結束後,只有某個組合對應的敏感詞全部命中時,才能判斷該組合敏感詞命中。為此我們需要給AC自動機新增一些前置和後置的處理步驟,具體步驟如下:

  • 將組合敏感詞分割為單個敏感詞,並記錄敏感詞與組合的對映關係;
  • 將分割後的組合敏感詞新增到AC自動機的Tire樹中;
  • 執行AC自動機,匹配文字;
  • 遍歷匹配結果,將匹配的結果根據對映關係對映到相應的組合上;
  • 記錄組合的命中情況,得到最終匹配結果。

假設目前存在組合敏感詞“澳門+博彩+網站”、“博彩+廣告”、“華人圈+賭博”、“賭博+廣告”,以及普通敏感詞“暴政”,則在步驟1中,我們將組合敏感詞分割為單個敏感詞:“澳門”、“網站”、“博彩”、“廣告”、“賭博”、“華人圈”、“暴政”,並建立圖中所示的對映關係。將這些詞新增到AC自動機後,對文字“歡迎登入澳門XX博彩官方網站”進行匹配時,會命中單個敏感詞“澳門”、“網站”、“博彩”。在步驟4中,演算法將匹配的詞對映到組合中,並標記對應的詞命中。例如根據“博彩”,可取到組合“澳門+博彩+網站”、“博彩+廣告”,則分別標記這兩個組合中的“博彩”已命中。步驟5會根據各組合中單詞的命中情況,來判斷該組合是否命中,由於在步驟4中組合敏感詞“澳門+博彩+網站”的三個詞均被標記為命中,因此可判斷該組合命中。

3.2 拼音敏感詞

在評論、彈幕等創作自由度很高的場景中,某些使用者為了規避機器稽核,會使用一些多音字、同音字來表達敏感詞彙,例如用“啋票”來代表“彩票”等。由於多音字、同音字變化較多,將一個詞的所有諧音詞都窮舉出來是很困難的。因此我們實現了拼音敏感詞的匹配方案,將中文文字轉換為拼音再匹配,通過讀音匹配敏感詞,即可保證命中所有的同音字,運營直接配置敏感詞的拼音,例如“CAI PIAO”,即可命中“啋票”、“彩票”、“採漂”等詞彙。

3.2.1 匹配流程

常規的AC自動機演算法是逐字元匹配的,因此Trie樹上每個節點儲存一個字元,但拼音敏感詞需要按照音節匹配,因此我們將Trie樹的節點資料型別由char改為String,示例:

拼音敏感詞的匹配關鍵在於將漢字準確的轉換為拼音,這一點在多音字的場景下尤為重要。由於多音字的讀音是受語境影響的,現有的技術條件很難確保能將多音字準確的轉換為拼音,而上文提到同音詞“啋票”是使用者自行造的詞,演算法無法準確的識別語境,可能轉換得到“CAI PIAO”、“XIAO PIAO”兩種不同的結果。如果拼音轉換不精準,則拼音敏感詞也無法準確命中。

因此我們不依賴演算法識別多音字的讀音,而是將文字內容的所有讀音都列出來匹配一遍,就可以避免避免拼音轉換不精準的問題。

下圖展示了文字內容與拼音的對應關係,由於存在多音字,因此儲存拼音的陣列從一維擴充套件到了二維,更像是“圖”的資料結構,下文將其稱為拼音圖。拼音圖的起始節點和終止節點之間存在多條路徑,這些路徑對應了多音字的所有排列組合情況,為了避免漏殺,我們需要使用AC自動機將這些路徑都匹配一遍。

從第二節的匹配流程可以看出,目標串是一維陣列,因此AC自動機在匹配文字時,通常採用順序遍歷的方式。而在拼音敏感詞中,由於目標串採用二維陣列儲存,是一種類似於“圖”的資料結構,不再適合使用順序遍歷的方式,因此需要採用圖的遍歷演算法。

圖的遍歷演算法中,最常用的就是深度優先遍歷(DFS)和廣度優先遍歷(BFS)。由於詞語是前後關聯的,為了使演算法更符合人類思考習慣,我們選擇了DFS。DFS演算法使用棧儲存節點資訊,在當前分支遍歷完成後,通過棧中的資訊回溯到上一個分支處繼續遍歷。由於Trie樹的狀態位與拼音圖的節點是相關的,在DFS回溯時,Trie樹也需要同步回溯,因此需要將Trie樹狀態位與拼音圖的節點資訊一起儲存到DFS棧中。下圖展示了拼音敏感詞的匹配流程。

3.2.2 終止條件與剪枝策略

DFS的終止條件是當所有節點都被遍歷過,且演算法會確保每個節點只會被遍歷一次。但是DFS遍歷時會在分支處回溯,所以往往終止的節點並不是待匹配文字的終點,很有可能AC自動機的匹配並未完成。

例如在下圖所示的匹配流程中,左圖是基於待匹配文字“朱朝陽和朋友”構建的拼音圖,右圖是基於拼音敏感詞“PENG YOU”、“ZHAO YANG”、“NI MA”、“MA DE”構建的Trie樹。左圖的拼音圖採用DFS演算法遍歷,演算法最後訪問的節點是藍色節點“ZHAO”,此時拼音圖中所有節點均被遍歷了一次,已經達到了DFS的終止條件。但右圖中Trie樹上的狀態位處於藍色節點“ZHAO”的位置,並沒有達到終止狀態,若此時停止匹配,則會導致無法命中敏感詞“ZHAO YANG”,故演算法應繼續執行,直到AC自動機匹配失敗為止。

因此合適的終止條件是:拼音圖所有節點均被遍歷 且 AC自動機匹配失敗

由於演算法需要結合DFS和AC自動機的狀態來判斷終止條件,因此會出現拼音圖中一個節點和路徑被遍歷多次的情況,當待匹配文字中多音字數量增多時,DFS遍歷的路徑數量會以笛卡爾積的形式增加。而這些路徑中會存在一部分重複的情況,因此在遍歷的過程中需要採取合適的剪枝策略,避免搜尋一些重複的路徑。例如下面左圖所示的遍歷情況,路徑②上“PENG”、“ YOU”兩個節點已被路徑①遍歷過,且對應的AC自動機狀態位(參考右圖)字首並不包含當前遍歷節點“HU”,所以“PENG”對應的敏感詞與路徑②無關,不必再搜尋一次。我們可以針對這種場景設計了剪枝策略,需要剪枝的路徑需要滿足兩個條件:

1)首先當前節點的下一節點已被遍歷過;

2)下一節點對應的AC自動機狀態與當前節點無關。

我們為拼音圖中的每個節點標記一個分支路徑長度B,表示當前節點與上一個最近的分支節點間的路徑長度,例如節點“PENG”對應的分支路徑長度為B = 2(從“HU”到“PENG”),節點“YOU”的分支路徑長度為B = 3(“HU”、PENG”、“YOU”)。在AC自動機的狀態機中,記錄Trie樹上每個節點的深度D。例如狀態機中“PENG”節點的深度D=1,“YOU”節點的深度D=2。從Trie樹根節點到某一個節點的路徑上經過的字元連線起來,為該節點對應的模式串,因此節點的深度D即為模式串的長度。當D < B時,表明當前正在匹配的模式串長度短於拼音圖中當前節點的分支路徑長度,所以當前的模式串與當前的路徑無關。

總結一下,剪枝所需的條件為:

1)拼音圖中下一節點已被遍歷;

2)拼音圖的分支路徑長度B > Trie樹節點的深度D。

四、總結與展望

諦聽系統基於AC自動機實現了普通敏感詞、組合敏感詞、拼音敏感詞的匹配,其中組合敏感詞和拼音敏感詞還可以結合成為拼音組合敏感詞,覆蓋了大部分的文字稽核場景,減輕了機審、人審的壓力。另外,在政策風向發生變化時,敏感詞匹配功能為運營同事提供了一種快速變更稽核策略的手段,使諦聽的文字稽核能力更加靈活。目前諦聽線上已經配置了數量超過100萬的敏感詞,極大程度的保障了公司的內容安全。

未來我們將結合業務使用場景繼續優化敏感詞匹配的能力,提升精準度和命中率。一方面我們可以採用某種方式實現“非”的邏輯,這樣可以在配置敏感詞時排除bad case,提升命中的精準度。另一方面,我們可以實現敏感詞的模糊命中,提升敏感詞的命中率。

作者:vivo網際網路伺服器團隊-Liang Kangwu

相關文章