一、敏感词过滤思路
使得互联网纯净,肯定会遇到敏感词过滤,如何认定这个词是敏感词,就尤为重要。比如: 黄色
可不可以认为是一个敏感词,但是天气预报中,也有黄色警报呀。我操
这个肯定是了,但是我 操
中间加个空格呢?加了空格就增加了检测的难度。检测的方式有很多种,使用布隆过滤器可以在简单的情况下,实现快速过滤。
1.分词
如果你好,我要发布一个炸药配方的视频
,需要先对其进行分词
[你好/l, ,/w, 欢迎/v, 使用/v, HanLP/nx, 汉语/nz, 处理/v, 包/v, !/w]
。
2.比对
敏感词库中比如有炸药|枪支
等敏感词。通过hash进行比对即可。这种方式比较简单,但是弊端也很明显,可以通过中间夹杂字符或者空格来绕过,比如炸@药
或者炸!药
,很容易绕过,不过也是可以满足很多场景。
二、代码示例
1.分词示例
引入HanLP工具包来进行分词。
HanLP是一系列模型与算法组成的NLP工具包,目标是普及自然语言处理在生产环境中的应用,可以实现中文分词,词性标注,命名实体识别,关键词提取等功能。
maven添加配置文件
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>28.2-jre</version>
</dependency>
public class Test {
public static void main(String[] args) {
System.out.println(HanLP.segment("你好,我要发布一个炸药配方的视频"));
}
/**
* [你好/l, ,/w, 我/r, 要/v, 发布/v, 一个/mq, 炸药/n, 配方/n, 的/uj, 视频/n]
*/
}
2.验证
分词结束之后,就是通过分词后的信息与敏感词进行比对。
比如认定炸药
是不允许发布的词,则需要将所有的词进行比对即可。
最容易想到的是通过Hashset保存敏感词集合,通过contains方法,判断词是否为敏感词,但是Hashset是通过HashMap来处理的,如果数据量很多,几万条数据插入HashMap中,会使用很多内存。使用布隆过滤器可以更好的减少内存的使用。布隆过滤器详解
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>28.2-jre</version>
</dependency>
import com.google.common.base.Charsets;
import com.google.common.hash.BloomFilter;
import com.google.common.hash.Funnel;
import com.google.common.hash.PrimitiveSink;
import com.hankcs.hanlp.dictionary.CustomDictionary;
import com.hankcs.hanlp.seg.Dijkstra.DijkstraSegment;
import com.hankcs.hanlp.seg.Segment;
import com.hankcs.hanlp.seg.common.Term;
import java.io.*;
import java.util.List;
public class BloomFilterTest {
private BloomFilter<String> configuredFilter;
private final BloomFilter<String> filter = BloomFilter.create(new Funnel<String>() {
private static final long serialVersionUID = 1L;
public void funnel(String arg0, PrimitiveSink arg1) {
arg1.putString(arg0, Charsets.UTF_8);
}
}, 1024*1024*32);
/**
* 读取带敏感词的布隆过滤器
*
* @return
* @throws IOException
*/
public BloomFilter<String> getSensitiveWordsFilter() throws IOException {
InputStreamReader read = null;
BufferedReader bufferedReader = null;
//加载敏感词库
/** 里面的信息
* 出售雷管
* 炸药
* 炸药
* 出售炸药
* 出售炸药 电话
* 制作火药配方
* 炸药出售
* .....此处省略
*/
read = new InputStreamReader(new FileInputStream(new File("C:\\Users\\archermind\\Desktop\\ml-1m\\SensitiveWords.txt")));
bufferedReader = new BufferedReader(read);
for (String txt = null; (txt = bufferedReader.readLine()) != null; ) {
// 将词库信息添加到分词词库
// 如果敏感词库中有 炸药配方 但是分词词库只有 炸药|配方 的话
// 这样会对炸药配方进行分词,无法匹配到 炸药配方
CustomDictionary.add(txt);
// 敏感词库put到布隆过滤器中
filter.put(txt);
}
this.configuredFilter = filter;
return filter;
}
/**
* 判断一段文字中,是否包含敏感词
*/
public Boolean segmentSensitiveFilterPassed(String[] segments) {
if(configuredFilter == null){
try {
getSensitiveWordsFilter();
}catch (IOException e){
e.printStackTrace();
}
}
Segment shortestSegment = new DijkstraSegment().enableCustomDictionary(true);
for(String segment :segments){
List<Term> termList = shortestSegment.seg(segment);
for (Term term :termList){
// 如果布隆过滤器中找到了对应的词,则认为敏感检测不通过
if(configuredFilter.mightContain(term.word)){
System.out.println("检测到敏感词:"+term.word);
throw new RuntimeException("检测到敏感词");
}
}
}
return true;
}
public static void main(String[] args) {
BloomFilterTest service = new BloomFilterTest();
service.segmentSensitiveFilterPassed(new String[]{"你好,我要发布一个炸药配方的小视频"});
}
}
敏感词库下载
https://github.com/jkiss/sensitive-words
https://github.com/tenstone/textfilter/blob/master/keywords