首页 > 编程语言 >SpringBoot-基于DFA算法实现敏感词过滤

SpringBoot-基于DFA算法实现敏感词过滤

时间:2024-10-23 11:18:53浏览次数:3  
标签:Map curMap SpringBoot int text String 算法 DFA wordMap

基于DFA实现敏感词过滤

笔记部分来源自黑马程序员

DFA全称为:Deterministic Finite Automaton,即确定有穷自动机。

存储:一次性的把所有的敏感词存储到了多个map中,就是下图表示这种结构

敏感词:冰毒、大麻、大坏蛋

在这里插入图片描述

检索的过程
在这里插入图片描述

开始实现

1、创建数据库表

CREATE TABLE `sensitive`
(
    `id`           int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
    `sensitives`   varchar(10) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '敏感词',
    `created_time` datetime                               DEFAULT NULL COMMENT '创建时间',
    PRIMARY KEY (`id`) USING BTREE
)

记得在配置文件配置好数据库,还有配置好Mysql和Mybits依赖

2、实体类

@Data
public class Sensitive implements Serializable {
    /**
     * 主键
     */
    private Integer id;

    /**
     * 敏感词
     */
    private String sensitives;

    /**
     * 创建时间
     */
    private Date createdTime;

}

3、DFA工具类(核心)

SensitiveWordUtil

import java.util.*;
public class SensitiveWordUtil {
    public static Map<String, Object> dictionaryMap = new HashMap<>();
    /**
     * 生成关键词字典库
     * @param words
     * @return
     */
    public static void initMap(Collection<String> words) {
        if (words == null) {
            System.out.println("敏感词列表不能为空");
            return ;
        }
        // map初始长度words.size(),整个字典库的入口字数(小于words.size(),因为不同的词可能会有相同的首字)
        Map<String, Object> map = new HashMap<>(words.size());
        // 遍历过程中当前层次的数据
        Map<String, Object> curMap = null;
        Iterator<String> iterator = words.iterator();

        while (iterator.hasNext()) {
            String word = iterator.next();
            curMap = map;
            int len = word.length();
            for (int i =0; i < len; i++) {
                // 遍历每个词的字
                String key = String.valueOf(word.charAt(i));
                // 当前字在当前层是否存在, 不存在则新建, 当前层数据指向下一个节点, 继续判断是否存在数据
                Map<String, Object> wordMap = (Map<String, Object>) curMap.get(key);
                if (wordMap == null) {
                    // 每个节点存在两个数据: 下一个节点和isEnd(是否结束标志)
                    wordMap = new HashMap<>(2);
                    wordMap.put("isEnd", "0");
                    curMap.put(key, wordMap);
                }
                curMap = wordMap;
                // 如果当前字是词的最后一个字,则将isEnd标志置1
                if (i == len -1) {
                    curMap.put("isEnd", "1");
                }
            }
        }

        dictionaryMap = map;
    }

    /**
     * 搜索文本中某个文字是否匹配关键词
     * @param text
     * @param beginIndex
     * @return
     */
    private static int checkWord(String text, int beginIndex) {
        if (dictionaryMap == null) {
            throw new RuntimeException("字典不能为空");
        }
        boolean isEnd = false;
        int wordLength = 0;
        Map<String, Object> curMap = dictionaryMap;
        int len = text.length();
        // 从文本的第beginIndex开始匹配
        for (int i = beginIndex; i < len; i++) {
            String key = String.valueOf(text.charAt(i));
            // 获取当前key的下一个节点
            curMap = (Map<String, Object>) curMap.get(key);
            if (curMap == null) {
                break;
            } else {
                wordLength ++;
                if ("1".equals(curMap.get("isEnd"))) {
                    isEnd = true;
                }
            }
        }
        if (!isEnd) {
            wordLength = 0;
        }
        return wordLength;
    }

    /**
     * 获取匹配的关键词和命中次数
     * @param text
     * @return
     */
    public static Map<String, Integer> matchWords(String text) {
        Map<String, Integer> wordMap = new HashMap<>();
        int len = text.length();
        for (int i = 0; i < len; i++) {
            int wordLength = checkWord(text, i);
            if (wordLength > 0) {
                String word = text.substring(i, i + wordLength);
                // 添加关键词匹配次数
                if (wordMap.containsKey(word)) {
                    wordMap.put(word, wordMap.get(word) + 1);
                } else {
                    wordMap.put(word, 1);
                }
                i += wordLength - 1;
            }
        }
        return wordMap;
    }

}

4、实现业务方法

Mapper

这里用了Mybatis-plus

@Mapper
public interface WmSensitiveMapper {
    @Select("select * from leadnews_wemedia.wm_sensitive")
    List<WmSensitive> getSensitiveAll();
}

开始判断

@Autowired
private SensitiveMapper SensitiveMapper;
// 敏感词审核
private boolean handleSensitiveScan(String content) {
    //从数据库获取所有的敏感词
    List<Sensitive> Sensitives = SensitiveMapper.getSensitiveAll();
    List<String> sensitiveList = Sensitives.stream().map(Sensitive::getSensitives).collect(Collectors.toList());
    //初始化敏感词库
    SensitiveWordUtil.initMap(sensitiveList);
    //查看文章中是否包含敏感词
    Map<String, Integer> map = SensitiveWordUtil.matchWords(content);
    if(map.size() >0)
        return false;
    return true;
}

完成

标签:Map,curMap,SpringBoot,int,text,String,算法,DFA,wordMap
From: https://blog.csdn.net/2301_81717523/article/details/143092825

相关文章