国内垂直领域的电商或者信息分享类应用都处于高速发展期,其对内容快速搜索的需求越来越强烈,对于能适应自己业务应用的搜索引擎解决方案也越来越重视。同时,通用的可选开源搜索引擎框架或解决方案也越来越多,如著名的Lucene,Solr,ElasticSearch等。打造一套完美适应自身业务需求的搜索引擎是个具有挑战性的任务,而且无论选择Lucene,Solr这些搜索引擎框架、方案还是自己另写一套搜索引擎,都面临着一个共同的核心问题---如何打造适合自身业务的分词系统。
经典笑话:某护士看到肝硬化病人在病房里偷偷喝酒,就走过去叮嘱说:小心肝!病人微笑回应:小宝贝!这里的“小心肝”存在歧义,从护士的角度理解为:小心/肝,病人的角度成了:小心肝。在中文的世界了,充满着需要准确分词才能消除歧义的场景。
分词对于搜索引擎而言是无比重要的,既影响索引的性能,又直接影响搜索结果的准确性以及相关性的计算。
英语(适用于所有的拉丁语系和相似语系语言)由于有其语言天然以单词为基本单位,所以分词相对容易。需要的基本步骤如下:
第一步很好理解,不做多余解释。
第二步中的停用词(stop word)是指a/an/and/are这类高频词,这类词对搜索的意义不大,但对基于词频的算分公式产生极大的干扰,所以需要过滤掉。
第三步,词干提取(stemming)是西方语言特有的处理,比如英语单词中的单复数变形,-ing和-ed的变形。但在计算相关性时应做同一个单词。比如 apple和apples,doing和done是同一个词,提取词干的目的就是要合并这些变态。这样做能更好的满足人们搜索的习惯和对返回内容的期望。
Lucene英文分词自带了3个常用的词干提取算法,分别是
词干提取的算法并不复杂,基本上是一堆规则,或用映射表,编程容易,但是必须精通这种语言的专家才能胜任---必须非常了解其构词法才行。
第四步,词形还原的基本方法是通过字典映射,比如将drove还原成drive。而stemming经常会把单词变短,如doing变成do。实际上stemming解决了大部分西方语言的分词转换问题,词形还原则更进一步提高了搜索引擎的体验。
数字在常规搜索引擎,如Lucene中,默认会将其当做一个纯粹的字符串处理。分词效果跟英文基本一致。也就是说像数值3.1415926的分词结果就是其本身,要想搜索到这个数字也需要输入完整的3.1415926才能精确命中。
基于全匹配的数字串搜索,对于使用者来说,上述的例子对搜索不太友好。在定制的搜索引擎中往往对此进行优化,以支持对数值更友好的搜索。如对数字进行抽取变成数值,支持数值范围的搜索以及部分数值搜索(章节"垂直领域分词系统差异"里会进一步提到)。
完美的中文分词系统是世界性的难题,原因在于它不仅要理解中文语法结构,中文语义还要自适应语境。不仅如此,中文新词的出现比较快,词义又在不断变化。所以至今为止,没有哪个人或机构声称他们的中文分词系统是100%准确的。或许人工智能的成熟可以将中文分词的准确性不断接近100%。
现有的分词系统方案:
一元切词是将每个中文字符(汉字)独立成一个词条(Term),这样的搜索结果会很糟糕,比如一个普通的搜索"上海",结果集中将完全不相干的"海上"一起返回出来。Lucene里默认提供的是二切中文分词,原理为将: 上海人 分词为: 上海/海人 这样做的好处是避免了一元切词出现的完全没有意义的结果。但二切分词的结果里出现根本没有意义的词条--- 海人 ,而且这是可搜索的内容,效果不如人意。
基于词典分词的一种方法是将词典构建成一个Trie搜索树,每个节点放一个字,同时将词的信息放在Node中,如词性,权重等。Trie树可以是一种多层散列表,在每一层上查找的速度是O(1),所以匹配速度非常快。
如下图所示的是一个由词组集 <一万 一万多="" 一万元="" 一上午="" 一下午="" 一下子="">生成的Tire树的子树一万>
(Trie树示例)
文本在Trie树上进行逐层匹配,直到Trie树不再有子层级或者文本无法匹配到该层的任何字符,这样的得出的分词结果为基于词典的最长匹配。
首先该方法也是依赖于词典,同时为了消除分词中的歧义,提高分词的精确度,需要找出一段文字中所有可能的词,生成全切分词图。
(中文分词切分路径)
上图中可以切分的路径有两条:
路径1:0-1-3-5 对应方案为:有/意见/分歧
路径2:0-2-3-5 对应方案为:有意/见/分歧
使用动态规划算法能获取上述切分结果,并使用词性,权重等综合因素最终确定分词结果。
从统计思维的角度来看,分词的问题可以理解为输入是一个字符串:C=C1,C2,C3...,Cn 输出是一个词串 S=W1,W2,W3...,Wm(m<=n)。对于一个特定的字符串C,会有多个切词方案S与之对应,分词就是从这些S中找出概率最大的一个切分方案,也就是对输入字符串切分出最有可能的词序列。
对于输入字符串C"有意见分歧",有S1和S2两种切分可能。
计算条件概率P(S1|C)和P(S2|C),然后采用概率大的值对应的切分方案。根据贝叶斯公式,有P(S|C)=(P(C|S)*P(S))/P(C),其中P(C)是字符串在语料中出现的概率,只是一个用来归一化的固定值。从词串恢复到汉字串的概率只有唯一的一种方式,所以P(C|S)=1。因此,比较P(S1|C)和P(S2|C)的大小变成比较P(S1)和P(S2)的大小。进一步推导可参考《解密搜索引擎技术实战:Lucene&Java》精华版第二版第4章.
从另外一个角度看,计算最大概率等于求切分词图的最短路径,可以采用动态规划法求解最短路径。
基于概率的分词法,依赖于充足的语料以及对语料的统计分析。因此它是属于事先学习型的分词法。目前一些高质量的分词法就是基于概率统计分词法实现的。
与通用搜索引擎的复杂语料相比,垂直搜索引擎中的语料数据在进索引之前往往会得到清洗。也意味着数据的复杂度会降低。同时在垂直领域中会有很多的专有术语,用户搜索的习惯跟通用搜索引擎也会不一样。因此,需要让垂直搜索引擎显得更智能,更能理解用户的搜索意图。比如自动校正输错的专业词汇,在输入框中提示更多的分类结果集等。这些都需要在搜索引擎中准确的分词以及基于分词的推荐算法来完成。
在垂直领域的英文分词,一般会减少传统英文分词的步骤。根据语料的差异,有时会将词干提取(stemming)省掉,有时候会将过滤stop word步骤省掉。而且一般不进行词干还原。具体怎么做主要取决于要索引的语料。比如在钢铁信息行业,钢铁相关术语非常多,而且很多英文本身是单词缩写,这时候做词干提取和词性还原可能达到会适得其反的效果。同时,由于行业信息推出的集中度很高,快速分词和索引要求较高,因而在不影响准确性的时候,英文分词步骤会做尽可能精简。
同时,垂直搜索引擎会支持更高级的语法来帮助用户在不确定词的情况,搜到结果,相关内容会在下面的中文分词中说明。
数字在文本搜索引擎中算是个异类,文本中出现的数字默认会当做文本来处理。搜索引擎使用者首先需要把数字组合当做一个单词来搜索,如果当做一个数字来搜则会出现疑惑。典型的疑惑有两个:第一,如何在文本中搜索数值范围;第二,长数字到底如何来搜索?比如,一篇文档中出现了1.5,2.0,3.0。能否通过搜索一个数值范围值(2.5-4.0)来匹配结果? 而3.1415926这样的长数值如何搜索才能找到?
Lucene里有NumericField(数值域)概念,其本质是将数字文本转换为数值以支持精确搜索或范围搜索。使用NumericField的前提是从文本中分析出数值,并且需要将数值索引到一个单独的NumericField中。
实际应用中,垂直搜索引擎往往会去清洗带有关键数值的文本Field(域),从中提取数值然后单独做索引。搜索数值的时候需要将NumericField映射到相应的文本Field中。同时在原有文本域中,将数字进行长度切分,如将3.1415926按照4位长度切分:3.14/1592/6,以满足用户用更简短的字符(如3.14)来搜索该数字串。当然,如果输入完整的长数字串匹配效果会更好。
垂直搜索引擎中的中文分词实现复杂度跟英文分词一样,也取决于语料。对于中文语料的清洗,基本能把那些无关业务的或者没有意义的中文本文去除掉。剩下的进行高速分词。
同时由于没有一种分词法能100%的分词准确,在高级搜索中,支持更多的搜索语法,典型的有如下高级搜索:
支持通配符(Wildcard)搜索能解决只知道部分内容的查询,如搜"*中**"能出来包含" 中间 "," 中国 "等词的文档
支持模糊(Fuzzy)查询,允许用户在输错的情况搜索想要的结果。如查询" 宝港股份有限公司 ",在模糊搜索下,能将" 宝钢股份有限公司 "搜索出来。
高级搜索跟分词的关系在于,用户的搜索语句最后往往合成一条复杂查询语句,分词器综合语法解析器切分出正确的查询词,并执行最终查询。
上述两个高级搜索特性同样适用于对于英文的搜索。
找钢网搜索业务具有如下的特征:
针对自身的业务特性和语料特征,构建了一套完整分词系统。
第一步,获取基础词条(Token)。将语料中的内容,按照语言切分出来。得到英文单词、数字、中文段、保留字、无用字。然后在各个语言分词器中进一步切分词,如中文分词需要将中文段再切分为中文词,数字进行4位切分等。
第二部,由第一步中获取的基本词条按照定制需求进行组合,如两个数字之间如果有小数点则组合成一个词条,搜索语句切分时将通配符跟其他词条组合成一个词条等。
第三步,筛选有用词条,丢弃无用词条,得到最终词条。
基本流程
中、日、韩三国语言有部分汉字是重叠的,并且可以基于词典,使用相同的分词法分词。这里主要说明中文分词。
中文分词采用了基于词典的最长匹配法,同时为了消除一些基本的歧义,我们采用了正向词典匹配外,还进行了反向词典匹配。最后根据切分词组的权重,选取更优结果。
经过系列测试和对比,在现有词典和语料下,目前中文分词法的准确度达到85%以上,在高级搜索的匹配下,搜索覆盖率能接近100%。分词的速度超过200K/m(词条数/分钟)以上,速度上也完全可接受。
随着业务需求上的细化和更多语料的积累,将进一步实现基于多元中文切分和基于概率统计的中文分词法来提高分词的准确性,提高搜索引擎的用户体验。
主要参考文献:
关于作者
找钢网搜索引擎高级算法工程师——周红星