1.1)需求分析
内容核心有以下内容:
文章审核不能过滤一些敏感词:私人侦探、针孔摄象、信用卡提现、广告代理、代开发票、刻章办、出售答案、小额贷款…
需要完成的功能:
需要自己维护一套敏感词,在文章审核的时候,需要验证文章是否包含这些敏感词
1.2)敏感词-过滤
技术选型
方案 | 说明 |
---|---|
数据库模糊查询 % % | 效率太低 |
String.indexOf(“”)查找 | 数据库量大的话也是比较慢 |
全文检索 | 分词再匹配 |
DFA算法 | 确定有穷自动机(一种数据结构) |
一、导入工具类
public class SensitiveWordUtil {public static Map<String, Object> dictionaryMap = new HashMap<>();public static ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock();/*** 生成关键词字典库** @param words* @return*/public static void initMap(Collection<String> words) {ReentrantReadWriteLock.WriteLock writeLock = reentrantReadWriteLock.writeLock();writeLock.lock();try {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标志置1if (i == len - 1) {curMap.put("isEnd", "1");}}}dictionaryMap = map;} finally {writeLock.unlock();}}/*** 搜索文本中某个文字是否匹配关键词** @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) {ReentrantReadWriteLock.ReadLock readLock = reentrantReadWriteLock.readLock();readLock.lock();try {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;} finally {readLock.unlock();}}
}
二、配置启动项,获取敏感词
@PostConstruct //初始化时执行
public void initSensitives(){//获取所有的敏感词//初始化敏感词库SensitiveWordUtil.initMap(sensitiveList);
}
三、审核方法调用
/*** 自管理的敏感词审核* @param content* @param wmNews* @return*/private boolean handleSensitiveScan(String content, WmNews wmNews) {boolean flag = true;//查看文章中是否包含敏感词Map<String, Integer> map = SensitiveWordUtil.matchWords(content);if(map.size() >0){//文章中出现了敏感词//编写业务逻辑代码flag = false;}return flag;}