zoukankan      html  css  js  c++  java
  • 过滤敏感词方式

    一、利用正则表达式

    关键正则表达式

    .*(关键词1|关键词2|关键词3).*

    模拟业务代码

    @WebServlet(name = "PatternControl", urlPatterns = {"/p"})
    public class PatternControl extends HttpServlet {
        private static final Pattern pattern = initPattern();
    
        private static Pattern initPattern() {
            List<String> stringList = null;
            try {
                stringList = Files.readAllLines(Paths.get("/Users/hans/Documents/word.txt"));
            } catch (IOException e) {
                e.printStackTrace();
            }
            StringBuilder stringBuilder = new StringBuilder(".*(");
            stringBuilder.append(stringList.get(0));
            for (int i = 1; i < stringList.size(); i++) {
                stringBuilder.append("|" + stringList.get(i));
            }
            stringBuilder.append(").*");
            Pattern pattern = Pattern.compile(stringBuilder.toString());
            return pattern;
        }
    
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            if (pattern == null) {
                response.sendError(500, "pattern is null");
                return;
            }
            if (request.getParameter("word") == null) {
                response.sendError(500, "word is null");
                return;
            }
            boolean isMatcher = pattern.matcher(request.getParameter("word")).matches();
            if (isMatcher) {
                response.sendError(209);
            } else {
                response.sendError(409);
            }
        }
    
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            doPost(request, response);
        }
    }

    时间空间占用情况

    前提

    关键词共有28448个,将其编译成上述的正则表达式

    CPU2.2GHz Intel i7四核
    内存

    16GB 1600 MHz DDR3

    时间情况(多次实验平均结果)

    阶段耗时(ms)
    初始化

    读取敏感词:38

    编译正则表达式:41

    每次匹配 47

    空间情况(多次实验平均结果)

    阶段消耗内存(MB)
    初始化 编译正则表达式 11
    每次匹配 极小

    cpu和堆运行时情况图

    结论 

    利用正则表达式过滤敏感词效果较好

    二、利用字符串暴力匹配

    核心思路

    循环总共关键词个数次,判断时候在待匹配字符串中 是否包含 本次循环的关键词

    模拟业务代码

    @WebServlet(name = "PatternControl", urlPatterns = {"/p"})
    public class PatternControl extends HttpServlet {
        private static final List<String> stringList = initStringList();
    
        private static List<String> initStringList() {
            List<String> stringList = null;
            try {
                stringList = Files.readAllLines(Paths.get("/Users/hans/Documents/word.txt"));
            } catch (IOException e) {
                e.printStackTrace();
            }
            return stringList;
        }
    
        private boolean matchKeyWord(String text) {
            for (String markWord : stringList) {
                if (text.contains(markWord)) {
                    return true;
                }
            }
            return false;
        }
    
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            if (request.getParameter("word") == null) {
                response.sendError(500, "word is null");
                return;
            }
            boolean isMatcher = matchKeyWord(request.getParameter("word"));
            if (isMatcher) {
                response.sendError(209);
            } else {
                response.sendError(409);
            }
        }
    
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            doPost(request, response);
        }
    }

    时间空间占用情况 

    时间情况(多次实验平均结果)

    阶段耗时(ms)
    初始化

    读取敏感词:38

    每次匹配 10

    空间情况(多次实验平均结果)

    阶段消耗内存(MB)
    初始化 3
    每次匹配 极小

    结论 

    利用暴力匹配的效果更好

    三、利用Tire树匹配

    核心思路

    将所有的敏感词构成一棵路径树,每个节点只有一个字符

    模拟业务代码

    public class TestAcWithoutFail {
        public void insert(String str, Node root) {
            Node p = root;
            for (char c : str.toCharArray()) {
                if (p.childrenNodes.get(c) == null) {
                    p.childrenNodes.put(c, new Node());
                }
                p = p.childrenNodes.get(c);
            }
            p.isEnd = true;
        }
    
        public boolean isContainSensitiveWord(String text, Node root) {
            for (int i = 0; i < text.length(); i++) {
                Node nowNode = root;
                for (int j = i; j < text.length(); j++) {
                    char word = text.charAt(j);
                    nowNode = nowNode.childrenNodes.get(word);
                    if (nowNode != null) {
                        if (nowNode.isEnd) {
                            return true;
                        }
                    } else {
                        break;
                    }
                }
            }
            return false;
        }
        public String containSensitiveWord(String text, Node root) {
        		for (int i = 0; i < text.length(); i++) {
            		Node nowNode = root;
            		for (int j = i; j < text.length(); j++) {
                		char word = text.charAt(j);
                		nowNode = nowNode.childrenNodes.get(word);
                		if (nowNode != null) {
                    		if (nowNode.isEnd) {
                        	return text.substring(i, j + 1);
                    		}
                		} else {
                    		break;
               		}
            	}
        	}
        	return "";
    	}
    
    
        public static void main(String[] args) throws IOException, InterruptedException {
            List<String> stringList = Files.readAllLines(Paths.get("/Users/hans/Documents/word.txt"));
            TestAcWithoutFail acNoFail = new TestAcWithoutFail();
            Node root = new Node();
            for (String text : stringList) {
                acNoFail.insert(text, root);
            }
            String string = "tiresdfsdffffffffffaaaaaaaaaa";
            Thread.sleep(10 * 1000);
            for (int i = 0; i < 1; i++) {
                System.out.println(acNoFail.isContainSensitiveWord(string, root));
            }
        }
    }
    
    class Node {
        Map<Character, Node> childrenNodes = new HashMap<>();
        boolean isEnd;
    }

    时间空间占用情况 

    时间情况(多次实验平均结果) 

    阶段耗时(ms)
    初始化

    读取敏感词:38

    构建比较树:36

    每次匹配 0.01量级(执行1000遍34ms、执行10000遍130ms) 

    空间情况(多次实验平均结果)

    阶段消耗内存(MB)
    初始化

    读取字符串:3

    构建比较树:24

    每次匹配 极小

    结论 

    在该业务中和暴力匹配效果哪个好值得商榷

    四、服务部署方式

    主站的做法(刘乐那边的做法一样)

    • 单独部署一台服务器
    • 将关键词放到一张表中
    • 设置定时任务每天初始化一次

    我的方案

    • 将关键词放到一张表中
    • 设置定时任务每天初始化一次(其实感觉每天更新都挺浪费的,写个接口,表中数据改了之后,调用一下就可以)
    • 多台机器上每个机器都每天读取一次数据库,解决同步的问题(或者用Tair缓存这些数据,但我感觉是不是弄麻烦了)
  • 相关阅读:
    sqlplus时报Linux-x86_64 Error: 13: Permission denied
    thrift之TTransport层的缓存传输类TBufferedTransport和缓冲基类TBufferBase
    Java实现 蓝桥杯 算法提高 新建Microsoft world文档
    Java实现 蓝桥杯 算法提高 新建Microsoft world文档
    Java实现 蓝桥杯 算法提高 快乐司机
    Java实现 蓝桥杯 算法提高 快乐司机
    Java实现 蓝桥杯 算法提高 队列操作
    Java实现 蓝桥杯 算法提高 队列操作
    Java实现 蓝桥杯 算法提高 文本加密
    Java实现 蓝桥杯 算法提高 合并石子
  • 原文地址:https://www.cnblogs.com/ironPhoenix/p/6048692.html
Copyright © 2011-2022 走看看