很多人在使用lucene时会使用其提供的queryparser分析query。不过,lucene的queryparser从一开始到现在都没有充分考虑中文等语言的特点,使得查询中文会出现让人不可理解的查不到结果的情况。这个bug就是LUCENE-2458。
这
个问题简单说来就是,对于一个连续的中文query,queryparser将Analyzer返回的Term序列构成了PhraseQuery(也有可
能是MultiPhraseQuery),而PhraseQuery默认的匹配规则是要求Term序列在索引的文档中完全顺序匹配。这对于英文查询来说是
可以接受的,因为queryparser在分析query时,首先通过AND、OR、NOT将query进行切分(这可以理解为queryparser
的第一层分析,这样切分后构成的TOP
Query就是BooleanQuery),然后将切分后的subquery交由Analyzer分析(当然这要求是满足FieldQuery的情况,否
则也可能是RangeQuery、WildcardQuery等),因为英文单词之间以空格分割,相当于OR查询,所以英文中的subquery就可以理
解是个短语(比如由多个连字符连接的短语,或者是英文和数字接合的短语,在lucene查询语法中,显示的双引号之间的内容认为是短语)。但对中文来说,
如果将subquery分析成PhraseQuery,就很成问题。比如subquery是”诺基亚N97“,如果构成PhraseQuery,则要求索
引的文档中必须存在”诺基亚N97“,如果”诺基亚“和”N97“中间有其他词,就不算匹配。对于这个例子,是可以调整PhraseQuery的
slop参数来变相解决,但这种情况,使用AND
BooleanQuery更合适,使用BooleanQuery在对文档打分上也要比PhraseQuery好很多。而对于query分词结果,也存在一
些TermQuery之间是OR的情况,使用PhraseQuery显然也不合适。
如LUCENE-2458提到,这个bug会在3.1和
4中被修复,修复方法是,只有显示通过双引号括起来的subquery才生成
PhraseQuery,否则可以派生子类来自定义处理。就目前使用来说,如果你使用IK做Analyzer,那么它提供的IKQueryParser是
很好的替代方案,它构造的就是由AND和OR联合的BooleanQuery。但因为BooleanQuery没有考虑各个Term在文档中的位置关系,
一味的根据词频计算得分,检索效果有时也不是很好。不知道大家是怎么处理的?我有想到去扩展它的Query和Scorer,不过看起来有些麻烦,暂且还没
精力投入上去。