文章目录

  • 准备阶段
    • 为何选用IK Analyzer
    • 什么是布隆过滤器
  • 开发过程
    • 整合Ik
    • 总结

《基于ik分词器和布隆过滤器实现敏感词过滤》首发 牧马人博客转发请加此提示

最近公司业务有个需求,要过滤掉敏感词,涉及到敏感词,我首先就想到了使用分词器以及布隆过滤器来实现它。

准备阶段

对市场上分词器进行了一个调研,目前市场上有很多分词器,比如IkAnalyzer,Hanlp等等。经过一系列的了解我最终选择了’IkAnalyzer’。另外我很快就定位到了BloomFilter(布隆过滤器)这是一个布隆提出的一个算法。他可以高效以及准确的定位到敏感词是否存在。

为何选用IK Analyzer

IK Analyzer是什么呢,一个很轻量的中文分词工具,是基于java(这是我选用的主要原因)开发的轻量级的中文分词工具包。它是以开源项目Luence为主体的,结合词典分词和文法分析算法的中文分词组件。IK有很多版本,在2012版本中,IK实现了简单的分词歧义排除算法。

这里我们采用了网上的一些介绍。

1、IK才用了特有的“正向迭代最细粒度切分算法”,支持细粒度和智能分词两种切分模式。

2、在系统环境:Core2 i7 3.4G双核,4G内存,window 7 64位, Sun JDK 1.6_29 64位 普通pc环境测试,IK2012具有160万字/秒(3000KB/S)的高速处理能力。

3、2012版的只能分词模式支持简单的分词排歧义处理和数量词合并输出。

4、用了多子处理器分析模式,支持 英文字母 数字 中文词汇等

5、优化词典存储,更小的内存占用。

本人实测

上面效率的问题广大网友已经给出了答案,所以我关注的点事,它分词准不准。

由此我对IK Analyzer以及 Hanlp进行了一个对比。

示例:我是一名程序员

Hanlp

long start = System.currentTimeMillis();Segment shortestSegment = new DijkstraSegment().enableCustomDictionary(false).enablePlaceRecognize(true).enableOrganizationRecognize(true);List<Term> termList =  shortestSegment.seg("我是程序员");termList.stream().forEach(term -> {System.out.println(term.word);});System.out.println(System.currentTimeMillis()-start);分词结果:我,是,程序员。耗时:450毫秒

IK Analyzer

start = System.currentTimeMillis();List<String> result = new ArrayList<>();StringReader sr = new StringReader("我是程序员");// 关闭智能分词 (对分词的精度影响较大)IKSegmenter ik = new IKSegmenter(sr, false);Lexeme lex;while(true) {try {if (!((lex=ik.next())!=null)) break;String lexemeText = lex.getLexemeText();System.out.println(lexemeText);result.add(lexemeText);} catch (IOException e) {e.printStackTrace();}}System.out.println(System.currentTimeMillis()-start);分词结果:我,是,程序员,程序,员耗时:500毫秒

结果很显然,IK Analyzer的结果更让我满意。效率而言。IK Analyzer的弱势可以忽略不计差了50毫秒.另外Ik支持自定义词汇。比如上面的例子我是他是分开的,我们可以使用他的扩展词典功能强行把我是变成我们要的词语。具体下文在说。

什么是布隆过滤器

网上一些言论:

布隆过滤器(Bloom Filter)是1970年由布隆提出的。它实际上是一个很长的二进制向量(位图)和一系列随机映射函数(哈希函数)。
布隆过滤器可以用于检索一个元素是否在一个集合中。它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率和删除困难。

本质上布隆过滤器是一种*数据结构,比较巧妙的概率型数据结构(probabilistic data structure),特点是高效地插入和查询,可以用来告诉你 “某样东西一定不存在或者可能存在”。

相比于传统的 List、Set、Map 等数据结构,它更高效、占用空间更少,但是缺点是其返回的结果是概率性的,而不是确切的。

抓重点:数据结构,空间效率和查询时间都远远超过一般的算法

具体的原理往这看布隆过滤器原理

开发过程

技术选型完毕,这个功能的本质上就是在布隆过滤器中使用IKf分词,然后判断是否存在敏感词。

整合Ik

pom文件


<dependency><groupId>com.janeluo</groupId><artifactId>ikanalyzer</artifactId><version>2012_u6</version><exclusions><exclusion><groupId>org.apache.lucene</groupId><artifactId>lucene-core</artifactId></exclusion><exclusion><groupId>org.apache.lucene</groupId><artifactId>lucene-queryparser</artifactId></exclusion><exclusion><groupId>org.apache.lucene</groupId><artifactId>lucene-analyzers-common</artifactId></exclusion></exclusions></dependency><!--  lucene-queryparser 查询分析器模块 --><dependency><groupId>org.apache.lucene</groupId><artifactId>lucene-queryparser</artifactId><version>7.3.0</version></dependency>

在resource目录下创建以下文件

IKAnalyzer.cfg.xml (IK Analyzer 扩展配置)

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties><comment>IK Analyzer 扩展配置</comment><entry key="ext_dict">/extend.dic</entry><entry key="ext_stopwords">/stopword.dic</entry>
</properties>

extend.dic(扩展字典)

我是
你是傻逼

这个就是你要扩展的词典,本来我是不是一个词语,但是如果你这里扩展了,那么他就会匹配这个词语。

stopword.dic(断点)

的
一

如果在分词过程中遇到类似关键字会分割。所以我把他解释为断点更为合适。

布隆过滤器结合Ik进行过滤


import com.alibaba.druid.util.StringUtils;
import com.google.api.client.util.Charsets;
import com.google.api.client.util.Lists;
import com.google.common.hash.BloomFilter;
import com.google.common.hash.Funnel;
import com.google.common.hash.PrimitiveSink;
import com.hankcs.hanlp.seg.Dijkstra.DijkstraSegment;
import com.hankcs.hanlp.seg.Segment;
import com.hankcs.hanlp.seg.common.Term;
import lombok.extern.slf4j.Slf4j;
import org.wltea.analyzer.core.IKSegmenter;
import org.wltea.analyzer.core.Lexeme;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;/*** @CLASSNAME BloomFilterHanlp 布隆过滤器使用hanlp分词* @Description* @Auther kangning @www.luckyhe.com* @DATE 2020/8/20 0020 16:43*/@Slf4j
public class BloomFilterHanlp {private BloomFilter<String> configuredFilter;private final BloomFilter<String> filter = BloomFilter.create(new Funnel<String>() {private static final long serialVersionUID = 1L;@Overridepublic 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(this.getClass().getClassLoader().getResourceAsStream("SensitiveWords.txt"), StandardCharsets.UTF_8);bufferedReader = new BufferedReader(read);for (String txt = null; (txt = bufferedReader.readLine()) != null; ) {filter.put(txt);}this.configuredFilter = filter;return filter;}/*** 读取带敏感词的布隆过滤器根据指定关键字** @return* @throws IOException*/public BloomFilter<String> getSensitiveWordsFilter(List<String> words) throws IOException {words.stream().forEach(word->{filter.put(word);});this.configuredFilter = filter;return filter;}/*** 判断一段文字中,是否包含敏感词** @param segment* @return*/public Boolean segmentSensitiveFilterPassed(String segment) {if(configuredFilter == null){try {List<String> word=new ArrayList<>(10);word.add("程序");getSensitiveWordsFilter(word);}catch (IOException e){e.printStackTrace();}}Segment shortestSegment = new DijkstraSegment().enableCustomDictionary(false).enablePlaceRecognize(true).enableOrganizationRecognize(true);List<Term> termList =  shortestSegment.seg(segment);for (Term term :termList){// 如果布隆过滤器中找到了对应的词,则认为敏感检测不通过if(configuredFilter.mightContain(term.word)){log.info("检测到敏感词:"+term.word);throw new RuntimeException("检测到敏感词");}}return true;}/*** 判断一段文字中,是否包含敏感词** @param segment* @return*/public Boolean segmentSensitiveFilterPassedIk(String segment) {if(configuredFilter == null){try {List<String> word=new ArrayList<>(10);word.add("程序");getSensitiveWordsFilter(word);}catch (IOException e){e.printStackTrace();}}List<String> result = new ArrayList<>();StringReader sr = new StringReader(segment);// 关闭智能分词 (对分词的精度影响较大)IKSegmenter ik = new IKSegmenter(sr, false);Lexeme lex;while(true) {try {if (!((lex=ik.next())!=null)) break;String lexemeText = lex.getLexemeText();result.add(lexemeText);} catch (IOException e) {e.printStackTrace();}}for (String term :result){// 如果布隆过滤器中找到了对应的词,则认为敏感检测不通过if(configuredFilter.mightContain(term)){log.info("检测到敏感词:"+term);throw new RuntimeException("检测到敏感词");}}return true;}public static void main(String[] args) {long start = System.currentTimeMillis();List<String> result = new ArrayList<>();StringReader sr = new StringReader("我是程序员");// 关闭智能分词 (对分词的精度影响较大)IKSegmenter ik = new IKSegmenter(sr, false);Lexeme lex;while(true) {try {if (!((lex=ik.next())!=null)) break;String lexemeText = lex.getLexemeText();System.out.println(lexemeText);result.add(lexemeText);} catch (IOException e) {e.printStackTrace();}}System.out.println(System.currentTimeMillis()-start);BloomFilterHanlp filterHanlp=new BloomFilterHanlp();filterHanlp.segmentSensitiveFilterPassedIk("我是程序员");}}

总结

关于布隆过滤器在敏感词过滤这块有很多应用,但其实hashMap也是可以完成这个需求的,hashMap的效率也很高的,但是hash有个扩容的问题,如果你的数据量很大,那么不推荐,但是如果你只是很小的数据量。其实hashMap也是不错的东西。有兴趣的同学可以对比下。我这边就撤了加班去了淦。

基于ik分词器和布隆过滤器实现敏感词过滤相关推荐

  1. 基于布隆过滤器实现敏感词识别和过滤

    在当前的网络环境下,敏感词过滤已经是各大网站的"标准配置",如果不想被大量的垃圾信息充斥,除了使用机器人识别.验证码等验证工具,还需要阻止含有敏感词内容的发布,否则可能面临关站等风 ...

  2. ik mysql热加载分词_Elasticsearch 之(25)重写IK分词器源码来基于mysql热更新词库...

    热更新在上一节< IK分词器配置文件讲解以及自定义词库>自定义词库,每次都是在es的扩展词典中,手动添加新词语,很坑 (1)每次添加完,都要重启es才能生效,非常麻烦 (2)es是分布式的 ...

  3. es ik分词热更新MySQL,ElasticSearch(25)- 改IK分词器源码来基于mysql热更新词库

    代码地址 已经修改过的支持定期从数据库中提取新词库,来实现热更新.代码: https://github.com/csy512889371/learndemo/tree/master/elasticse ...

  4. 31_ElasticSearch 修改IK分词器源码来基于mysql热更新词库

    31_ElasticSearch 修改IK分词器源码来基于mysql热更新词库 更多干货 分布式实战(干货) spring cloud 实战(干货) mybatis 实战(干货) spring boo ...

  5. elasticsearch学习(六):IK分词器

    1.IK分词器简介 IKAnalyzer是一个开源的,基于java语言开发的轻量级的中文分词工具包.从2006年12月推出1.0版开始IKAnalyzer已经推出 了3个大版本.最初,它是以开源项目L ...

  6. FlinkSQL使用自定义UDTF函数行转列-IK分词器

    一.背景说明 优惠券网 www.cps3.cn 本文基于IK分词器,自定义一个UDTF(Table Functions),实现类似Hive的explode行转列的效果,以此来简明开发过程. 如下图Fl ...

  7. ElasticSearch ik分词器从MySQL里面获取分词信息

    出自 中华石杉 老师的一个课程, 缘由 每次都是在es的扩展词典中,手动添加新词语,很坑 (1)每次添加完,都要重启es才能生效,非常麻烦 (2)ElasticSearch是分布式的,可能有数百个节点 ...

  8. ik分词器 分词原理_ElasticSearch 集成Ik分词器

    1 . 由于 ElasticSearch 默认的分词器不支持中文分词,所以我们需要集成IK 分词器. 2. 集成步骤 https://github.com/medcl/elasticsearch-an ...

  9. requirednew基于xml配置日志不回滚_Elasticsearch配置IK分词器的远程词库

    在生活中很多很多地方都涉及到了全文检索,最常见的就好比日常使用到的百度搜索等搜索引擎,也都是基于全文检索来实现的:全文检索种类较多,就好比Elasticsearch.Sorl等. 为Ealsticse ...

最新文章

  1. 设计模式之观察者模式(Observer)摘录
  2. 脑机交互研究及标准化实践
  3. 5.6 SMO-机器学习笔记-斯坦福吴恩达教授
  4. Intellij idea requested without authorization请求页面未经授...
  5. [Flink] The file LOG does not exist on the TaskExecutor
  6. linux下创建用户,给用户设置密码,给用户授权
  7. JavaScript嵌套函数this的指向问题
  8. sensor_msgs::PointCloud2转换pcl::PCLPointCloud2 pcl::PointXYZ
  9. 阶段3 2.Spring_03.Spring的 IOC 和 DI_3 spring基于XML的IOC环境搭建和入门
  10. python实现语音机器人
  11. 机器学习算法竞赛实战-学习总结
  12. css 左右居中和上下垂直居中
  13. 新人做ASO如何快速写好关键词?
  14. GIS制图人员的自我修养(1)--制图误区
  15. 商品订单(增删改查):新增订单;批量删除,发货;模糊查询,下拉菜单内容过滤(含时间);全选反选,列名排序
  16. 『拓扑排序』「NOI2010」航空管制
  17. Unity-使用UPR资源检测工具AssetChecker-Win进行本地资源检测
  18. 茶叶文化网站设计与实现 HTML+CSS学生网页设计作业源码
  19. Habor镜像仓库的搭建
  20. FFmpeg入门详解之116:rtsp live555摄像头直播

热门文章

  1. 挑战杯大赛优秀作品示例_图像分类比赛tricks:华为云人工智能大赛·垃圾分类挑战杯...
  2. 2021年MathorCup高校数学建模挑战赛b题:三维团簇的能量预测(三等)
  3. CLRS第二章思考题
  4. 【JAVA程序设计】(C00043)基于SSM非maven的人事管理系统
  5. 高校实验室安全考试题库 辅助软件
  6. 哈夫曼编码-Java实现
  7. 2022年宜昌中级职称评审必须要有助理工程师吗?甘建二
  8. STM32-通用定时器-定时器中断
  9. 《PMPBOK》第七版发布了
  10. CentOS镜像文件下载