基于Lucene的联系人搜索3

基于Lucene的联系人搜索3

遗留问题

前两篇文章中提到了检索的时候不支持的一些特性,比如孙燕姿这个名字输入syanz无法查找,为了解决这个问题,今天又对切词的部分进行了修正。

 

解决

对于名字字段进行两种全拼和简拼转换,比如孙燕姿,拼音转换后的结果是sunyanzi,syz,然后再对这个转换结果进行前向后向两个方向的N-Gram切分。

原有的设计是拼音转换有四种,对于“沈世卿”这样的名字,拼音转换结果有shenshiqing,shshq, ssq, shensq,通过这个方式枚举所有组合编码上不漂亮,设计起来也不nice。所以放弃了这种方式。

 

同时增加了了一个类似于SpellCheck的字段,这个是参考自:http://lucene.apache.org/java/3_0_1/api/contrib-spellchecker/org/apache/lucene/search/spell/SpellChecker.html

这个字段也只进行全拼和简拼两种拼音转换,但转换后的结果使用了标准的N-Gram而非EdgeNGram的TokenFilter,这样这个字段就可以进行拼写检查的工作。

你可能会问了,为什么不只使用拼写检查一个字段来进行搜索?

  1. 一个是我们要对结果进行高亮,如果这样存储过大,并且还要存储位置信息,存储就更大了,没有提到的是拼写检查字段我是不存储的,只是分词和索引。

  2. 第二个问题是,如果只使用拼写检查一个字段,检索的时候QueryParser上也会遇到问题,如果选择AND_OPERATOR,那么输入错误 就检索不到结果,如果使用OR_OPERATOR,那么搜索结果太多无关的,用户会觉得很奇怪。否则就需要检索的时候手动做一次N-Gram的切分,然后 在使用这个切分后的组合(中间加空格)来查询。

 

这样设计好了之后如何检索:

检索时候的分词我们使用WhiteSpaceAnalyzer+ICU+Lowercase作为QueryParser的analyzer(实际上 我使用的MultipleFieldQueryParser+PerFieldAnalyzer,不过原理上类似,考虑下就清楚了),同时使用 AND_OPERATOR

 

如果第一次检索结果为空,那么我们使用拼写检查字段字段进行检索,QueryParser使用索引时候使用的Analyzer,同时使用 OR_OPERATOR,在使用这个新的QueryParser检索一次,将前两个结果(如果有的话)拼接成新的检索关键词再检索一次,这次的结果返回给 用户,如果拼写检查返回空,那么仍然使用原始关键词检索一次返回给用户。不要担心多次检索的性能损失,这个耗时很少,要比你整理结果返回给用户的耗时还 少,所以大可不比担心。这个过程对用户透明,用户感觉不到这个过程,经过这样的改进,我发现对于用户的任意输入能尽可能的给出满意的结果,减少了空结果的 返回可能性,同时允许了用户更加随意的输入,同时由于减少了拼音转换的次数,性能也有了细微的提升(目前还没时间做压力,压力估计要这个月底才能进行)。

 

同时还进行了简单的优化,假设拼写检查返回了两个结果(我是设置了按照相似度得分降序),那么前两个结果应该有不同的权重,所以我也对这两个搜索词赋予了逐级下降的权重,那么检索的结果会更优。

此条目发表在未分类分类目录,贴了标签。将固定链接加入收藏夹。