敏感词过滤算法DFA
DFA
敏感詞過濾方案
1 使用數(shù)據(jù)庫模糊查詢,效率太低
2 使用String.indexOf("")查找,數(shù)據(jù)庫量大的話也是比較慢
3 把敏感詞和內(nèi)容使用全文檢索(solr,ElasticSearche)技術(shù)進(jìn)行分詞再匹配,也是可以的,但是這種方案比較麻煩。
4 DFA算法,確定有窮自動(dòng)機(jī)。本項(xiàng)目采用這種方案
DFA全稱為:Deterministic Finite Automaton,即確定有窮自動(dòng)機(jī)。其特征為:有一個(gè)有限狀態(tài)集合和一些從一個(gè)狀態(tài)通向另一個(gè)狀態(tài)的邊,每條邊上標(biāo)記有一個(gè)符號(hào),其中一個(gè)狀態(tài)是初態(tài),某些狀態(tài)是終態(tài)。但不同于不確定的有限自動(dòng)機(jī),DFA中不會(huì)有從同一狀態(tài)出發(fā)的兩條邊標(biāo)志有相同的符號(hào)。
- 一次性的把所有的敏感詞存儲(chǔ)到了多個(gè)map中,就是下圖表示這種結(jié)構(gòu)
敏感詞:冰毒、大麻、大壞蛋
- 檢索的過程,就是hashMap的get實(shí)現(xiàn)
1、第一個(gè)字“冰”,我們?cè)趆ashMap中可以找到。得到一個(gè)新的map = hashMap.get("")。
2、如果map == null,則不是敏感詞。否則跳至3
3、獲取map中的isEnd,通過isEnd是否等于1來判斷該詞是否為最后一個(gè)。如果isEnd == 1表示該詞為敏感詞,否則跳至1。
通過這個(gè)步驟我們可以判斷“冰毒”為敏感詞,但是如果我們輸入“冰箱”則不是敏感詞了。
工具類:
import java.util.*;public class SensitiveWordUtil {public static Map<String, Object> dictionaryMap = new HashMap<>();/*** 生成關(guān)鍵詞字典庫* @param words* @return*/public static void initMap(Collection<String> words) {if (words == null) {System.out.println("敏感詞列表不能為空");return ;}// map初始長度words.size(),整個(gè)字典庫的入口字?jǐn)?shù)(小于words.size(),因?yàn)椴煌脑~可能會(huì)有相同的首字)Map<String, Object> map = new HashMap<>(words.size());// 遍歷過程中當(dāng)前層次的數(shù)據(jù)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++) {// 遍歷每個(gè)詞的字String key = String.valueOf(word.charAt(i));// 當(dāng)前字在當(dāng)前層是否存在, 不存在則新建, 當(dāng)前層數(shù)據(jù)指向下一個(gè)節(jié)點(diǎn), 繼續(xù)判斷是否存在數(shù)據(jù)Map<String, Object> wordMap = (Map<String, Object>) curMap.get(key);if (wordMap == null) {// 每個(gè)節(jié)點(diǎn)存在兩個(gè)數(shù)據(jù): 下一個(gè)節(jié)點(diǎn)和isEnd(是否結(jié)束標(biāo)志)wordMap = new HashMap<>(2);wordMap.put("isEnd", "0");curMap.put(key, wordMap);}curMap = wordMap;// 如果當(dāng)前字是詞的最后一個(gè)字,則將isEnd標(biāo)志置1if (i == len -1) {curMap.put("isEnd", "1");}}}dictionaryMap = map;}/*** 搜索文本中某個(gè)文字是否匹配關(guān)鍵詞* @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));// 獲取當(dāng)前key的下一個(gè)節(jié)點(diǎn)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;}/*** 獲取匹配的關(guān)鍵詞和命中次數(shù)* @param text* @return*/public static Map<String, Integer> matchWords(String text) {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);// 添加關(guān)鍵詞匹配次數(shù)if (wordMap.containsKey(word)) {wordMap.put(word, wordMap.get(word) + 1);} else {wordMap.put(word, 1);}i += wordLength - 1;}}return wordMap;}public static void main(String[] args) {List<String> list = new ArrayList<>();list.add("冰毒");initMap(list);String content="我是一個(gè)好人,買賣冰毒是違法的";Map<String, Integer> map = matchWords(content);System.out.println(map);} }總結(jié)
以上是生活随笔為你收集整理的敏感词过滤算法DFA的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 让互联网助小组合作一臂之力
- 下一篇: 深入分析驴子系列(2)