针对于数据内容的敏感词过滤经典算法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;
}
}