敏感词过滤
Turms不支持且未来也不会支持图片、视频与语音的反垃圾检测功能,下文所有内容仅在文本检测范围内进行说明。
功能特性对比
结合现实情况,商用敏感词过滤功能的最大优点是:词库丰富,更新及时,支持多语言。最主要缺点是:按检测次数收费、每次检测都需要发送网络请求;turms-plugin-antispam的最大优点是:免费、本地极速检测,只需遍历一遍目标串。最主要缺点是:不提供词库。具体而言:
特别一提的是:由于黑产的客观存在,“按检测次数收费”的实际开销可能会比您预期的开销大。
商业反垃圾服务(含敏感词过滤) | turms-plugin-antispam | |
---|---|---|
免费 | 否。按检测次数收费 | 是 |
开源 | 否。完全闭源 | 是。完全开源 |
匹配速度 | 需要发送网络请求,比turms-plugin-antispam的匹配速度慢了几个数量级 | 本地极速匹配(基于双数组Trie的AC自动机算法实现)。您可以忽略匹配时带来的性能开销。 在NORMALIZATION模式下,匹配的时间复杂度为O(n),n为输入字符串长度。 在NORMALIZATION_TRANSLITERATION模式下,音译的时间复杂度为O(n),n为输入字符串长度。匹配音译结果的时间复杂度为O(m),m为音译结果字符串长度。 补充:汉字音译指将汉字转换成拼音 |
文本去噪(如去标点符号、字母与数字标准化) | 部分支持 | 部分支持 |
形近字匹配(如火星文) | 部分支持 | TODO(1.1支持) |
拆字匹配 | 部分支持 | TODO(1.2支持) |
音近字精确匹配 | 支持 | 支持 |
音近字模糊匹配 | 支持 | TODO(1.1支持) |
多音字匹配 | 支持 | TODO(1.1支持) |
词库 | 闭源,但是词库丰富,更新及时 | 不提供。具体原因见下文 |
多语言/方言支持 | 支持多种语言与方言 | 需要用户自行采集词库。另外,也有项目通过调用“翻译API”,将源语言翻译成某特定语言再进行匹配,但turms-plugin-antispam不提供该类实现 |
生僻字支持 | 部分支持 | 部分支持。turms-plugin-antispam能够识别Unicode基本多语言平面(BMP)内的code points,支持识别两万多个汉字(《新华字典》最新版仅收录一万多个汉字)。 由于大部分IM应用都不要求一定要能显示特别生僻的字(如“𤳵”字),建议您的UI前端应用直接用如“?”的占位符对BMP之外的cope points进行替换。 turms-plugin-antispam没有计划支持BMP以外的code points |
组合敏感词 | 支持 | TODO(1.1支持) |
文字竖排检测 | 不支持 | 不支持 |
查询词库附加信息 | 附加信息丰富。如敏感词类别(涉黄、涉政、暴恐、违禁、谩骂、灌水、广告、广告法、涉价值观等) | TODO(1.0)。另外,虽然Turms之后会支持该功能,但Turms依旧不提供敏感词库 |
白名单 | 支持 | TODO(1.1支持) |
地区差异化服务 | 部分支持 | 不支持 |
人工审核系统 | 部分支持 | 不支持 |
敏感词检测的复杂性
并不是什么文本都能检测的。以字符串“Turms是一个优秀的IM开源项目”为例,如果我们采用常规的竖排明文显示。那么如果敏感词检测系统不支持特征提取,那么该系统就无法检测该类文本:
text╔═╤═╤═╤═╤═╗ ║┊│项│的│是│T║ ║┊│目│I│一│u║ ║┊│┊│M│个│r║ ║┊│┊│开│优│m║ ║┊│┊│源│秀│s║ ╚═╧═╧═╧═╧═╝
甚至也可以先用加密算法对消息进行加密后再发送(比如您的应用支持Web端,那黑客甚至可以给您的Web端,写个浏览器插件,让每条消息在发送前都进行加密,在收到时进行解密)。因此敏感词过滤只能提高发出敏感词行为的成本,没法根除发送敏感词这一行为。
大部分系统都不支持检测语义,尤其是正话反说,明褒暗贬。同样一句话,放在不同的上下文,可以有着完全不同的含义。
存在误封。对一些正常词汇又存在着误封,如很多商业服务将“水乳交融”认为是“具有极高可信度的色情词汇”,结果造成了正常用户的流失。补充:为了避免这种误封情况,需要将这些词语录入“白名单”中(turms-plugin-antispam目前暂不提供)。
实现可以非常灵活(turms-plugin-antispam暂无计划提供相关实现)。具体而言包括:根据不同区域的用户提供不同的敏感词过滤服务;相比私聊消息,对群消息实行更为严格检测;有些词具有时效性,在某些时候是敏感词,在某些时候就不是敏感词。
鉴于上述敏感词检测的复杂性,turms-plugin-antispam
所需做的就是:结合边际效应,综合考虑敏感词的广泛度、敏感词的识别难度、识别时所需的系统资源开销。只要求能够识别大多数敏感词与常见伪装方式,不要求能够识别相对少见的伪装形式。
敏感词词库
由于敏感词的特殊性,turms-plugin-antispam不提供敏感词词库,需要用户自行采集。
来源
网络采集、运营采集、逆向工程、相关部门提供、人工举报
作用
为turms-plugin-antispam提供敏感词词库,以进行后续的敏感词检测。除
word
字段以外,其他字段目前暂时对敏感词检测没有实际作用(TODO)为运营人员提供Admin API接口,来查询与全量更新敏感词词库
短期内,我们并没有计划支持从数据库中导入原始数据,以及敏感词词库的运营功能。您需要自行管理敏感词词库,turms-plugin-antispam目前只是作为一个纯粹的数据使用方
格式
turms-plugin-antispam目前支持两种导入词库的格式:1. 原始的CSV格式数据;2. 已经解析好的bin数据。
由于通过解析好的bin数据导入,turms-plugin-antispam就无需进行词库的解析操作,只是单纯地读取文件的字节流数据,因此强烈推荐您通过im.turms.plugin.antispam.ac.AhoCorasickCodec#main
自行将原始的CSV格式数据解析成bin数据,再通过dictParsing.binFilePath
让turms-plugin-antispam直接导入bin数据(TODO:即将支持通过Admin API导入数据)
CSV格式
敏感词,词ID,过滤等级,类别,词源,收录时间,失效时间,生效时间,更新时间,注释
word,id,level,category,source,create_time,disable_time,enable_time,update_time,comment
- 要特别注意导入的文件格式,非常推荐统一采用
UTF-8
编码 ,
与\t
这两种分隔符都会被自动识别,不需要用户手动指定- 上述所有列中,除了
word
列必须存在之外,其他所有列都可以不存在 - 如果在解析到与列格式不符的数据格式,则拒绝继续解析,并抛出异常
考虑到上述列已经可以满足大部分场景,暂不计划支持自定义列
特性。
举例而言:
你好,123,1,打招呼的敬语,网络采集,1970-01-01T00:00:00.000Z,1970-01-01T00:00:00.000Z,1970-01-01T00:00:00.000Z,,汉语中打招呼的敬语常用词语
Hello,,2,,
안녕하세요,,,,,,,,,,,,,,,,,,,,,,,,,,,
こんにちは
配置讲解
配置类:im.turms.plugin.antispam.property.AntiSpamProperties
配置前缀:turms.plugin.antispam
配置项
配置名 | 默认值 | 作用 |
---|---|---|
enabled | true | 是否启动反垃圾功能 |
dictParsing.binFilePath | null | 词库的二进制文件路径。该文件保存了词库文本解析后的数据,用于避免每次服务端启动时都从头解析词库文本。如果用户配置了“textFilePath”与“binFilePath”,则会优先使用“binFilePath” |
dictParsing.textFilePath | null | 词库的文本文件路径 |
dictParsing.textFileCharset | "UTF-8" | 词库编码格式。推荐统一使用“UTF-8”编码 |
dictParsing.skipInvalidCharacter | true | 解析词库文本时,是否自动跳过非法字符。 如果false且在解析过程中遇到非法字符,则会抛出异常 |
dictParsing.extendedWords.enabled | true | 是否需要支持拓展词库功能。如果为true ,则解析并使用词库中的所有数据。如果为false ,则仅仅解析与使用word 字段数据,以大幅度减少内存开销 |
textParsingStrategy | NORMALIZATION_TRANSLITERATION | 词典文本与用户输入文本的解析策略: NORMALIZATION:对输入文本进行标准化。如: ⑩HELLO(你{}好./ -> 10hello你好 NORMALIZATION_TRANSLITERATION:对输入文本进行标准化并音译。如: ⑩HELLO(你{}好./ -> 10hellonihao |
unwantedWordHandleStrategy | REJECT_REQUEST | 非法文本处理策略: REJECT_REQUEST:向客户端返回“MESSAGE_IS_ILLEGAL”错误状态码 MASK_TEXT:替换非法字符,并继续正常处理请求 |
mask | '*' | 当“unwantedWordHandleStrategy”为“MASK_TEXT”时,所采用的掩码 |
maxNumberOfUnwantedWordsToReturn | 0 | 当处理策略为REJECT_REQUEST 且该值大于0时,被检测为非法文本的字符串,将以ASCII0x1E (Record Separator)字符作为分隔符,通过异常的描述字符串来表示。该异常文本最终会被客户端接收 |
textTypes | 所有其他用户可见的文本 | 配置哪些请求的哪些文本字段需要进行检测 |
silentIllegalTextTypes | 空 | 配置当检测到这些请求的这些文本字段包含非法字符时,服务端会“OK”状态码响应客户端,但服务端实际并没有继续处理该请求。 在实际业务场景中,该值除了通常为空外,还通常为 CREATE_MESSAGE_REQUEST_TEXT ,用于静默拒绝发送用户消息 |
Admin API
TODO
不使用其他开源实现的原因
在全球开源圈子内,目前可找到的开源实现的质量都非常之低,主要体现在:代码质量低(高空间复杂度与时间复杂度)、很多匹配功能都不支持、作者不具备工程设计能力,甚至还有收费的半开源IM项目通过遍历词库来进行匹配的。暂未有像turms-plugin-antispam这样的算法与代码质量都优秀的实现,且传统反垃圾方案(不涉及机器学习)的总体实现难度不大,因此Turms选择自研,也为后期众多拓展做足准备。具体而言:
- 会算法的不会工程设计,会工程设计的不会算法。一方面,实现基于双数组Trie的AC自动机算法的难度较高,且Java的数据结构设计的都比较保守,如
String
与StringBuilder
为了保证内部数据与外部数据隔离,很多函数都会涉及内存拷贝工作,能够在算法实现中避开各种Java的“坑”就需要工程师有基本的优化意识。另一方面,Turms里的反垃圾设计与算法实现的逻辑都是统一的,都是为了Turms这个IM项目设计的,为实际IM需求服务的。因此能保证“能想到的功能就能做到,不需要的功能就不需要提供,以免不必要的时间与空间开销”。 - 自研可以根据项目需求,定制算法实现与算法的上下游代码,以保证绝对的高效(把空间复杂度压到O(1),时间复杂度压到O(n),保证遍历一边字符串即可完成敏感词匹配)。举个例子,在AC自动机标准算法实现中,并没有涉及到“跳过某字符进行匹配”的逻辑。那么如果我们想要实现“只检测BMP内的code points”,就需要在把原始char[]传递给标准AC算法实现之前,先自行过滤并拷贝一个新的char[],再传递给AC自动机进行匹配。这频繁的内存拷贝工作无疑是非常低效且不必要的,尤其是“用户文本消息”本身就是所有用户请求中最占内存也是出现最频繁的数据。而采用定制实现的话,我们只需在AC自动机进行匹配时,加一个if判断条件直接跳过该字符即可。既实现简单清晰,又无需开辟新的内存空间,空间效率高。