针对于数据内容搜索匹配个数以及敏感词过滤的经典方法

针对于数据内容的敏感词过滤经典算法DFA分析详解

例如目前我开发的业务文档内容需要一定的审核,才能上传到文档库里,所以这些敏感字段不允许出现在文档里面的,一经发现需要追溯上传人。。。等,,所以今天这个就是怎么让敏感词高效率的处理让时间和空间复杂度降低的算法 dfa
在这里插入图片描述

原因:
1.使用数据库针对数据内容进行全局模糊搜索的效率太低 或者String.indexOf(“”) 当数据量大也是非常慢的

​ 2.针对于敏感词和全文检索放在一块ElasticSearch 分词再匹配的话也可行,但是此方案较为麻烦

​ 3. DFA算法 确定有穷自动机 比较适合敏感词类型业务

有一个有限的带状态的集合和一些从一个状态通向另一个状态的边 ,每条边上标记一个符号,其中一个状态是初态,一些状态结束态

{
	"大"{
		"傻"{
			"春"{	
				"isEnd": "1"
			}
			"isEnd": "0"
		},
		 {
			"麻"{
				"isEnd": "1"
			}
		}
		"isEnd""0"
	}
}
package org.example.demopoi.util;

import java.util.*;

/**
 * @version 1.0
 * @Author jjjjjjjjava
 * @Date 2024/7/23 10:05
 */
public class DFA {

    public static void main(String[] args) {

        List<String> list = new ArrayList<>();

        list.add("大麻");
        list.add("草泥马");
        list.add("妈的");
        initMap(list);
        String content="我草泥马,你他妈的卖大麻";
        Map<String, Integer> map = matchWord(content);
        System.out.println("map = " + map);
    }

    private static Map<String, Object> dictMap = new HashMap<>();

    /**
     * @version 1.0
     * @Author jjjjjava
     * @Date 2024/7/23 10:05
     * //初始化生成敏感词字典库
     */
    private static void initMap(Collection<String> words) {

        if (words == null || words.size() == 0) {

            System.out.println("敏感词列表不能为空");

            return;
        }

        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");
                }
            }

        }
        dictMap = map;
    }

    private static int checkWord(String text, int beginIndex) {
        //敏感词结束标识位,用于敏感词只有1位的情况
        boolean flag = false;
        //匹配到的敏感字个数,也就是敏感词长度
        int length = 0;
        //从根Map开始查
        Map nowMap = dictMap;
        for (int i = beginIndex; i < text.length(); i++) {
            //被判断语句的第i个字符开始
            String key = String.valueOf(text.charAt(i));
            //获取指定的key,并将敏感词库指针指向下级Map
            nowMap = (Map) nowMap.get(key);
            if (nowMap != null) { //存在,则判断是否为最后一个
                //找到相应的key,匹配长度+1
                length++;
                if ("1".equals(nowMap.get("isEnd"))) {
                    flag = true;
                }
            } else {
                //敏感库不存在 跳出
                break;
            }
        }
        if (length < 2 || !flag) {
            length = 0;
        }
        return length;
    }

    /**
     * @version 1.0
     * @Author jjjjjava
     * @Date 2024/7/23 10:05
     * //获取匹配的关键字和命中次数
     */

    public static Map<String, Integer> matchWord(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;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值