敏感詞過濾是隨着互聯網社區發展一塊兒發展起來的一種阻止網絡犯罪和網絡暴力的技術手段,經過對可能存在犯罪或網絡暴力可能的關鍵詞進行有針對性的篩查和屏蔽,不少時候咱們可以防患於未然,把後果嚴重的犯罪行爲扼殺於萌芽之中。html
隨着各類社交平臺等的日益火爆,敏感詞過濾逐漸成了很是重要的也是值得重視的功能。那麼在 Serverless 架構下,經過Python 語言,敏感詞過濾又有那些新的實現呢?咱們可否是用最簡單的方法,實現一個敏感詞過濾的API呢?python
若是說敏感詞過濾,其實不如說是文本的替換,以Python爲例,說到詞彙替換,不得不想到replace
,咱們能夠準備一個敏感詞庫,而後經過replace
進行敏感詞替換:git
def worldFilter(keywords, text): for eve in keywords: text = text.replace(eve, "***") return text keywords = ("關鍵詞1", "關鍵詞2", "關鍵詞3") content = "這是一個關鍵詞替換的例子,這裏涉及到了關鍵詞1還有關鍵詞2,最後還會有關鍵詞3。" print(worldFilter(keywords, content))
可是動動腦你們就會發現,這種作法在文本和敏感詞庫很是龐大的前提下,會有很嚴重的性能問題。例如我將代碼進行修改,進行基本的性能測試:github
import time def worldFilter(keywords, text): for eve in keywords: text = text.replace(eve, "***") return text keywords =[ "關鍵詞" + str(i) for i in range(0,10000)] content = "這是一個關鍵詞替換的例子,這裏涉及到了關鍵詞1還有關鍵詞2,最後還會有關鍵詞3。" * 1000 startTime = time.time() worldFilter(keywords, content) print(time.time()-startTime)
此時的輸出結果是:0.12426114082336426
,能夠看到性能很是差。算法
與其用replace
,還不如經過正則表達re.sub
來的更加快速。express
import time import re def worldFilter(keywords, text): return re.sub("|".join(keywords), "***", text) keywords =[ "關鍵詞" + str(i) for i in range(0,10000)] content = "這是一個關鍵詞替換的例子,這裏涉及到了關鍵詞1還有關鍵詞2,最後還會有關鍵詞3。" * 1000 startTime = time.time() worldFilter(keywords, content) print(time.time()-startTime)
咱們一樣增長性能測試,按照上面的方法進行改造測試,輸出結果是0.24773502349853516
。經過這樣的例子,咱們能夠發現,其性能磣韓劇並不大,可是實際上隨着文本量增長,正則表達這種作法在性能層面會變高不少。json
這種方法相對來講效率會更高一些。例如,咱們認爲壞人,壞孩子,壞蛋是敏感詞,則他們的樹關係能夠表達:api
用DFA字典來表示:瀏覽器
{ '壞': { '蛋': { '\x00': 0 }, '人': { '\x00': 0 }, '孩': { '子': { '\x00': 0 } } } }
使用這種樹表示問題最大的好處就是能夠下降檢索次數,提升檢索效率,基本代碼實現:網絡
import time class DFAFilter(object): def __init__(self): self.keyword_chains = {} # 關鍵詞鏈表 self.delimit = '\x00' # 限定 def parse(self, path): with open(path, encoding='utf-8') as f: for keyword in f: chars = str(keyword).strip().lower() # 關鍵詞英文變爲小寫 if not chars: # 若是關鍵詞爲空直接返回 return level = self.keyword_chains for i in range(len(chars)): if chars[i] in level: level = level[chars[i]] else: if not isinstance(level, dict): break for j in range(i, len(chars)): level[chars[j]] = {} last_level, last_char = level, chars[j] level = level[chars[j]] last_level[last_char] = {self.delimit: 0} break if i == len(chars) - 1: level[self.delimit] = 0 def filter(self, message, repl="*"): message = message.lower() ret = [] start = 0 while start < len(message): level = self.keyword_chains step_ins = 0 for char in message[start:]: if char in level: step_ins += 1 if self.delimit not in level[char]: level = level[char] else: ret.append(repl * step_ins) start += step_ins - 1 break else: ret.append(message[start]) break else: ret.append(message[start]) start += 1 return ''.join(ret) gfw = DFAFilter() gfw.parse( "./sensitive_words") content = "這是一個關鍵詞替換的例子,這裏涉及到了關鍵詞1還有關鍵詞2,最後還會有關鍵詞3。" * 1000 startTime = time.time() result = gfw.filter(content) print(time.time()-startTime)
這裏咱們的字典庫是:
with open("./sensitive_words", 'w') as f: f.write("\n".join( [ "關鍵詞" + str(i) for i in range(0,10000)]))
執行結果:
0.06450581550598145
能夠看到性能進一步提高。
接下來,咱們來看一下 AC自動機過濾敏感詞算法:
AC自動機:一個常見的例子就是給出n個單詞,再給出一段包含m個字符的文章,讓你找出有多少個單詞在文章裏出現過。
簡單地講,AC自動機就是字典樹+kmp算法+失配指針
代碼實現:
import time class Node(object): def __init__(self): self.next = {} self.fail = None self.isWord = False self.word = "" class AcAutomation(object): def __init__(self): self.root = Node() # 查找敏感詞函數 def search(self, content): p = self.root result = [] currentposition = 0 while currentposition < len(content): word = content[currentposition] while word in p.next == False and p != self.root: p = p.fail if word in p.next: p = p.next[word] else: p = self.root if p.isWord: result.append(p.word) p = self.root currentposition += 1 return result # 加載敏感詞庫函數 def parse(self, path): with open(path, encoding='utf-8') as f: for keyword in f: temp_root = self.root for char in str(keyword).strip(): if char not in temp_root.next: temp_root.next[char] = Node() temp_root = temp_root.next[char] temp_root.isWord = True temp_root.word = str(keyword).strip() # 敏感詞替換函數 def wordsFilter(self, text): """ :param ah: AC自動機 :param text: 文本 :return: 過濾敏感詞以後的文本 """ result = list(set(self.search(text))) for x in result: m = text.replace(x, '*' * len(x)) text = m return text acAutomation = AcAutomation() acAutomation.parse('./sensitive_words') startTime = time.time() print(acAutomation.wordsFilter("這是一個關鍵詞替換的例子,這裏涉及到了關鍵詞1還有關鍵詞2,最後還會有關鍵詞3。"*1000)) print(time.time()-startTime)
詞庫一樣是:
with open("./sensitive_words", 'w') as f: f.write("\n".join( [ "關鍵詞" + str(i) for i in range(0,10000)]))
使用上面的方法,測試結果爲0.017391204833984375
。
能夠看到這個全部算法中,在上述的基本算法中DFA過濾敏感詞性能最高,可是實際上,對於後二者算法,並無誰必定更好,可能某些時候,AC自動機過濾敏感詞算法會獲得更高的性能,因此在生產生活中,推薦時候用二者,能夠根據本身的具體業務須要來作。
將代碼部署到Serverless架構上,能夠選擇API網關與函數計算進行結合,以AC自動機過濾敏感詞算法爲例:咱們只須要增長是幾行代碼就好,完整代碼以下:
# -*- coding:utf-8 -*- import json, uuid class Node(object): def __init__(self): self.next = {} self.fail = None self.isWord = False self.word = "" class AcAutomation(object): def __init__(self): self.root = Node() # 查找敏感詞函數 def search(self, content): p = self.root result = [] currentposition = 0 while currentposition < len(content): word = content[currentposition] while word in p.next == False and p != self.root: p = p.fail if word in p.next: p = p.next[word] else: p = self.root if p.isWord: result.append(p.word) p = self.root currentposition += 1 return result # 加載敏感詞庫函數 def parse(self, path): with open(path, encoding='utf-8') as f: for keyword in f: temp_root = self.root for char in str(keyword).strip(): if char not in temp_root.next: temp_root.next[char] = Node() temp_root = temp_root.next[char] temp_root.isWord = True temp_root.word = str(keyword).strip() # 敏感詞替換函數 def wordsFilter(self, text): """ :param ah: AC自動機 :param text: 文本 :return: 過濾敏感詞以後的文本 """ result = list(set(self.search(text))) for x in result: m = text.replace(x, '*' * len(x)) text = m return text def response(msg, error=False): return_data = { "uuid": str(uuid.uuid1()), "error": error, "message": msg } print(return_data) return return_data acAutomation = AcAutomation() path = './sensitive_words' acAutomation.parse(path) def main_handler(event, context): try: sourceContent = json.loads(event["body"])["content"] return response({ "sourceContent": sourceContent, "filtedContent": acAutomation.wordsFilter(sourceContent) }) except Exception as e: return response(str(e), True)
最後,爲了方便本地測試,咱們能夠增長:
def test(): event = { "requestContext": { "serviceId": "service-f94sy04v", "path": "/test/{path}", "httpMethod": "POST", "requestId": "c6af9ac6-7b61-11e6-9a41-93e8deadbeef", "identity": { "secretId": "abdcdxxxxxxxsdfs" }, "sourceIp": "14.17.22.34", "stage": "release" }, "headers": { "Accept-Language": "en-US,en,cn", "Accept": "text/html,application/xml,application/json", "Host": "service-3ei3tii4-251000691.ap-guangzhou.apigateway.myqloud.com", "User-Agent": "User Agent String" }, "body": "{\"content\":\"這是一個測試的文本,我也就呵呵了\"}", "pathParameters": { "path": "value" }, "queryStringParameters": { "foo": "bar" }, "headerParameters": { "Refer": "10.0.2.14" }, "stageVariables": { "stage": "release" }, "path": "/test/value", "queryString": { "foo": "bar", "bob": "alice" }, "httpMethod": "POST" } print(main_handler(event, None)) if __name__ == "__main__": test()
完成以後,咱們就能夠測試運行一下,例如個人字典是:
呵呵 測試
執行以後結果:
{'uuid': '9961ae2a-5cfc-11ea-a7c2-acde48001122', 'error': False, 'message': {'sourceContent': '這是一個測試的文本,我也就呵呵了', 'filtedContent': '這是一個**的文本,我也就**了'}}
接下來,咱們將代碼部署到雲端,新建serverless.yaml
:
sensitive_word_filtering: component: "@serverless/tencent-scf" inputs: name: sensitive_word_filtering codeUri: ./ exclude: - .gitignore - .git/** - .serverless - .env handler: index.main_handler runtime: Python3.6 region: ap-beijing description: 敏感詞過濾 memorySize: 64 timeout: 2 events: - apigw: name: serverless parameters: environment: release endpoints: - path: /sensitive_word_filtering description: 敏感詞過濾 method: POST enableCORS: true param: - name: content position: BODY required: 'FALSE' type: string desc: 待過濾的句子
而後經過sls --debug
進行部署,部署結果:
最後,經過PostMan進行測試:
敏感詞過濾是目前很是常見的需求/技術,經過敏感詞過濾,咱們能夠在必定程度上下降惡意言語或者違規言論的出現,在上述實踐過程,有如下兩點內容:
咱們誠邀您來體驗最便捷的 Serverless 開發和部署方式。在試用期內,相關聯的產品及服務均提供免費資源和專業的技術支持,幫助您的業務快速、便捷地實現 Serverless!
3 秒你能作什麼?喝一口水,看一封郵件,仍是 —— 部署一個完整的 Serverless 應用?
複製連接至 PC 瀏覽器訪問:https://serverless.cloud.tencent.com/deploy/express
3 秒極速部署,當即體驗史上最快的 Serverless HTTP 實戰開發!
傳送門:
- GitHub: github.com/serverless
- 官網:serverless.com
歡迎訪問:Serverless 中文網,您能夠在 最佳實踐 裏體驗更多關於 Serverless 應用的開發!