使用TrieTree(字典树)来实现敏感词过滤
使用TrieTree(字典树)来实现敏感词过滤
1. 字典树定义
字典树(TrieTree),是一种树形结构,典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串,如01字典树)。主要思想是利用字符串的公共前缀来节约存储空间。很好地利用了串的公共前缀,节约了存储空间。字典树主要包含两种操作,插入和查找。
字典树具有以下规则:
-1. 根节点不包含字符,其他节点包含一个字符。
-
- 从根节点到某一节点经过的字符连接起来构成一个字符串。如图中的 him 、 her 、 cat 、 no 、 nova。
-
- 一个字符串与 Trie 树中的一条路径对应。
-
- 在实现过程中,会在叶节点中设置一个标志,用来表示该节点是否是一个字符串的结尾,本例中用isEnd标记。
关于字典树的插入、删除等操作,可参考以下文章:
- 在实现过程中,会在叶节点中设置一个标志,用来表示该节点是否是一个字符串的结尾,本例中用isEnd标记。
我来说说我对 Trie 数的理解。
下面是用Java实现的简易的TrieTree字典树
import java.util.HashMap;
import java.util.Map;public class TrieTree {public class TrieNode{public char value;public int isEnd; //0表示非终结 1表示终结public Map<Character,TrieNode>children;public TrieNode(char value,int isEnd){this.value=value;this.isEnd=isEnd;this.children=new HashMap<>();}public TrieNode(char value){this.value=value;this.isEnd=0;this.children=new HashMap<>();}public TrieNode(){this.isEnd=0;this.children=new HashMap<>();}}private TrieNode root;public TrieTree(){this.root=new TrieNode();}//插入敏感词汇public void insert(String str){if(str==null||str.length()==0){return ;}root=insert(root,str,0);}//判断字符串中,是否包含敏感词汇public boolean match(String str){if (str == null || "".equals(str)) {return false;}TrieNode temp=root;for(int i=0;i<str.length();i++){char ch=str.charAt(i);//获取到下一个节点TrieNode next = temp.children.get(ch);if (next==null){temp=root;}else{temp=next;}if (temp.isEnd==1){return true;}}return false;}//移除敏感词汇public void remove(String str){if (str == null || "".equals(str)) {return;}//没有该敏感词时,直接返回if (!match(str)){return;}//开始删除敏感词root=remove(root,str,0);}private TrieNode remove(TrieNode t,String str,int index){char ch=str.charAt(index);TrieNode child = t.children.get(ch);//到达最末尾if (index==str.length()-1){if (child.children.size()>0){//当前节点有子节点时,将标记为设置为0即可child.isEnd=0;}else{//否则直接删除该节点t.children.remove(ch);}return t;}//往下删除child=remove(child,str,++index);//回溯if (child.children.size()==0&&child.isEnd==1){//当没有节点并且isEnd==0时t.children.remove(ch);}return t;}private TrieNode insert(TrieNode t,String str,int index){char ch=str.charAt(index);TrieNode child = t.children.get(ch);if (child!=null){if (index==str.length()-1){child.isEnd=1;return t;}child=insert(child,str,++index);
// t.children.put(ch,child);return t;}child=new TrieNode(ch);if (index==str.length()-1){child.isEnd=1;}else{child=insert(child,str,++index);}t.children.put(ch,child);return t;}public static void main(String[] args) {String[]sensitive={"华南理工","大学生","泰裤辣"};TrieTree trieTree=new TrieTree();for(int i=0;i<sensitive.length;i++){trieTree.insert(sensitive[i]);}System.out.println(trieTree.match("我是华南大学的学生"));System.out.println(trieTree.match("华北理工大学泰裤"));System.out.println(trieTree.match("华南理工大学"));System.out.println(trieTree.match("大学生"));System.out.println(trieTree.match("大学生泰裤辣"));System.out.println(trieTree.match("人之初性本善性相近习相远华南大学泰山崩于前而面不改色泰裤辣哈哈哈哈哈哈"));trieTree.remove("华南理工");System.out.println(trieTree.match("华南理工大学"));trieTree.remove("大学生");System.out.println(trieTree.match("大学生"));trieTree.remove("泰裤辣");System.out.println(trieTree.match("人之初性本善性相近习相远华南大学泰山崩于前而面不改色泰裤辣哈哈哈哈哈哈"));}
}
测试结果如下:
2. 使用字典树实现话题发布时,检查是否有敏感词汇
先创建三个表,分别是m_user用户表,m_topic话题表,m_sensitive敏感词汇表,表的具体内容如下:
表的部分内容如下:
创建一个maven项目,添加下列依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.young</groupId><artifactId>trie01</artifactId><version>1.0-SNAPSHOT</version><parent><artifactId>spring-boot-starter-parent</artifactId><groupId>org.springframework.boot</groupId><version>2.7.0</version></parent><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.4.3</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.83</version></dependency></dependencies><properties><maven.compiler.source>11</maven.compiler.source><maven.compiler.target>11</maven.compiler.target></properties></project>
application.yml
server:port: 8089
spring:datasource:username: rootpassword: 123456url: jdbc:mysql://localhost:3306/young?useSSL=false&serverTimezone=UTCdriver: com.mysql.cj.jdbc.Driver
mybatis-plus:global-config:db-config:logic-not-delete-value: 0logic-delete-value: 1
实体类信息如下图,其中User类中有一个字段isEnabled,我们可以使用这个字段,来约束用户的行为,但用户多次发布含有不当言论的话题时,将用户的isEnable置为0,这里为了方便演示,不实现该功能
相关的mapper
UserMapper.java
package com.young.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.young.entity.User;
import org.apache.ibatis.annotations.Mapper;@Mapper
public interface UserMapper extends BaseMapper<User> {
}
SensitiveMapper.java
package com.young.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.young.entity.Sensitive;
import org.apache.ibatis.annotations.Mapper;@Mapper
public interface SensitiveMapper extends BaseMapper<Sensitive> {
}
TopicMapper.java
package com.young.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.young.entity.Topic;
import org.apache.ibatis.annotations.Mapper;@Mapper
public interface TopicMapper extends BaseMapper<Topic> {
}
UserService.java
package com.young.service;import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.young.entity.User;
import com.young.mapper.UserMapper;
import com.young.vo.UserVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class UserService {@Autowiredprivate UserMapper userMapper;public User login(String username,String password){LambdaQueryWrapper<User>queryWrapper=new LambdaQueryWrapper<>();queryWrapper.eq(User::getUsername,username).eq(User::getPassword,password);User user = userMapper.selectOne(queryWrapper);return user;}
}
TopicService.java
package com.young.service;import com.young.entity.Topic;
import com.young.exception.BusinessException;
import com.young.mapper.TopicMapper;
import com.young.vo.TrieTree;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import javax.annotation.Resource;@Service
public class TopicService {@Autowiredprivate TopicMapper topicMapper;@Resourceprivate TrieTree trieTree;public boolean saveTopic(Topic topic){//判断是否有敏感词汇if (trieTree.match(topic.getTitle())||trieTree.match(topic.getContent())) {throw new BusinessException("发布内容中存在不当词汇,请遵守相关法律法规,营造良好的网络环境!!!");}return topicMapper.insert(topic)>0;}
}
SensitiveService.java,用于获取数据库中的敏感词汇表
package com.young.service;import com.young.entity.Sensitive;
import com.young.mapper.SensitiveMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;@Service
public class SensitiveService {@Autowiredprivate SensitiveMapper sensitiveMapper;public List<Sensitive>getAllSensitive(){return sensitiveMapper.selectList(null);}public List<String>getAllSensitiveWord(){List<Sensitive> allSensitive = getAllSensitive();if (allSensitive!=null&&allSensitive.size()>0){return allSensitive.stream().map(sensitive -> sensitive.getWord()).collect(Collectors.toList());}return new ArrayList<>();}
}
TrieTreeConfig.java,创建TrieTree的相关bean,方便后续使用
package com.young.config;import com.young.service.SensitiveService;
import com.young.vo.TrieTree;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import java.util.List;@Configuration
public class TrieTreeConfig {@Autowiredprivate SensitiveService sensitiveService;@Beanpublic TrieTree constructTrieTree(){System.out.println("初始化字典树======================");List<String> words = sensitiveService.getAllSensitiveWord();TrieTree trieTree=new TrieTree();for (String word : words) {trieTree.insert(word);}return trieTree;}
}
BusinessException.java
package com.young.exception;public class BusinessException extends RuntimeException{private String msg;public BusinessException(String msg){super(msg);}
}
GlobalExceptionHandler.java
package com.young.exception;import com.young.util.ResultVOUtil;
import com.young.vo.ResultVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {@ExceptionHandler(BusinessException.class)public ResultVO businessExceptionHandler(BusinessException e){log.error("businessException:{}",e);return ResultVOUtil.fail(400,e.getMessage());}@ExceptionHandler(Exception.class)public ResultVO exceptionHandler(Exception e){log.error("exception:{}",e);return ResultVOUtil.fail(400,e.getMessage());}
}
相关的vo
ResultVOUtil.java
package com.young.util;import com.young.vo.ResultVO;public class ResultVOUtil <T>{public static <T> ResultVO<T> success(){return new ResultVO<>(200,"操作成功");}public static <T> ResultVO<T> success(T data){return new ResultVO<>(200,"操作成功",data);}public static <T> ResultVO<T> fail(){return new ResultVO<>(400,"操作失败");}public static <T> ResultVO<T> fail(Integer code,String msg){return new ResultVO<>(code,msg);}
}
DemoController.java,这里为了方便演示,用了session保存用户信息
package com.young.controller;import com.young.entity.Topic;
import com.young.entity.User;
import com.young.service.TopicService;
import com.young.service.UserService;
import com.young.util.ResultVOUtil;
import com.young.vo.ResultVO;
import com.young.vo.UserVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import javax.servlet.http.HttpServletRequest;@RestController
@RequestMapping("/user")
public class DemoController {@Autowiredprivate UserService userService;@Autowiredprivate TopicService topicService;@PostMapping("/login")public ResultVO login(@RequestBody UserVO userVO, HttpServletRequest request){User user = userService.login(userVO.getUsername(), userVO.getPassword());if (user==null){return ResultVOUtil.fail(400,"用户名或密码错误");}request.getSession().setAttribute("user",user);return ResultVOUtil.success(user);}@PostMapping("/topic")public ResultVO addTopic(@RequestBody Topic topic,HttpServletRequest request){User user = (User)request.getSession().getAttribute("user");if (user==null){return ResultVOUtil.fail(400,"用户未登录");}topic.setUserId(user.getId());if (topicService.saveTopic(topic)){return ResultVOUtil.success();}return ResultVOUtil.fail(400,"发布话题失败");}
}
运行项目,登录用户
发布文章(包含敏感词汇)
相关文章:

使用TrieTree(字典树)来实现敏感词过滤
使用TrieTree(字典树)来实现敏感词过滤 1. 字典树定义 字典树(TrieTree),是一种树形结构,典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串,如01字典树)。…...

USB转串口芯片CH9101U
CH9101是一个USB总线的转接芯片,实现USB转异步串口。提供了常用的MODEM联络信号,用于为计算机扩展异步串口,或者将普通的串口设备或者MCU直接升级到USB总线。 特点 全速USB设备接口,兼容USB V2.0。内置固件,仿真标准串…...
Java语言介绍
Java是一种广泛使用的计算机编程语言,由Sun Microsystems公司于1995年推出。它是一个健壮的、面向对象的、跨平台的语言,被用于开发各种应用程序和系统,包括Web应用程序、移动应用程序、桌面应用程序、游戏以及企业级系统等。 Java具有许多优…...
终于把 vue-router 运行原理讲明白了(二)!!!
一、vue-router路由变化侦测 1.1 上一遍文章中,介绍了vue-router 的install 函数的内部实现,知道了能在this中访问$router 和视图更新的机制,文章链接终于把 vue-router 运行原理讲明白了(一)!!…...

ChatGPT实现服务器体验沙箱
服务器体验沙箱 IT 人员在学习一门新技术时,第一个入门门槛通常都是"如何在本地安装并成功运行"。因此,很多技术的官网都会通过沙箱技术,提供在线试用的 playground 或者按步模拟的 tour。让爱好者先在线尝试效果是否满足预期&…...

【算法】刷题中的位运算
作者:指针不指南吗 专栏:算法篇 🐾人类做题的过程,其实是暴搜的过程🐾 文章目录 1.位运算概述2.位运算符3.位运算应用3.1整数的奇偶性判断3.2有关 2 的幂的应用3.3lowbit(x)返回x的最后一位13.4二进制数中1的个数3.5求…...
9.Java中异常处理机制是什么
Java的异常处理通过五个关键字来实现,分别是捕获异常:try,catchsfinally;声明异常:throws;抛出异常:throw 一:try,catch捕获异常二:finally回收资源三&#x…...
GeoTools实战指南: 叠加GeoTIFF与Shapefile图层生成截图
GeoTools实战指南: 叠加GeoTIFF与Shapefile图层生成截图 介绍 本教程将介绍如何使用GeoTools库在Java中将栅格数据(GeoTIFF)与矢量数据(Shapefile)叠加显示,并将结果保存为PNG格式的图片文件。我们将解析和分析 RasterDataRenderer 类,并了解其中的每个方法和对象。 准…...

nginx配置sh脚本远程执行一键安装
背景 本地多机重复操作某些shell指令,分步执行,很耗费时间, 需要远程一键部署,傻瓜化运维,更为通用安装。 即参考docker通用安装 sudo curl https://get.docker.com | sh - # sudo python3 -m pip install docker-co…...
Excel表格成绩排名全攻略,让你事半功倍!
在学校或公司中,我们经常需要对成绩进行排名。如果手动计算排名,不仅费时费力,而且容易出错。幸运的是,Microsoft Excel提供了一个简单而快速的方法来计算和显示排名。 在学校或公司中,成绩排名是一项重要的任务。使用…...

Docker 持久化存储 Bind mounts
Docker 持久化存储 Bind mounts Bind mounts 的 -v 与 --mount 区别启动容器基于bind mount挂载到容器中的非空目录只读 bind mountcompose 中使用 bind mount 官方文档:https://docs.docker.com/storage/bind-mounts/ Bind mounts 的 -v 与 --mount 区别 如果使用…...

LVS +Keepalived 高可用群集部署
一、LVSKeepalived 高可用群集 在这个高度信息化的 IT 时代,企业的生产系统、业务运营、销售和支持,以及日常管理等环节越来越依赖于计算机信息和服务,对高可用(HA)技术的应用需求不断提高,以便提供持续的…...
Kafka调优
生产者 参数名称描述bootstrap.serverskafka集群的地址key.deserializerkey的反序列化类,写全类名value.deserializervalue的反序列化类,写全类名buffer.memoryRecordAccumulator缓冲区总大小,默认32mbatch.size缓冲区一批数据最大值&#x…...
Debezium系列之:详细介绍Debezium2.X版本导出Sqlserver数据库Debezium JMX指标的方法
Debezium系列之:详细介绍Debezium2.X版本导出Sqlserver数据库Debezium JMX指标的方法 一、需求背景二、相关技术文章三、安装jmx_prometheus_javaagent四、Debezium2.X版本Sqlserver数据库jmx指标格式五、导出Debezium2.X版本Sqlserver数据库jmx指标方法六、Debezium2.X版本各…...

基于PWM技术的三相光伏逆变器研究(Simulink)
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...

〖Python网络爬虫实战㉑〗- 数据存储之JSON操作
订阅:新手可以订阅我的其他专栏。免费阶段订阅量1000 python项目实战 Python编程基础教程系列(零基础小白搬砖逆袭) 说明:本专栏持续更新中,目前专栏免费订阅,在转为付费专栏前订阅本专栏的,可以免费订阅付…...

不得不说的行为型模式-责任链模式
目录 责任链模式: 底层原理: 代码案例: 下面是面试中可能遇到的问题: 责任链模式: 责任链模式是一种行为型设计模式,它允许多个对象在一个请求序列中依次处理该请求,直到其中一个对象能够…...

基于dsp+fpga+AD+ENDAC的半导体运动台高速数据采集电路仿真设计(四)
整个调试验证与仿真分析分三个步骤:第一步是进行 PCB 检查及电气特性测试,主 要用来验证硬件设计是否正常工作;第二步进行各子模块功能测试,包括高速光纤串行 通信的稳定性与可靠性测试, A/D 及 D/A 转换特性测…...

快速搭建Electron+Vite3+Vue3+TypeScript5脚手架 (无需梯子,快速安装Electron)
一、介绍 😆 😁 😉 Electron是一个使用 JavaScript、HTML 和 CSS 构建桌面应用程序的框架。 嵌入 Chromium 和 Node.js 到 二进制的 Electron 允许您保持一个 JavaScript 代码代码库并创建 在Windows上运行的跨平台应用 macOS和Linux——不需…...

语义分割学习笔记(二)转置卷积
目录 1.转置卷积Transposed Convolution概念 2.转置卷积操作步骤 3.转置卷积参数 4.实战案例 推荐课程:转置卷积(transposed convolution)_哔哩哔哩_bilibili 感谢霹雳吧啦Wz,真乃神人也。 1.转置卷积Transposed Convolutio…...

docker详细操作--未完待续
docker介绍 docker官网: Docker:加速容器应用程序开发 harbor官网:Harbor - Harbor 中文 使用docker加速器: Docker镜像极速下载服务 - 毫秒镜像 是什么 Docker 是一种开源的容器化平台,用于将应用程序及其依赖项(如库、运行时环…...

【OSG学习笔记】Day 18: 碰撞检测与物理交互
物理引擎(Physics Engine) 物理引擎 是一种通过计算机模拟物理规律(如力学、碰撞、重力、流体动力学等)的软件工具或库。 它的核心目标是在虚拟环境中逼真地模拟物体的运动和交互,广泛应用于 游戏开发、动画制作、虚…...

阿里云ACP云计算备考笔记 (5)——弹性伸缩
目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...

MFC内存泄露
1、泄露代码示例 void X::SetApplicationBtn() {CMFCRibbonApplicationButton* pBtn GetApplicationButton();// 获取 Ribbon Bar 指针// 创建自定义按钮CCustomRibbonAppButton* pCustomButton new CCustomRibbonAppButton();pCustomButton->SetImage(IDB_BITMAP_Jdp26)…...

学校招生小程序源码介绍
基于ThinkPHPFastAdminUniApp开发的学校招生小程序源码,专为学校招生场景量身打造,功能实用且操作便捷。 从技术架构来看,ThinkPHP提供稳定可靠的后台服务,FastAdmin加速开发流程,UniApp则保障小程序在多端有良好的兼…...

华为OD机试-食堂供餐-二分法
import java.util.Arrays; import java.util.Scanner;public class DemoTest3 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint a in.nextIn…...
【决胜公务员考试】求职OMG——见面课测验1
2025最新版!!!6.8截至答题,大家注意呀! 博主码字不易点个关注吧,祝期末顺利~~ 1.单选题(2分) 下列说法错误的是:( B ) A.选调生属于公务员系统 B.公务员属于事业编 C.选调生有基层锻炼的要求 D…...

DBAPI如何优雅的获取单条数据
API如何优雅的获取单条数据 案例一 对于查询类API,查询的是单条数据,比如根据主键ID查询用户信息,sql如下: select id, name, age from user where id #{id}API默认返回的数据格式是多条的,如下: {&qu…...

ElasticSearch搜索引擎之倒排索引及其底层算法
文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...

BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践
6月5日,2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席,并作《智能体在安全领域的应用实践》主题演讲,分享了在智能体在安全领域的突破性实践。他指出,百度通过将安全能力…...