一个敏感词检查功能是怎么来的

需求

敏感词检查是一个很常见的需求,在做用户输入功能时,如果不对敏感词进行检查,不仅影响平台内容的质量,可能还因此违反法律法规直接被封。敏感词是动态的,不同时机敏感不同,用户还会千方百计的使用谐音、拼音等避开检查,所以需要实时的更新。及时修改规则。

分析

最好的办法当然是人工审核,效果最好,但是人工审核成本太高了,要是内容少还好,一多根本审核不过来,影响用户发布内容,用户跑完了。

所以一般都是通过机器检查并且不断的根据实际情况完善检测机制。

机器检测也可以通过机器学习的方法不过不在本文的讨论范围内。

先建立一个敏感词库,对用户输入的文本逐个比较检查是否包含敏感词库里的敏感词。

敏感词库建立比较简单,就建立一个表保存敏感词,提供CURD操作即可。敏感词库可以网上找,而且不同的业务需要的敏感词是不一样的,一般网上找一版之后再进行人工筛查后不断的完善即可。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XhrJzHoF-1668919959859)(https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/3fdd756e521943ccac03312e77ed0d41~tplv-k3u1fbpfcp-watermark.image?)]

这样敏感词检测问题就转化成字符串匹配的问题。假设敏感词库里有一千条敏感词,那么每次都需要进行一千次匹配,比如下面代码。

public static void main(String[] args) {
    List<String> sensitiveWordList = new ArrayList<>();
    sensitiveWordList.add("今天");
    sensitiveWordList.add("明天");
    sensitiveWordList.add("后天");

    String word = "今天去上班,明天也要去上班,后天不用去上班";

    for (String s : sensitiveWordList) {
        if(sensitiveWord(word, s)){
            System.out.println("存在敏感词:"+ s);
        }
    }
}

public static boolean sensitiveWord(String word, String sensitiveWord){
    if(sensitiveWord.length() == 0){
        return true;
    }
    if(word.length()  < sensitiveWord.length() ){
        return false;
    }

    for (int i = 0; i < word.length(); i++) {
        //首字母相等继续匹配下一个字母
        if(word.charAt(i) == sensitiveWord.charAt(0)){
            if(sensitiveWord(word.substring(i+1), sensitiveWord.substring(1))){
                return true;
            }
            //否则匹配下一个字母开始
        }else if(sensitiveWord(word.substring(i+1), sensitiveWord)){
            return true;
        }
    }
    return false;
}

输出结果为

存在敏感词:今天
存在敏感词:明天
存在敏感词:后天

整体思路也是比较直观的,和人工去匹配的思维是一样的,代码中先遍历输入句子是否存在这个字,如果不存在就比较下一个字符,如果存在就进入子循环检查下一个字符是否是,如果是就存在,如果不是再回到原来的地方继续寻找这个字符,不断重复此步骤直到末尾。

人工检查也是这样子找的,这样的代码很多循环会显得很笨重。一点都不优雅而且随着敏感词的增多,会越来越慢。如果上万个敏感词,那么每次输入都要进行上万次循环(晕)

有什么办法进行优化呢?

仔细比较会发现有一些重复的比较。比如,如果存在敏感词颜色电影颜色小视频颜色图片,去检查句子网站中如果存在颜色电影将会被依法查封那么颜色这两个字会被检查三次,重复计算了三次。

存在重复的工作那么就存在优化的空间。如何做让它只进行一次检查后面共用结果呢?

既然是因为三个敏感词都存在颜色才会重复计算,那么是否可以将它们三个归类,先检查颜色再检查颜色后面是否是电影小视频图片呢,这样检查颜色后,如果后面存在电影小视频图片说明存在敏感词。

进一步想,颜色电影可以拆成颜色电影那么也可以拆成颜``色``电``影四个字,这样后面如果新加一个颜如玉这样的敏感词又可以共用字,减少的匹配次数。美哉。

因为匹配单词是从前面按顺序往后所有字符都匹配才能算成功匹配,所以只有相同前缀的词可以共用前缀复用匹配。

如果说所有敏感词都不存在公共前缀那么就没法通过这个方法优化了。

这就是成了著名前缀树
[208. 实现 Trie (前缀树)](https://leetcode.cn/problems/implement-trie-prefix-tree/)

所以将所有敏感词构建一棵前缀树,之后将用户输入的内容进行检查即可。

public static void main(String[] args) {
    List<String> sensitiveWordList = new ArrayList<>();
    sensitiveWordList.add("今天");
    sensitiveWordList.add("明天");
    sensitiveWordList.add("后天");

    String word = "今天去上班,明天也要去上班,后天不用去上班";

    //初始化一棵前缀树
    Trie trie = new Trie();
    for (String s : sensitiveWordList) {
        trie.insert(s);
    }

    System.out.println(trie.sensitiveWord(word));

}
static class Trie {

    //通过map保存子树
    private Map<Character, Trie> children ;
    private boolean isEnd;
    public Trie() {
        children = new HashMap<>();
        isEnd = false;
    }

    //将敏感词插入到前缀树中
    public void insert(String word) {
        Trie node = this;
        for (int i = 0; i < word.length(); i++) {
            char ch = word.charAt(i);
            Trie childrenNode = node.children.get(ch);
            if(childrenNode == null){
                node.children.put(ch, new Trie());
            }
            node = node.children.get(ch);
        }
        node.isEnd = true;
    }

    //检查一个单词的开头是否存在铭感词
    private boolean prefixSensitiveWord(String word, int start) {
        Trie node = this;
        for (int i = start; i < word.length(); i++) {
            char ch = word.charAt(i);
            Trie childrenNode = node.children.get(ch);
            if(childrenNode == null){
                //说明后面没有匹配的了
                break;
            }else{
                //说明存在一个敏感词匹配了
                if(childrenNode.isEnd){
                    return true;
                }
            }
            node = childrenNode;
        }
        return node.isEnd;
    }

    //检查一个单词是否存在铭感词
    private boolean sensitiveWord(String word) {
        //不断向前移动检查
        for (int i = 0; i < word.length(); i++) {
            if(prefixSensitiveWord(word, i)){
                return true;
            }
        }
        return false;
    }
}

后续

只是通过简单的敏感词匹配判断存在敏感词也存在一些缺陷,比如一台独立的服务器,是理论上是合规的但是其中含有台又有独所以可能被判定含有敏感词。中文博大精深,可能换个读音表达一个意思,懂的都懂,但是机器不懂。牛点的可以通过人工智能的手段,训练一个专门识别敏感词的模型,提高识别率。但是语言博大精深,像在王者荣耀这种大游戏也照样能不带一点脏话骂人[狗头dog],可见要通过机器准确的进行敏感词检测难度之大,所以敏感词的检测只是一个简单的初步检查,真要花心思发布违规内容很难拦下或者说准确的拦截敏感词的成本是很高的。

一般再通过设计一些用户投诉机制,发布敏感词惩罚机制等进一步提高用户发敏感词的成本,想办法让用户不发,问题解决不了就解决搞出问题的人,嘿嘿。

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
极致CMS是一款功能强大,免费开源,无需授权,免费商用,免费二开的建站系统。 极致CMS前台功能: CMS模块:首页,栏目,单页,自定义页面 个人中心:响应式设计个人中心模块,兼容各种PC及手机 关注粉丝:可以关注某个用户,粉丝查看 喜欢收藏:喜欢收藏文章及商品等 评论管理:评论文章/商品 内容投稿:可以在网站上投稿 购物车:临时购物车 我的钱包:金币和积分记录 积分兑换:网站支持用积分兑换,后台设定对应的兑换率 订单中心:订单记录 消息提醒:内置收藏喜欢评论,订单提交等消息提醒,也可以设置中关闭 极致CMS后台功能:layui前端框架 基础模块:商品模块、文章模块、栏目模块、TAG管理、轮播图管理、友情链接、留言管理、评论管理 高级模块:自定义模块、自定义字段(新增各种类型字段) 桌面设置:可以自定义后台界面功能摆放 双端静态生成 支持自动缓存,支持设定页面缓存时间 PC/手机/微信三端可以设定不同模板 自定义栏目URL:无需手动配置伪静态 SEO功能:XML生成,栏目及各模块内置SEO选项 插件中心:可以在线下载/安装插件,可以在线升级系统,提供丰富的插件 支持QQ登录,微信登录 支持微信支付/支付宝支付 支持微信接入/获取微信素材 后台管理员多角色管理:每个角色可以设定不同后台界面(结合桌面设置),每个角色可以指定管理某个栏目 图片管理:各种上传的图片可以进行管理,可以及时删除垃圾图片 自定义系统配置:可以在系统配置中自定义 敏感词过滤:可以设置敏感词过滤,提交时自动检查 极致CMS v1.9.4 更新内容如下: 修复:静态HTML生成问题 修复:导航缓存问题 修复:管理员列表分页数无法设置 优化:session缓存时间 优化:404页面返回404状态 优化:模块中设置栏目不是必选,字段可以在全局栏目使用 优化:栏目模板可以手动填写 优化:图集多附件字段默认text类型 新增:后台角色可以设置发布审核

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值