JAVA使用前綴樹(shù)(Tire樹(shù))實(shí)現(xiàn)敏感詞過(guò)濾、詞典搜索
簡(jiǎn)介
有時(shí)候需要對(duì)用戶輸入的內(nèi)容進(jìn)行敏感詞過(guò)濾,或者實(shí)現(xiàn)查找文本中出現(xiàn)的詞典中的詞,用遍歷的方式進(jìn)行替換或者查找效率非常低,這里提供一個(gè)基于Trie樹(shù)的方式,進(jìn)行關(guān)鍵詞的查找與過(guò)濾,在詞典比較大的情況下效率非常高。
Trie樹(shù)
Trie樹(shù),又叫前綴樹(shù),多說(shuō)無(wú)益,直接看圖就明白了
詞典:[“豬狗”, “小狗”, “小貓”, “小豬”, “垃圾”, “狗東西”]
Tire數(shù)據(jù)結(jié)構(gòu):
code
樹(shù)節(jié)點(diǎn)Node.class
/** * trie tree * * @author lovely dog * @date 2020/10/20 */ public class Node { /** * 子節(jié)點(diǎn) */ private Map<Character, Node> nextNodes = new HashMap<>(); public void addNext(Character key, Node node){ nextNodes.put(key, node); } public Node getNext(Character key){ return nextNodes.get(key); } public boolean isLastCharacter(){ return nextNodes.isEmpty(); } }
搜索類TrieSearcher.class
/** * trie tree searcher * * @author lovely dog * @date 2020/10/20 */ public class TrieSearcher { private Node root = new Node(); /** * 添加詞 * * @param word 詞 */ public void addWord(String word) { Node tmpNode = root; for (char c : word.toCharArray()) { Node node = tmpNode.getNext(c); if (null == node) { node = new Node(); tmpNode.addNext(c, node); } tmpNode = node; } } /** * 替換詞 * * @param text 待處理文本 * @param afterReplace 替換后的詞 * @return 處理后的文本 */ public String replace(String text, String afterReplace) { StringBuilder result = new StringBuilder(text.length()); Node tmpNode = root; int begin = 0, pos = 0; while (pos < text.length()) { char c = text.charAt(pos); tmpNode = tmpNode.getNext(c); if (null == tmpNode) { result.append(text.charAt(begin)); begin++; pos = begin; tmpNode = root; } else if (tmpNode.isLastCharacter()) { // 匹配完成, 進(jìn)行替換 result.append(afterReplace); pos++; begin = pos; tmpNode = root; } else { // 匹配上向后移 pos++; } } result.append(text.substring(begin)); return result.toString(); } /** * 查找 * * @param text 待處理文本 * @return 統(tǒng)計(jì)數(shù)據(jù) key: word value: count */ public Map<String, Integer> find(String text) { Map<String, Integer> resultMap = new HashMap<>(16); Node tmpNode = root; StringBuilder word = new StringBuilder(); int begin = 0, pos = 0; while (pos < text.length()) { char c = text.charAt(pos); tmpNode = tmpNode.getNext(c); if (null == tmpNode) { begin++; pos = begin; tmpNode = root; } else if (tmpNode.isLastCharacter()) { // 匹配完成 String w = word.append(c).toString(); resultMap.put(w, resultMap.getOrDefault(w, 0) + 1); pos++; begin = pos; tmpNode = root; word = new StringBuilder(); } else { // 匹配上向后移 word.append(c); pos++; } } return resultMap; } }
測(cè)試Main.class
public class Main { public static void main(String[] args) { TrieSearcher trieSearcher = new TrieSearcher(); Stream.of("豬狗", "小狗", "小貓", "小豬", "垃圾", "狗東西").forEach(trieSearcher::addWord); String sentence = "你好,小狗,小豬,今天天氣真好。"; System.out.println(trieSearcher.replace(sentence, "***")); System.out.println(trieSearcher.find(sentence)); } }
輸出:
你好,***,***,今天天氣真好。
{小豬=1, 小狗=1}
Benchmark:
replace 1093.517 ns/op
trie 200.042 ns/op
結(jié)論
在僅有短文本和小詞典的情況下,通過(guò)性能測(cè)試可以看出前綴樹(shù)的效率很高,隨著文本和詞典的增長(zhǎng),性能提升會(huì)非常明顯。
到此這篇關(guān)于JAVA使用前綴樹(shù)(Tire樹(shù))實(shí)現(xiàn)敏感詞過(guò)濾、詞典搜索的文章就介紹到這了,更多相關(guān)JAVA前綴樹(shù)敏感詞過(guò)濾內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- JavaEE Filter敏感詞過(guò)濾的方法實(shí)例詳解
- JavaWeb中的filter過(guò)濾敏感詞匯案例詳解
- java利用DFA算法實(shí)現(xiàn)敏感詞過(guò)濾功能
- Java實(shí)現(xiàn)DFA算法對(duì)敏感詞、廣告詞過(guò)濾功能示例
- Java實(shí)戰(zhàn)之敏感詞過(guò)濾器
- Java使用DFA算法實(shí)現(xiàn)敏感詞過(guò)濾的示例代碼
- Java 過(guò)濾器實(shí)現(xiàn)敏感詞匯過(guò)濾功能
- Java數(shù)據(jù)敏感詞轉(zhuǎn)換成符號(hào)的方法詳解
- Java 敏感詞檢測(cè)工具的實(shí)現(xiàn)
相關(guān)文章
Java通過(guò)SMS短信平臺(tái)實(shí)現(xiàn)發(fā)短信功能 含多語(yǔ)言
這篇文章主要為大家詳細(xì)介紹了Java通過(guò)SMS短信平臺(tái)實(shí)現(xiàn)發(fā)短信功能的相關(guān)資料,感興趣的小伙伴們可以參考一下2016-07-07IDEA maven項(xiàng)目中刷新依賴的兩種方法小結(jié)
這篇文章主要介紹了IDEA maven項(xiàng)目中刷新依賴的兩種方法小結(jié),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-03-03Java數(shù)據(jù)類型分類與基本數(shù)據(jù)類型轉(zhuǎn)換
這篇文章主要介紹了Java數(shù)據(jù)類型分類與基本數(shù)據(jù)類型轉(zhuǎn)換,Java的數(shù)據(jù)類型主要分為兩類,基本數(shù)據(jù)類型、引用數(shù)據(jù)類型,下文詳細(xì)介紹,感興趣的朋友可以參考一下2022-07-07關(guān)于spring.factories失效原因分析及解決
這篇文章主要介紹了關(guān)于spring.factories失效原因分析及解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-07-07Java日常練習(xí)題,每天進(jìn)步一點(diǎn)點(diǎn)(25)
下面小編就為大家?guī)?lái)一篇Java基礎(chǔ)的幾道練習(xí)題(分享)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧,希望可以幫到你2021-07-07Spring Boot學(xué)習(xí)入門(mén)之統(tǒng)一異常處理詳解
我們?cè)谧鯳eb應(yīng)用的時(shí)候,請(qǐng)求處理過(guò)程中發(fā)生錯(cuò)誤是非常常見(jiàn)的情況。下面這篇文章主要給大家介紹了關(guān)于Spring Boot學(xué)習(xí)入門(mén)之統(tǒng)一異常處理的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考下。2017-09-09java substring(a)與substring(a,b)的使用說(shuō)明
這篇文章主要介紹了java substring(a)與substring(a,b)的使用說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-10-10Java之SpringBoot集成ActiveMQ消息中間件案例講解
這篇文章主要介紹了Java之SpringBoot集成ActiveMQ消息中間件案例講解,本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07