需求
部分字段(可能为富文本)需要做敏感词过滤,敏感词词库由产品给出。
前置条件
项目使用的spring cloud全家桶,springboot版本2.1.0 ,项目中集成了spring Data elasticsearch 单独为一个子模块被各个服务引用,elasticsearch 插件版本为6.6.2,并且es插件中已经安装ik中文分词器
设计要求
1、敏感词能精确过滤,速度尽量快
2、如果敏感词有更新,要求能实时更新,并且更新过程尽量简单
实现过程
第一次方案设计
1、把敏感词导入数据库,再把数据库中的敏感词同步至ES
2、如果敏感词有更新,则通过任务调度器把数据同步至ES
3、使用IK分词器对输入文本进行分词,分词结果在ES中进行匹配查找,其中同步至ES的敏感词类型设置为 keyword,查找匹配使用termsQuery等精确匹配
测试结果:
1、ik分词器分词不理想,输入一段文本,由于IK分词器没有按照预期的分词结果进行分词,导致没有过滤出敏感词
2、teamsQuery默认一次只能输入1024个词,超过则会报错,尝试修改ES设置,增大参数,但是按照网上查找的资料设置失败。修复方案为写一个IK分词器工具类,对输入的文本进行分词检查,如果分词结果大于1024个,则去重后分组匹配,最后把结果放入一个list返回
过程要点
设置字段类型为Keyword,设置为keyword类型,则在索引过程中不分再词
@Field(type = FieldType.Keyword)
private String word;
IK分词工具类:
public List<String> getAnalyzes(String index, String analyzer, String text) {
//调用ES客户端分词器进行分词
AnalyzeRequestBuilder ikRequest = new AnalyzeRequestBuilder(elasticsearchTemplate.getClient(),
AnalyzeAction.INSTANCE, index, text).setAnalyzer(analyzer);
List<AnalyzeResponse.AnalyzeToken> ikTokenList = ikRequest.execute().actionGet().getTokens();
// 赋值
List<String> searchTermList = new ArrayList<>();
if (ToolUtil.isNotEmpty(ikTokenList)) {
ikTokenList.forEach(ikToken -> {
searchTermList.add(ikToken.getTerm());
});
}
return searchTermList;
}
匹配方式:
//sensitives = getAnalyzes(...)
QueryBuilder queryBuilder = QueryBuilders.termsQuery("word", sensitives);
QueryBuilder queryBuilder = QueryBuilders.multiMatchQuery(word, "word").analyzer(analyzer).operator(Operator.OR);
term为精确匹配,即不分词,而带match的查询则是先分词,再进行匹配
同步数据至es
@Override
public void fetchFromMysql() {
log.info("从数据库同步敏感词至ES");
list = ;//查询数据库
if (CollectionUtil.isNotEmpty(list)) {
log.info("从数据库中查询