背景
查询敏感词我这边了解到的有两种方法:
1、使用 contains() 对比是否含有字符串,直接从数据库查询出来敏感词,然后遍历对比。
2、使用反向 like 直接在 MySQL 数据库模糊查询。
以上两种方法在敏感词较少的时候查询速度还不错,但是随着敏感词增多还是会有一定的服务器压力,所以我们就有了 DAF 有穷自动机算法算法。
DAF 算法简介
1、解释:
DFA全称为:Deterministic Finite Automaton,即确定有穷自动机。它是是通过 event 和当前的 state 得到下一个 state ,即 event + state = nextstate。理解为系统中有多个节点,通过传递进入的 event ,来确定走哪个路由至另一个节点,而节点是有限的。
2、构造描述
以下面的例子,我们首先是‘王‘、’八’两个字,然后有个分叉点,分别是‘蛋’、‘羔’、‘子’,首先就是构建敏感词库,这两个敏感词库的 hash 表构造也如下图所示。
代码实现
1、工具类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
| package com.zeno.common.utils;
import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set;
@SuppressWarnings({"unchecked", "rawtypes"}) public class SensitiveFilterUtil {
public static HashMap sensitiveWordMap;
public static void initContext(HashSet<String> set) { initSensitiveWordMap(set); }
private static void initSensitiveWordMap(Set<String> sensitiveWordSet) { sensitiveWordMap = new HashMap<String, String>(sensitiveWordSet.size()); Map<Object, Object> temp; Map<Object, Object> newWorMap; for (String key : sensitiveWordSet) { temp = sensitiveWordMap; for (int i = 0; i < key.length(); i++) { char keyChar = key.charAt(i); Object wordMap = temp.get(keyChar); if (wordMap != null) { temp = (Map) wordMap; } else { newWorMap = new HashMap<>(); newWorMap.put("isEnd", "0"); temp.put(keyChar, newWorMap); temp = newWorMap; } if (i == key.length() - 1) temp.put("isEnd", "1"); } } }
public static boolean contains(String txt) { boolean flag = false; for (int i = 0; i < txt.length(); i++) { int matchFlag = checkSensitiveWord(txt, i); if (matchFlag > 0) { flag = true; } } return flag; }
private static int checkSensitiveWord(String txt, int beginIndex) { boolean flag = false; int matchFlag = 0; char word; Map nowMap = sensitiveWordMap; for (int i = beginIndex; i < txt.length(); i++) { word = txt.charAt(i); nowMap = (Map) nowMap.get(word); if (nowMap != null) { matchFlag++; if ("1".equals(nowMap.get("isEnd"))) { flag = true; } } else { break; } } if (matchFlag < 2 || !flag) { matchFlag = 0; } return matchFlag; }
public static HashSet getSensitiveWord(String txt) { HashSet hashSet = new HashSet(); for (int i = 0; i < txt.length(); i++) { int length = checkSensitiveWord(txt, i); if (length > 0) { hashSet.add(txt.substring(i, i + length)); i = i + length - 1; } } return hashSet; }
public static HashSet checkTxt(String context, HashSet<String> set) { initContext(set); return getSensitiveWord(context); } }
|
2、工具类使用
1 2 3 4 5 6 7 8 9 10 11 12 13
| HashSet<String> set = new HashSet<>();
List<Map> isSensitive = userService.findIsSensitive(username); for (Map is : isSensitive) { set.add(is.getString("sensitive_word")); }
if (StringUtils.isNotEmpty(SensitiveFilterUtil.checkTxt(username, set))) { msg = "用户名包含敏感词,请重新输入"; return msg; }
|