导读:咱们在实现检测一个字符串是否包含另外一个字符串时,简单的用一个字符串匹配算法就能够实现,若是要实现检测一个字符串是否包含 N 个字符串时,这个 N 有可能上千万,再利用简单的字符串匹配算法就无法知足咱们的需求了,上千万的词须要能够灵活的维护,业务方匹配时可以拿到本身的词进行匹配,千万词的匹配须要保证匹配速度,要在秒级以内出结果。因此,咱们须要一套解决此类问题的方案——词表服务 。mysql
全文5370字,预计阅读时间 12分钟。算法
1、背景
内容审核平台须要检测做者发的文章中是否含有特殊的敏感词。对于不一样的业务线对这些词的要求也不一样,有的严格有的宽松;有的须要单词,有的须要多词;有的须要检测出隐含词、变体词;有的在标题生效,有的在正文生效;有的检测出送人审,有的检测出直接拒绝;有的须要几千词,有的须要上万、百万、甚至千万词。对于这些词各业务线能够本身维护,方便增长、删除、修改,各业务能够根据本身的需求配置词的生效规则;在检测的时候业务方能够拿到本身维护的词对文章进行检测,并且须要保证检测的时效,可以实时拿到检测结果。sql
2、架构
上图是词表服务的总体架构:数据库
(1)词表管理:各业务线在词表管理平台维护本身的词表,每一个业务线能够添加多个词表组,每一个词表组中能够维护敏感词以及能够动态添加敏感词的属性;词表管理平台用ES实现了对词表及上千万词高效的分词检索能力;词表管理会定时生成各业务线的词表BOS文件,上传到BOS服务。缓存
(2)服务层:业务方调用词表服务统一对外的匹配接口,服务层将匹配任务送到策略算子层,完成词表的匹配功能。词表对外的统一服务至关于一个简单的网关,提供了鉴权功能,验证请求是否合法;提供了流量限制的功能,能够为每一个请求方设置流量限制值;提供告终果处理的功能,策略算子返回的敏感词属性只是一部分,根据业务方的需求,能够完善策略算子返回的敏感词属性;提供了流量转发的功能,能够根据配置将各业务线的请求打到不一样的集群,实现各业务策略算子分集群部署。多线程
(3)策略算子层:策略算子实现对文本中敏感词的匹配,匹配的模式有包含匹配、强过滤匹配、多模匹配,命中的敏感词会返回给词表服务层。各业务线的词表会被策略的每一个算子用全量刷新的方式或者实时同步增量数据的方式加载到内存,支持算子的匹配功能。全量刷新的方式:词表管理平台会定时将词表分业务线生成BOS文件,上传到 BOS 服务,策略算子定时从BOS文件中同步敏感词到内存;实时同步的方式:策略算子会实时扫描刺词表数据库,将增量的词表加载到内存。架构
(4)基础服务:GDP框架实现了词表服务开发,Pandora平台实现了词表服务的部署,mysql 实现了词表数据的存储,ES实现了词表的分词检索,bdrp实现了限流及缓存功能,BOS服务实现了词表文件的的传输。框架
3、词表管理平台
词表管理平台,实现了各业务线维护本身的词表,每一个业务线下能够建立多个词表组,方便业务方分类管理本身的敏感词,每一个词表组的含义由业务方赋予,具体体如今当命中的敏感词属于这个词表组的时候,业务方是否根据词表组作不一样的处置;每一个词表组下能够维护敏感词,敏感词的属性由业务方本身选择,例如,审核类型这个属性,业务方能够根据命中具体某个敏感词后要送审,就选择送审词这个属性值,若是要拒绝就选择拒绝词这个属性值。微服务
3.1词表管理
各业务线能够添加、修改的词表,能够对词表进行检索。优化
(1)新增词表,选择属于的业务线,添加名字和备注,能够一次将词表建立到多个业务线下,若是其余业务线有词表能够复用,也可直接将其余业务线的词表拷贝到本身新建的词表下,方便快捷,方便管理人员对词表的管理。如图1:
(1)修改词表,能够修改词表的名字、备注,能够将词表从新指定业务线,若是其余业务线有词表能够复用,也可直接将其余业务线的词表拷贝到本身的词表下,方便快捷,方便管理人员对词表的管理。如图2:
(2)词表检索,支持经过词表ID、词表名称、业务线以及建立的时间检索词表;词表名称的检索,利用了 ES 的特性能够实现对词表名称进行分词检索;在检索到的列表中,能够看到词表的id、词表名称、业务线、词表的建立时间、更新时间、每一个词表下的词条数量、词表备注、词表的生效状态操做人等词表属性;能够在列表中状态中点击,将词表改为生效或失效状态;在操做栏能够点击修改,修改词表,点击追加给词表添加词,点击查看查看词表的详情信息。如图3:
3.2敏感词维护
在词表中能够高效快捷的维护敏感词。重要的敏感词的属性包含:
(1) 词条类型:标识敏感词是送审词仍是过滤词;
(2) 敏感类型:标识词条的敏感分类;
(3) 匹配模式:包含匹配-检测本文中是否包含敏感词,强过滤匹配-检测文本中汉字、字母、数字、特殊字符相互组合后是否包含敏感词,多模匹配-检测文本中是否命中2个或3个词,且多个词间距在有效范围内。
(4) 生效位置:敏感词在文章中的生效位置,如,标题、正文、图片中给的文字等。
(5) 豁免词:包含匹配中敏感词的属性,若是敏感词是A,豁免词是B,文本中有AB词,则敏感词A不会命中。
(6) 延展策略:多模位置置换-若是有多模词AB,文本中有词BA,则能够命中AB敏感词;字母大小写转换-忽略大小写,若是敏感词是cd,文本中有cD、Cd、CD词,则均可命中cd词。
(7) 失效时间:提供了长期有效和具体失效时间两种选择。
敏感词维护提供了单条添加、批量添加、单条修改、批量修改、词表检索、词条检索等功能:
(1)单条追加,追加的词表名称已经肯定,业务方能够根据本身的业务选择词的属性,追加中的操做,若是词的匹配模式属性选择了包含词,能够添加这个词的豁免词。如图4:
(2)批量添加,支持同步最大一次添加3000条,能够同时添加到不一样业务线的不一样的词表中,方便快捷,方便了管理员对敏感词的维护工做,要添加的全部的敏感词属性必须一致才可使用此功能,二期不支持给包含词添加豁免词属性,能够在敏感词输入框中换行输入多条。如图5:
(3)批量建立,业务方能够根据本身的业务将敏感词及属性维护到EXCEL表中,每一个文件最大支持3万词,提交后,能够生成一个建立任务,后台运行,同时能够建立多个任务,执行的时候是顺序执行,如图6:
(3)单条修改,能够修改词条的任意属性,若是敏感词是同步批量添加的包含词,想要添加敏感词的豁免词能够在这里修改。如图7:
(3)批量修改,业务方能够根据本身的业务将敏感词及要修改的属性维护到EXCEL表中,每一个文件最大支持3万词,提交后,能够生成一个更新任务,后台运行,同时能够建立多个更新任务,执行的时候是顺序执行。如图8::
(4)敏感词检索,能够根据敏感词的审核类型、匹配模式、生效位置、敏感类型、操做人、所属业务线、所属词表、敏感词的建立时间等属性检索,敏感词的检索使用了ES分词检索的特性,能够支持分词检索,也能够实现精确检索;检索的列表中展现了敏感词的名称、所属业务线、所属词表、操做人、操做时间、备注等字段,能够查看整体数量,能够导出,批量解除,操做栏中,能够点击修改,进入修改页面,能够点击解除,解除此条敏感词。如图9:
4、词表服务统一入口
词表服务统一入口,提供了标准的 API 接口,业务方调用词表服务统一对外的匹配接口,服务层将匹配任务送到策略算子层,完成词表的匹配功能。词表对外的统一服务至关于一个简单的网关,提供了鉴权功能,验证请求是否合法;提供了流量限制的功能,能够为每一个请求方设置流量限制值;提供告终果处理的功能,策略算子返回的敏感词属性只是一部分,根据业务方的需求,能够完善策略算子返回的敏感词属性;提供了流量转发的功能,能够根据配置将各业务线的请求打到不一样的集群,实现各业务策略算子分集群部署。具体的流程,如图10。
5、策略加载词表
策略加载词表通过多方案的迭代,方案最终逐渐成熟稳定。
初版词表在策略的生效方案:词表管理平台将全部的业务线的词表生成一个词表文件,上传到BOS,词表策略30min定时扫描加载一次。全部业务线集中到一个词表文件中,一次加载,致使了策略加载词表速度慢。
第二版的方案,30分钟生效时间后来不能知足业务方的需求,词表管理平台按照业务线生成多个词表文件,推送到BOS系统,词表策略定时,分业务线开启多线程加载词表,词表生效时间由 30min 减小到5分钟。
单三版方案,5min钟时间对于特殊场景仍是不知足,咱们增长了词表实时同步方案,由词表策略10s定时去数据库扫描增量的数据加载到内存,可是这种方案不适合上万的增量数据加载,只适合万级之内词的加载。
如今词表策略加载词表,第二版和第三版同时存在,优点互补,整个演变过程如图11:
BOS文件格式,多列用制表符分割,多模词用 & 符号链接,包含词添加前缀+号识别,主要的信息有敏感词id、敏感词名称、敏感词所属词表id、多模词词间距、失效时间、审核类型、匹配类型、所属业务线、生效位置、敏感类型、延展策略、豁免词。如图12:
全量加载和增量实时同步加载流程,全量加载会在启动的时候加载一次,加载的频率半个小时以上,能够根据业务线配置;增量实时同步10s中去数据库检测一次是否有增量数据,而后分页加载到内存。如图13:
策略缓存词表到内存的加载结构,以下:
(1)业务线、生效位置,敏感词,敏感词id 字典映射。匹配到敏感词,能够根据业务线,生效位置,快速的找到敏感词的id,经过敏感词的 id 再获取敏感词的属性规则,用于计算匹配到的敏感词是否有效。如图14:
(2)敏感词id及敏感词属性规则字典映射,BOS文件每行敏感词处理存储。经过敏感词ID可以快速查到敏感词的属性规则,用于计算匹配到的敏感词是否有效。如图15:
(3)敏感词挂在到字典树(Trie树),每一个业务线、生效位置生成一个字典树,字典树是词表策略的核心,上千万的敏感词匹配能在10ms之内返回配置结果。如图16:
6、词表策略匹配实现
6.1词表策略匹配流程
策略配置匹配流程,如图17:
(1)输入匹配参数,request_id请求的惟一标识,用于上下游定位,req_from请求来源,用于识别请求业务方,token用于权限校验,service_line业务线标识,用于识别匹配用的词表,conent要匹配的文本,以及文本的配置,用于识别须要哪一个生效位置的敏感词。如图18:
(2)将文本中的中文、字母、数字、特殊符号抽取组合生成不一样组合的文字片断,用于强过滤匹配。如图19:
(3)根据业务线以及文本的位置将文本送到对应的字典树匹配出单个敏感词,信息包含敏感词、敏感词在文本中的位置、敏感词的长度,位置和长度用于多模词,词间距是否有效的计算。匹配出的结果,如图20:
(4)经过业务线,生效位置、敏感词,从 match_data(图13)缓存中获取到敏感词所属的敏感词ID,再经过敏感词ID从line_cahe缓存中获取到敏感词的属性规则;若是匹配到的敏感词是包含词或者过滤词,直接命中输出;若是是多模词,则再查找多模词中的其余词是否命中,若是命中切两个词的顺序和词间距知足多模词的属性规则,则命中输出。结果返回,如图21:
6.2大文本匹配超时解决方案
PGC图文常常有几十万字的大文本文章过词表,因为字数太多,召回的词量能达到几万,这些词在作匹配规则计算时耗时太长,致使匹配超时。
优化方案如图21:
(1)优化前,一个大文本文章,标题字数100,正文19.9w,词表匹配时先匹配标题,耗时10ms,再匹配正文,因为正文字数多,耗时19s,最终匹配的耗时二者累加达到20s。
(2)优化后,大文本文章过词表,先将字数超过5000的正文,拆成多个小于等于5000的正文,词表匹配时,多个文字片断并行匹配,最终耗时结果是多个并行计算中耗时最大的一个,我举的例子50ms。
6.3 字典树(Trie树)的实现
字典树匹配算法使用了厂内的开源C++库 dictmatch,dictmatch实现了最简单的Trie树的算法,没有进行穿线改进,所以是须要回朔的。可是其使用2个表来表示Trie树,并对其占用空间大的问题进行了很大的优化,特色是在建树的时候比较慢,但在查询的时候很是快。
字典树结构,如图23:
7、发展&思考
词表特殊字符支持:如今的词表词的存储以及字典树的匹配算法对于表情及其余特殊字符不支持,词表服务下一步的优化迭代会主要放在特殊字符的支持上,可以知足更多业务的需求。
词表分业务线部署:如今词表服务 60+ 的业务方,各业务线都是混部,全部业务线的词表都在实例中加载一份,耗费内存特大,并且词表服务出问题会影响全部的业务方;若是每一个业务线都分集群部署,会增长维护成本,因此咱们在探索一种自动分业务线部署的方式。
推荐阅读:
---------- END ----------
百度Geek说
百度官方技术公众号上线啦!
技术干货 · 行业资讯 · 线上沙龙 · 行业大会
招聘信息 · 内推信息 · 技术书籍 · 百度周边
欢迎各位同窗关注