敏感词过滤,一个很经典的需求场景,目前我要对一个每天上千万消息的聊天系统做敏感词过滤优化,之前的解决方案是,每次从redis中取出敏感词集合,然后做遍历操作,使用indexOf查看是否出现在聊天消息中,鉴于消息的高频转发,所以每次从redis中读取敏感词库方案已经不太适用该场景,经过调研和请教有以下两个解决方案可够参考: 1、将redis中的敏感词库在服务启动时,加载到内存中,后续逻辑不变; 2、同样将敏感词库读到内存,不同之处在于使用bloom-filter算法,将敏感词打散到内存位数组中,每次将消息放进去看是否匹配到; 优劣分析:方案一可以节约redis读取的耗时,提高每次的处理效率,但是鉴于node单个进程珍贵的1.4G内存,如果敏感词库很大的情况下,不太适用;方案2在方案1的基础上,不仅提高了处理效率,同时大大减少了内存消耗,但缺点很明显,如果聊天消息中包含敏感词之外其他的内容,将对结果造成很大程度的误判; 综上,目前我比较偏向于方案2,如果有更好的方案,请大家积极分享;毕竟作为一个经典需求场景应该会有很多人遇到,希望能够帮助到大家;
======更新线====== 性能测试环境:敏感词组已存在内存中,并且不考虑初始化树 和 bloom-filter初始化的耗时,敏感词库包含1000多个敏感词; DFA算法:单个词耗时1ms左右; indexOf算法:单个词耗时1ms左右(曾经出现过一次40ms) bloom-filter算法:单个词耗时0.5ms左右(三个hash函数,千分之一的错误百分比) BTW:容错率是指,检索1000次允许出现误判的概率,容错率约小(苛刻)耗时越高、结果越准确;同时该算法不会少判,只会多判;
看到敏感词又滚进来 1.敏感词库比较大而且不希望误伤的话,还是放到搜索引擎比较好,引擎的分词可以降低被误伤的概率,比如什么 江阴毛纺厂 一类的 2.indexOf的方法效率实在太感人了,请用 DFA或者 Trie树做 3.附上我自己做的简易过滤器 text-censor ,代码不多,DFA,可以简单试试
@aojiaotage 首先,还是非常感谢你能回复的,刚翻到两年前你回复的一个关于敏感词的话题,已经看到了这个模块,正在做性能对比,虽说知道indexOf感人的效率,还是不死心的自己压了一把,目前找到的方案,应该还有一个使用正则匹配的,等结果出来后贴出来;
@haozxuan 感觉还是正则匹配吧
@haozxuan 正则的效率也很感人的,我的代码里有一些小部分用于替换但我也会找时间换掉的
一看到过滤,就想到正则匹配,超级好用。
敏感词用正则的都是土豪!
敏感词如果不考虑变种和误杀,其实很简单,Trie树什么的就搞定了,难就难在对付各种变种和误杀。
国家硬性规定的,宁可错杀,也放过,国家无硬性规定的,适度放宽。太高级的技术用来干这个不值得。
@haozxuan 期待结果
@fireswork 正则很强大,驾驭不了,还是有些尴尬的。。。我花了两天时间做性能测试,特别是对敏感词中的各种奇葩字符做过滤的时候,让我崩溃了。。。。。。
@aojiaotage 你的小模块我研究了下,鉴于我不需要replace,只是做true or false的判定,为了减少不确定因素的应先,所以参考DFA思想自己写了一个,性能对比将在页面首页贴出
@stardew516 如果敏感词全都是中规中矩的还好,有其他特殊字符就很尴尬了,搞了好久我是解决不了,所以就放弃了。
@coordcn 虽然不太理解为什么用正则的是土豪,但是特殊字符的过滤搞得我已经放弃这个方式了,将在页面贴出两种模式的性能对比;
@alsotang 看到我tang的监督回复还是让我感觉很亦可赛艇的,两天时间,主要是研究了下DFA思想,加上正则的抓狂规则,和一些公司琐碎事情,所以拖的比较晚了,将在首页更新两种方案的性能对比;
@haozxuan 话说。。我自己电脑上跑跑似乎1000个词的敏感词库替换1000个词只需要20ms。。你是肿么测试的呀。。 而且实际上DFA会比敏感词直接放内存里占用内存小
可以写进native模块
@aojiaotage 可能测试机制不太相同,我的场景是每次只会来一句话或一个词去匹配,所以我做匹配一个词的耗时,可能匹配一个词和10个词的耗时都是1ms,不过对我来说需求场景不同;至于内存消耗,不敢苟同,bloom-filter是存在位数组的,他的大小肯定比你的trie树要小,当然与直接放内存相比一个是数组一个是trie树,没有太深入研究消耗大小;综上,在目前敏感词库1000左右的样子,直接indexOf和其他算法并没有很大出入;