恶俗评论敏感词过滤,可直接拿去用,动态热更新

  • 过滤算法
  • 敏感词库加载及初始化
  • 敏感词库的动态热更新
  • bean配置
  • yml配置
  • 依赖

过滤算法

主要是实现一个前缀树的数据结构,项目启动时读取敏感词库并进行预处理化,保存到前缀树中,空间换时间,其中,filter方法为过滤方法。

/*** @author cy c* @date 2022/5/17 16:49*/
@Component
public class SensitiveFilter {private static final Logger logger = LoggerFactory.getLogger(SensitiveFilter.class);/***替换符*/@Value("${replacement}")private String REPLACEMENT;private TrieNode rootNode = new TrieNode();public TrieNode getRootNode() {return rootNode;}public void setRootNode(TrieNode rootNode) {this.rootNode = rootNode;}public void addKeyWord(String keyWord) {TrieNode tempNode = rootNode;for (int i = 0; i < keyWord.length(); i++) {char c = keyWord.charAt(i);TrieNode subNode = tempNode.getSubNode(c);if (subNode == null) {subNode = new TrieNode();tempNode.addSubNode(c, subNode);}tempNode = subNode;if (i == keyWord.length() - 1) {tempNode.setKeywordEnd(true);}}}/**** 过滤敏感词* @param text 待过滤文本* @return 过滤后的文本*/public String filter(String text) {if (StringUtils.isBlank(text)) {return null;}TrieNode tempNode = rootNode;int begin = 0;int position = 0;StringBuilder sb = new StringBuilder();while (position < text.length()) {char c = text.charAt(position);//跳过符号if (isSymbol(c)) {//若指针1处于根节点,将此符号计入结果,让指针2向下一步if (tempNode == rootNode) {sb.append(c);begin++;}//无论符号在开头或中间,指针3都向下走一步position++;continue;}//检查下个节点tempNode = tempNode.getSubNode(c);if (tempNode == null) {//以begin开头的字符串不是敏感词sb.append(text.charAt(begin));//进入下一个位置position = ++begin;//重新指向根节点tempNode = rootNode;} else if (tempNode.isKeywordEnd()) {//发现了敏感词,将begin-position字符串替换掉sb.append(REPLACEMENT);//进入下一个位置begin = ++position;//重新指向根节点tempNode = rootNode;} else {//检查下一个字符position++;}}//将最后一批计入结果sb.append(text.substring(begin));return sb.toString();}/***判断是否为符号*/private boolean isSymbol(Character c) {//0x2E80-0x9FFF是东亚文字范围return CharUtils.isAsciiAlphanumeric(c) && (c < 0x2E80 || c > 0x9FFF);}/***前缀树*/private class TrieNode {//关键词结束的标识private boolean isKeywordEnd = false;//子节点(key是下级字符,value是下级节点)private Map<Character, TrieNode> subNodes = new HashMap<>();public boolean isKeywordEnd() {return isKeywordEnd;}public void setKeywordEnd(boolean keywordEnd) {isKeywordEnd = keywordEnd;}//添加子节点public void addSubNode(Character c, TrieNode node) {subNodes.put(c, node);}//获取子节点public TrieNode getSubNode(Character c) {return subNodes.get(c);}}
}

敏感词库加载及初始化

这里我们使用到了spring的容器刷新事件和commons-io包,commons-io包用于对文件的动态监听,事件用于项目启动初始化时开启文件的监听线程及前缀树的初始化操作

/*** @author cy c* @date 2022/5/17 19:36*/
public class ContextRefreshedListener implements ApplicationListener<ContextRefreshedEvent> {private volatile AtomicBoolean isInit = new AtomicBoolean(false);private final FileAlterationMonitor fileAlterationMonitor;private final SensitiveFilter sensitiveFilter;@Value("${filePath.sensitivePath}")private String monitorDir;@Value("${filePath.sensitiveFile}")private String monitorFile;private final static Logger logger = LoggerFactory.getLogger(ContextRefreshedListener.class);public ContextRefreshedListener(FileAlterationMonitor fileAlterationMonitor, SensitiveFilter sensitiveFilter) {this.fileAlterationMonitor = fileAlterationMonitor;this.sensitiveFilter = sensitiveFilter;}/*** 容器刷新完成后初始化监听处理并加载恶评词*/@Overridepublic void onApplicationEvent(ContextRefreshedEvent event) {//cas操作防止父子容器重复加载导致事件重复触发start报错if (!isInit.compareAndSet(false, true)) {return;}sensitiveInit();fileAdaptorInit();}public void fileAdaptorInit() {try {logger.info(">>>>>>>>>>>>>>>>>>>文件监听开启<<<<<<<<<<<<<<<<<<<<<<");fileAlterationMonitor.start();} catch (Exception e) {logger.error("监控出错:{}", e);}}public void sensitiveInit() {try (LineIterator it = FileUtils.lineIterator(new File(monitorDir+monitorFile))) {while (it.hasNext()) {String badWord = it.nextLine();sensitiveFilter.addKeyWord(badWord);}} catch (IOException e) {logger.error("恶评词加载失败:{}", e.getMessage());}logger.info(">>>>>>>>>>>>>>>>>>>加载恶评词完成<<<<<<<<<<<<<<<<<<<<<<");}
}

敏感词库的动态热更新

继承FileAlterationListenerAdaptor,重写文件变动方法,当监听到文件变动时,初始化前缀树并替换

/*** @author cy c* @date 2022/5/17 16:49*/
public class RefreshSensitiveAdaptor extends FileAlterationListenerAdaptor {private final static Logger logger = LoggerFactory.getLogger(RefreshSensitiveAdaptor.class);@Autowiredprivate SensitiveFilter sensitiveFilter;/*** 文件修改事件处理*/@Overridepublic void onFileChange(File file) {logger.info("恶评词热更新:{}", file.getName());updateBadWord(file);logger.info("恶评词热更完成");}public void updateBadWord(File file) {try (LineIterator it = FileUtils.lineIterator(file)) {SensitiveFilter newSensitiveFilter = new SensitiveFilter();while (it.hasNext()) {String badWord = it.nextLine();newSensitiveFilter.addKeyWord(badWord);}sensitiveFilter.setRootNode(newSensitiveFilter.getRootNode());} catch (Exception e) {logger.error("恶评词更新失败!:{}", e.getMessage());}}}

bean配置

@Configuration
public class ListenerAutoConfig {@Value("${filePath.sensitivePath}")private String monitorDir;long interval = TimeUnit.SECONDS.toMillis(20);@Bean@ConditionalOnMissingBeanpublic ContextRefreshedListener contextRefreshedListener(FileAlterationMonitor fileAlterationMonitor, SensitiveFilter sensitiveFilter) {return new ContextRefreshedListener(fileAlterationMonitor, sensitiveFilter);}@Bean@ConditionalOnMissingBeanpublic RefreshSensitiveAdaptor refreshBeanAdaptor() {return new RefreshSensitiveAdaptor();}@Bean@ConditionalOnMissingBeanpublic FileAlterationMonitor fileAlterationMonitor(RefreshSensitiveAdaptor refreshSensitiveAdaptor) {//实例化观察者FileAlterationObserver observer = new FileAlterationObserver(new File(monitorDir));observer.addListener(refreshSensitiveAdaptor);return new FileAlterationMonitor(interval, observer);}
}

yml配置

文件每行一个敏感词

依赖

        <dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.6</version></dependency>

恶俗评论敏感词过滤 (可直接拿去用,动态热更新)相关推荐

  1. AC自动机:多模式串匹配实现敏感词过滤

    文章出处:极客时间<数据结构和算法之美>-作者:王争.该系列文章是本人的学习笔记. 1 敏感词过滤场景 在很多支持用户发表内容的网站,都有敏感词过滤替换的功能.例如将一些淫秽.反动内容过滤 ...

  2. python敏感词过滤replace_Serverless 实战:3 分钟实现文本敏感词过滤

    敏感词过滤是随着互联网社区一起发展起来的一种阻止网络犯罪和网络暴力的技术手段,通过对可能存在犯罪或网络暴力的关键词进行有针对性的筛查和屏蔽,能够防患于未然,将后果严重的犯罪行为扼杀于萌芽之中. 随着各 ...

  3. 敏感词过滤优化的解决方案

    敏感词过滤优化的解决方案 介绍 敏感词字库匹配其实是关键字的一种匹配.最简单想到的额方法就是,如果要匹配某个字符串,去遍历敏感字库,这是最简单粗暴的方式.但是很明显当字库很大时,比如有六十万条数据,那 ...

  4. 转:鏖战双十一-阿里直播平台面临的技术挑战(webSocket, 敏感词过滤等很不错)...

    转自:http://www.infoq.com/cn/articles/alibaba-broadcast-platform-technology-challenges 鏖战双十一-阿里直播平台面临的 ...

  5. TypeScript:Aho–Corasick算法实现敏感词过滤

    敏感词过滤应该是许多后端同事经常会遇到的需求,无论是评论.弹幕.文章,都需要做敏感词过滤处理来规避风险.在前端开发中,使用replace函数来替换字符串是我们的常规操作,在这之前我思考过如果用Java ...

  6. 【图解算法面试】记一次面试:说说游戏中的敏感词过滤是如何实现的?

    版权声明:本文为苦逼的码农原创.未经同意禁止任何形式转载,特别是那些复制粘贴到别的平台的,否则,必定追究.欢迎大家多多转发,谢谢. 小秋今天去面试了,面试官问了一个与敏感词过滤算法相关的问题,然而小秋 ...

  7. 敏感词过滤之——自定义构建查询词库与快速查询实现

    关于敏感词过滤的一点思考与实践 业务场景 思考与研究 逻辑分析 代码实现(php) 构建敏感词树 分割字符串 敏感词树长分支的递归实现 读取敏感词库 敏感词树的查询 查询实现 调用 测试.分析与总结 ...

  8. spring boot 使用DFA算法实现敏感词过滤

    spring boot 使用DFA算法实现敏感词过滤 敏感词.文字过滤是一个网站必不可少的功能,如何设计一个好的.高效的过滤算法是非常有必要的. DFA算法简介 DFA全称为:Deterministi ...

  9. 【面试被虐】说说游戏中的敏感词过滤是如何实现的?

    版权声明:本文为苦逼的码农原创.未经同意禁止任何形式转载,特别是那些复制粘贴到别的平台的,否则,必定追究.欢迎大家多多转发,谢谢. 小秋今天去面试了,面试官问了一个与敏感词过滤算法相关的问题,然而小秋 ...

最新文章

  1. 前序遍历(递归、非递归)、层序遍历(递归、非递归)
  2. Django(part22)--创建数据对象
  3. 通过kubeless命令行部署Kyma Lambda Function
  4. JQ插件 jquery mobiscroll
  5. ubuntu 配置 静态ip
  6. C#信息采集系统,常见控件练习
  7. 华为计算机充电指示灯,数码产品:华为p40充电指示灯不亮在哪里设置 有指示灯吗...
  8. c++虚函数动态联编需要避免的内存泄漏问题
  9. js正则表达式校验手机号码和电话号码
  10. bat调用vbs脚本
  11. 偏相关分析在matlab上的实现
  12. 小学生学计算机编程实例,用日常生活小例子来教孩子学编程
  13. bigmp4.com AI 视频无损放大高清补帧工具
  14. 使用WebPack构建UMD库兼容性原理浅谈
  15. 嵌入式 Linux 入门(一、Linux 基本介绍及文件结构)
  16. 音频在计算机里存储形式是什么,如何在录音带上存储任何类型的文件
  17. 如何在PyCharm上配置Python解释器,以及解决Windows上PyCharm不能识别C:\Users\Me\AppData路径的问题。
  18. SYN包TCP选项的设置
  19. 从头开始,彻底理解服务端渲染原理
  20. CollageIt - [照片拼贴,照片整合]

热门文章

  1. Linux | Ubuntu 20.04安装ipopt和cppAD | 安装全流程+报错解决
  2. MATLAB 图片三角风格化(low poly)
  3. Kindle安装KOReader插件实现PDF文件的重新排版
  4. Time Series Segmentation through Automatic Feauture Learning
  5. ATF54143的ADS模型
  6. 运营方案要包括哪些内容_施工招标项目技术方案编制的内容包括哪些?
  7. md5在线查询和本地破解
  8. Oracle培训的一些感受
  9. GNS3搭建小型局域网并连接互联网
  10. 0patch接棒微软,将为Win7提供安全补丁至2025年1月