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缓存这些数据,但我感觉是不是弄麻烦了)
  • 相关阅读:
    读Android之大话设计模式--前言和说明
    把二叉树打印成多行
    按之字形顺序打印二叉树
    对称的二叉树
    二叉树的下一个结点
    链表中环的入口结点
    字符流中第一个不重复的字符
    表示数值的字符串
    构建乘积数组
    数组中重复的数字
  • 原文地址:https://www.cnblogs.com/ironPhoenix/p/6048692.html
Copyright © 2011-2022 走看看