DFA实现敏感词审查

1.1)需求分析

内容核心有以下内容:

文章审核不能过滤一些敏感词:私人侦探、针孔摄象、信用卡提现、广告代理、代开发票、刻章办、出售答案、小额贷款…

需要完成的功能:

需要自己维护一套敏感词,在文章审核的时候,需要验证文章是否包含这些敏感词

1.2)敏感词-过滤

技术选型

方案 说明
数据库模糊查询 % % 效率太低
String.indexOf(“”)查找 数据库量大的话也是比较慢
全文检索 分词再匹配
DFA算法 确定有穷自动机(一种数据结构)

一、导入工具类

public class SensitiveWordUtil {

    public static Map dictionaryMap = new HashMap<>();

    public static ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock();


    /**
     * 生成关键词字典库
     *
     * @param words
     * @return
     */
    public static void initMap(Collection words) {

        ReentrantReadWriteLock.WriteLock writeLock = reentrantReadWriteLock.writeLock();

        writeLock.lock();
        try {
            if (words == null) {
                System.out.println("敏感词列表不能为空");
                return;
            }

            // map初始长度words.size(),整个字典库的入口字数(小于words.size(),因为不同的词可能会有相同的首字)
            Map map = new HashMap<>(words.size());
            // 遍历过程中当前层次的数据
            Map curMap = null;
            Iterator 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 wordMap = (Map) 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;
        } 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 curMap = dictionaryMap;
        int len = text.length();
        // 从文本的第beginIndex开始匹配
        for (int i = beginIndex; i < len; i++) {
            String key = String.valueOf(text.charAt(i));
            // 获取当前key的下一个节点
            curMap = (Map) 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 matchWords(String text) {
        ReentrantReadWriteLock.ReadLock readLock = reentrantReadWriteLock.readLock();
        readLock.lock();
        try {
            Map 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 map = SensitiveWordUtil.matchWords(content);
        if(map.size() >0){
           //文章中出现了敏感词

//编写业务逻辑代码
            flag = false;
        }

        return flag;
    }

你可能感兴趣的:(工具类,java,微服务)