该文章已同步收录到我的博客网站,欢迎浏览我的博客网站,xhang’s blog
1.DFA算法简介
DFA(Deterministic Finite Automaton) 是一种非递归自动机,也称为确定有穷自动机。它是通过event和当前的state得到nextstate,即event+state=nextstate。
确定:状态以及引起状态转换的事件都是可确定的。
有穷:状态以及引起状态转换的事件的数量都是可穷举的。
对于以下状态转换图:
(S,a) -> U
(S,b) -> V
(U,a) -> Q
(U,b) -> V
(V,a) -> U
(V,b) -> Q
(Q,a) -> Q
(Q,b) -> Q

我们可以将每个文本片段作为状态,例如“匹配关键词”可拆分为“匹”、“匹配”、“匹配关”、“匹配关键”和“匹配关键词”五个文本片段。

过程:
- 初始状态为空,当触发事件“匹”时转换到状态“匹”;
- 触发事件“配”,转换到状态“匹配”;
- 依次类推,直到转换为最后一个状态“匹配关键词”。
再让我们考虑多个关键词的情况,例如“匹配算法”、“匹配关键词”以及“信息抽取”。

可以看到上图的状态图类似树形结构,也正是因为这个结构,使得 DFA 算法在关键词匹配方面要快于关键词迭代方法(for 循环)。
2.Java对DFA算法的实现思路

在Java中实现敏感词过滤的关键就是DFA算法的实现。
我们可以认为,通过S query U、V,通过U query V、P,通过V query U P。通过这样的转变我们可以将状态的转换转变为使用Java集合的查找。
如果有以下词为敏感词:日本人、日本鬼子

这样我们就将我们的敏感词库构建成了一个类似与一颗一颗的树,这样我们判断一个词是否为敏感词时就大大减少了检索的匹配范围。比如我们要判断日本人,根据第一个字我们就可以确认需要检索的是那棵树,然后再在这棵树中进行检索。
但是如何来判断一个敏感词已经结束了呢?利用标识位来判断。
所以对于这个关键是如何来构建一棵棵这样的敏感词树。下面我以Java中的HashMap为例来实现DFA算法。以日本人,日本鬼子为例,具体过程如下:
- 首先获取到根节点HashMap,判断“日”是否存在于根节点当中,如果不存在,则表示该敏感词还不存在。则以“日”为key,创建新的HashMap为value做为根节点。
- 如果存在,则表示已经存在含有以“日”开头的敏感词。设置hashMap = hashMap.get(“日”),接着依次匹配“本”、“人”。
- 判断该字是否为该词中的最后一个字。若是表示敏感词结束,设置标志位isEnd = 1,否则设置标志位isEnd = 0;
3.Java对DFA算法的实现案例
假如以“日本人”和“日本鬼子”为敏感词,以下为实现过程

代码实现:
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public class DFAHashMap {
public void createDFAHashMap(List<String> strings) {
// 1.创建dfaHashMap,此HashMap就表示一个树形结构。
// 指定容量为集合strings的长度,避免dfaHashMap在添加的数据的时候动态扩容
HashMap<String, Object> dfaHashMap = new HashMap<>(strings.size());
// 2.创建temporaryHashMap,用于装载临时HashMap数据
HashMap<String, Object> temporaryHashMap = new HashMap<>(strings.size());
// 3.遍历字符串
for (String string : strings) {
// 3.1对于每个字符串,首个temporaryHashMap就是dfaHashMap,就是树型结构的根节点,
// 即temporaryHashMap首先指向根节点dfaHashMap的内存地址。
temporaryHashMap = dfaHashMap;
// 4.遍历字符串中的每个字符
for (int i = 0; i < string.length(); i++) {
// 5.查询在当前temporaryHashMap当中是否存在当前字符
String word = String.valueOf(string.charAt(i));
HashMap<String, Object> resultHashMap = (HashMap<String, Object>) temporaryHashMap.get(word);
if (resultHashMap == null) {
// 6.如果当前dfaHashMap当中不存在当前字符,就以当前字符为key,新建HashMap作为Value
resultHashMap = new HashMap<String, Object>();
// 6.1由于temporaryHashMap指向的就是dfaHashMap的内存地址,所以dfaHashMap当中存储了该值
temporaryHashMap.put(word, resultHashMap);
}
// 7.将temporaryHashMap的地址指向下一个HashMap
temporaryHashMap = resultHashMap;
// 8.判断是否跳过本次循环
// 如果temporaryHashMap里面已经有isEnd,并且为1,说明时树形结构中已经存在的敏感词,就不再设置isEnd
// 如日本和日本鬼子,先设置日本
// 在日本鬼子设置的时候,本对应的map有isEnd=1,如果这时对它覆盖,就会isEnd=0,导致日本这个关键字失效
if

文章介绍了DFA(确定有穷自动机)的概念,以及它在关键词匹配上的优势。通过一个状态转换图示例,阐述了DFA的工作原理。接着,详细讲解了如何使用Java实现DFA算法,特别是针对敏感词过滤的情况,构建类似于树形结构的敏感词库。最后,给出了具体的Java代码示例和敏感词库初始化及过滤工具类的实现,展示了如何处理多个敏感词并进行替换的过程。
最低0.47元/天 解锁文章
8819

被折叠的 条评论
为什么被折叠?



