使用TrieTree(字典树)来实现敏感词过滤

news2025/1/11 23:41:49

使用TrieTree(字典树)来实现敏感词过滤

1. 字典树定义

字典树(TrieTree),是一种树形结构,典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串,如01字典树)。主要思想是利用字符串的公共前缀来节约存储空间。很好地利用了串的公共前缀,节约了存储空间。字典树主要包含两种操作,插入和查找。
字典树具有以下规则:
-1. 根节点不包含字符,其他节点包含一个字符。

    1. 从根节点到某一节点经过的字符连接起来构成一个字符串。如图中的 him 、 her 、 cat 、 no 、 nova。
    1. 一个字符串与 Trie 树中的一条路径对应。
    1. 在实现过程中,会在叶节点中设置一个标志,用来表示该节点是否是一个字符串的结尾,本例中用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: root
    password: 123456
    url: jdbc:mysql://localhost:3306/young?useSSL=false&serverTimezone=UTC
    driver: com.mysql.cj.jdbc.Driver
mybatis-plus:
  global-config:
    db-config:
      logic-not-delete-value: 0
      logic-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 {
    @Autowired
    private 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 {
    @Autowired
    private TopicMapper topicMapper;
    @Resource
    private 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 {
    @Autowired
    private 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 {
    @Autowired
    private SensitiveService sensitiveService;
    @Bean
    public 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 {
    @Autowired
    private UserService userService;
    @Autowired
    private 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,"发布话题失败");
    }
}

运行项目,登录用户
在这里插入图片描述
发布文章(包含敏感词汇)
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/482330.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Hive本地开发/学习环境配置

前提 hive依赖hadoop的相关组件&#xff0c;需要启动Hadoop的相关组件。 Hive 版本&#xff1a;3.1.3 Hadoop版本&#xff1a;3.3.4 hive-env.sh export HADOOP_HOME$HADOOP_HOME export HIVE_CONF_DIR/usr/local/Cellar/hive/3.1.3/libexec/conf export HIVE_AUX_JARS_PATH/…

micro-app的简单学习

本文承接上一篇手把手教你使用vue2搭建micro-app&#xff0c;对micro-app进行简单的认识与学习。 简述 因为上一篇只是对micro-app的搭建&#xff0c;并没有对具体的内容进行深入了解&#xff0c;所以本文是在上一篇文章代码的基础上对micro-app官网&#xff0c;的初步了解。…

Vue(标签属性:ref、配置项:props、混入mixin、插件、样式属性:scroped)

一、ref&#xff08;打标识&#xff09; 前面提及到了标签属性&#xff1a;keys 这里将了解ref&#xff1a;打标识 正常布置脚手架并创建入口文件main.js,引入组件 1. 可以给元素注册引用信息&#xff08;获取真实DOM&#xff09; 给一个按钮获取上方的dom的方法&#xff0c;方…

log4j2实现日志输出

引言 日志是我们在软件开发过程中非常重要的一个组成部分&#xff0c;它能够记录系统运行时的各种信息和异常&#xff0c;方便我们在需要的时候进行排查和调试。而Log4j2是目前最为流行的Java日志框架之一&#xff0c;它提供了丰富的日志输出方式和配置选项&#xff0c;可以满…

设计模式——装饰器模式(Decorator Pattern)

很久没有写博客了&#xff0c;最近也有很多事情要处理&#xff0c;也在努力的备考软件考试&#xff0c;正好模拟题中有一道关于装饰器模式的题&#xff0c;觉得还不错&#xff0c;所以特地写一篇文章希望能分享给小伙伴们。 装饰器模式的作用&#xff1a;允许向一个现有的对象…

vue3导入elcel表格并展示(使用xlsx插件+vite+element-plus)/js上传表格(js+xlsx)

表格内容(本博客演示的表格,这里其实可以更换任意表格,动态展示的) 安装插件xlsx npm install xlsx组件的所有代码(附解释) <script setup> import { ref } from "vue"; import * as XLSX from "xlsx"; // 把文件按照二进制进行读取 function read…

解密PyTorch动态计算图:打破深度学习束缚的秘密武器

❤️觉得内容不错的话&#xff0c;欢迎点赞收藏加关注&#x1f60a;&#x1f60a;&#x1f60a;&#xff0c;后续会继续输入更多优质内容❤️ &#x1f449;有问题欢迎大家加关注私戳或者评论&#xff08;包括但不限于NLP算法相关&#xff0c;linux学习相关&#xff0c;读研读博…

【C++】STL之priority_queue类源码剖析

目录 概述 算法 源码 PriorityQueue.h test.cpp 测试结果 概述 priority_queue&#xff1a;优先级队列&#xff0c;包含在头文件<queue>中 优先级队列类似于堆结构&#xff0c;优先级最高的元素被置为堆顶&#xff0c;最优先被弹出top()和删除pop() 优先级队列的…

Python凸包

文章目录 ConvexHullQG三维情况ConvexHull属性 ConvexHull ConvexHull是spatial中的一个类&#xff0c;主要功能是找到一组点的边缘&#xff0c;并做一个凸包。其必要的初始化参数为一个点集&#xff0c;点集格式为 n m n\times m nm维度的数组&#xff0c;n为点集中点的个数…

定位的特殊应用

注意&#xff1a;发生固定定位&#xff0c;绝对定位后&#xff0c;元素都变成了定位元素&#xff0c;默认高宽被内容撑开&#xff0c;则可以设置宽高&#xff1b;以下只针对绝对定位和固定定位的元素&#xff0c;不包括相对定位元素。 1.定位元素块的宽充满包含块 前提&#x…

封装建立-SMD封装

1. 看规格书&#xff0c;建立需要的焊盘&#xff0c;命名。注意padstack editor保存路径中不能有中文。 2.新建.dra工程&#xff0c;layout/pin 在里面筛选需要的焊盘。 3. 放置焊盘&#xff0c;需要计算精确坐标&#xff0c;allegro里command用x 0 0命令可以定位到原点。 4…

Python综合案例-学生数据可视化

近年来,数据分析和可视化已经成为了许多领域中的重要工具。在教育领域中,通过对学生的表现和行为进行数据分析和可视化,可以更好地了解学生的学习状态,发现问题、改进教学,并提高学生成绩。本文将介绍一个 Python 综合案例,使用 Pandas 和 Seaborn 库,对学生的数据进行清…

MySQL几种备份方式对比,你用对了吗?

各备份方法对比 备份数据的策略需要根据几种维度考虑 备份能承受最大丢失数据量 备份期间系统可以处于哪种情况&#xff08;不可用&#xff0c;部分可用&#xff0c;完全可用&#xff09; 数据恢复时长 需要恢复全量数据还是增量数据 备份数据的方法 逻辑备份&#xff1a;…

推荐算法实战项目:Deep Crossing 模型原理以及案例实战(附完整 Python 代码)

本文要介绍的Deep Crossing模型是由微软研究院在论文《Deep Crossing: Web-Scale Modeling without Manually Crafted Combinatorial Features》中提出的&#xff0c;它主要是用来解决大规模特征自动组合问题&#xff0c;从而减轻或者避免手工进行特征组合的开销。 Deep Cross…

推荐算法实战项目:DCN 原理以及案例实战(附完整 Python 代码)

本文要介绍的是由斯坦福大学联合Google的研究人员发表的论文《Deep & Cross Network for Ad Click Predictions》中提出的Deep&Cross模型&#xff0c;简称DCN。 DCN模型是Wide&Deep的改进版本&#xff0c;其中Deep部分的设计思路与Wide&Deep没有发生本质的变化…

asp.net基于web的校园美食派送配送系统

1&#xff0e;系统登录&#xff1a;系统登录是用户访问系统的路口&#xff0c;设计了系统登录界面&#xff0c;包括用户名、密码和验证码&#xff0c;然后对登录进来的用户判断身份信息&#xff0c;判断是管理员用户还是普通用户。 2&#xff0e;系统用户管理&#xff1a;不管是…

OpenHarmony JS项目开发流程

一、配置OpenHarmony开发环境 1.1软件需求 1&#xff09;下载并安装好DevEco Studio 2.1 Release及以上版本&#xff0c;下载链接&#xff1a;https://developer.harmonyos.com/cn/develop/deveco-studio#download 2&#xff09;获取OpenHarmony SDK包并解压&#xff0c;下载…

学历不仅是敲门砖,也是我下不来的高台,更是孔乙己脱不下的长衫

学历不仅是敲门砖&#xff0c;也是我下不来的高台&#xff0c;更是孔乙己脱不下的长衫 鲁迅《孔乙己》是一篇具有深刻思想和感人情感的短篇小说&#xff0c;通过酒肆里的故事反映社会的残酷和人性的悲哀&#xff1b; 故事中的孔乙己是一个身世不明、生活贫困的酒鬼&#xff0c…

OpenCV学习小记

OpenCV学习小记 &#x1f388;&#x1f388;记在最前&#x1f388;&#x1f388;图像处理的基本操作✨读取图像✨显示图像✨保存图像✨获取图像属性 &#x1f388;&#x1f388;像素的操作✨像素&#x1f514;获取像素的BGR值&#x1f514;修改像素的BGR值 ✨使用NumPy模块操作…

2023年值得关注的20大网络安全趋势

随着围绕所有企业的数字革命&#xff0c;无论大小&#xff0c;企业、组织甚至政府都依赖计算机化系统来管理他们的日常活动&#xff0c;从而使网络安全成为保护数据免受各种在线攻击或任何未经授权访问的主要目标。 随着数据泄露、勒索软件和黑客攻击的新闻成为常态&#xff0…