18lucene学习总结之七:lucene搜索过程解析(3)内容摘要:

anQueryRewrite采取方式二,其 rewrite函数代码如下: public Query rewrite(IndexReader reader, MultiTermQuery query) throws IOException { //得到 MultiTermQuery的 Term枚举器 FilteredTermEnum enumerator = (reader)。 BooleanQuery result = new BooleanQuery(true)。 int count = 0。 try { //一个循环,取出对应 MultiTermQuery的所有的 Term,加入 BooleanQuery do { Term t = ()。 if (t != null) { TermQuery tq = new TermQuery(t)。 (() * ())。 (tq, )。 count++。 } } while (())。 } finally { ()。 } (count)。 return result。 }  以上两种方式各有优劣: o 方式一使得 MultiTermQuery对应的所有的 Term看成一个 Term,组成一个docid set,作为统一的倒排表参与倒排表的合并,这样无论这样的 Term在索引中有多少,都只会有一个倒排表参与合并,不会产生 TooManyClauses异常,也使得性能得到提高。 但是多个 Term之间的 tf, idf等差别将被忽略,所以采用方式二的 RewriteMethod为 ConstantScoreXXX,也即除了用户指定的 Query boost,其他的打分计算全部忽略。 o 方式二使得整个 Query对象树被展开,叶子节点都为 TermQuery,MultiTermQuery中的多个 Term可根据在索引中的 tf, idf等参与打分计算,然而我们事先并不知道索引中和 MultiTermQuery相对应的 Term到底有多少个,因而会出现 TooManyClauses异常,也即一个 BooleanQuery中的子查询太多。 这样会造成要合并的倒排表非常多,从而影响性能。 o Lucene认为对于 MultiTermQuery这种查询,打分计算忽略是很合理的,因为当用户输入 appl*的时候,他并不知道索引中有什么与此相关,也并不偏爱其中之一,因而计算这些词之间 的差别对用户来讲是没有意义的。 从而Lucene对方式二也提供了 ConstantScoreXXX,来提高搜索过程的性能,从后面的例子来看,会影响文档打分,在实际的系统应用中,还是存在问题的。 o 为了兼顾上述两种方式, Lucene提供了 ConstantScoreAutoRewrite,来根据不同的情况,选择不同的方式。 : public Query rewrite(IndexReader reader, MultiTermQuery query) throws IOException { final CollectionTerm pendingTerms = new ArrayListTerm()。 //计算文档数目限制, docCountPercent默认为 ,也即索引文档总数的 % final int docCountCutoff = (int) ((docCountPercent / 100.) * ())。 //计算 Term数目限制,默认为 350 final int termCountLimit = ((), termCountCutoff)。 int docVisitCount = 0。 FilteredTermEnum enumerator = (reader)。 try { //一个循环,取出与 MultiTermQuery相关的所有的 Term。 while(true) { Term t = ()。 if (t != null) { (t)。 docVisitCount += (t)。 } //如果 Term数目超限,或者文档数目超限,则可能非常影响倒排表合并的性能,因而选用方式一,也即 ConstantScoreFilterRewrite的方式 if (() = termCountLimit || docVisitCount = docCountCutoff) { Query result = new ConstantScoreQuery(new MultiTermQueryWrapperFilterMultiTermQuery(query))。 (())。 return result。 } else if (!()) { //如果 Term数目不太多,而且文档数 目也不太多,不会影响倒排表合并的性能,因而选用 方式二,也即 ConstantScoreBooleanQueryRewrite的方式。 BooleanQuery bq = new BooleanQuery(true)。 for (final Term term: pendingTerms) { TermQuery tq = new TermQuery(term)。 (tq, )。 } Query result = new ConstantScoreQuery(new QueryWrapperFilter(bq))。 (())。 (())。 return result。 } } } finally { ()。 } } 从上面的叙述中,我们知道,在重写 Query对象树的时候,从 MultiTermQuery得到的TermEnum很重要,能够得到对应 MultiTermQuery的所有的 Term,这是怎么做的的呢。 MultiTermQuery的 getEnum返回的是 FilteredTermEnum,它有两个成员变量,其中 TermEnum actualEnum是用来枚举索引中所有的 Term的,而 Term currentTerm指向的是当前满足条件的 Term, FilteredTermEnum的 next()函数如下: public boolean next() throws IOException { if (actualEnum == null) return false。 currentTerm = null。 //不断得到下一个索引中的 Term while (currentTerm == null) { if (endEnum()) return false。 if (()) { Term term = ()。 //如果当前索引中的 Term满足条件,则赋值为当前的 Term if (termCompare(term)) { currentTerm = term。 return true。 } } else return false。 } currentTerm = null。 return false。 } 不同的 MultiTermQuery的 termCompare不同:  对于 PrefixQuery的 getEnum(IndexReader reader)得到的是 PrefixTermEnum,其 termCompare实现如下: protected boolean termCompare(Term term) { //只要前缀相同,就满足条件 if (() == () amp。 amp。 ().startsWith(())){ return true。 } endEnum = true。 return false。 }  对于 FuzzyQuery的 getEnum得到的是 FuzzyTermEnum,其 termCompare实现如下: protected final boolean termCompare(Term term) { //对于 FuzzyQuery,其 prefix设为空 ,也即这一条件一定满足,只要计算的是 similarity if (field == () amp。 amp。 ().startsWith(prefix)) { final String target = ().substring(())。 = similarity(target)。 return (similarity minimumSimilarity)。 } endEnum = true。 return false。 } //计算 Levenshtein distance 也即 edit distance,对于两个字符串,从一个转换成为另一个所需要的最少基本操作 (添加,删除,替换 )数。 private synchronized final float similarity(final String target) { final int m = ()。 final int n = ()。 // init matrix d for (int i = 0。 i=n。 ++i) { p[i] = i。 } // start puting edit distance for (int j = 1。 j=m。 ++j) { // iterates through target int bestPossibleEditDistance = m。 final char t_j = (j1)。 // jth character of t d[0] = j。 for (int i=1。 i=n。 ++i) { // iterates through text // minimum of cell to the left+1, to the top+1, diagonally left and up +(0|1) if (t_j != (i1)) { d[i] = ((d[i1], p[i]), p[i1]) + 1。 } else { d[i] = ((d[i1]+1, p[i]+1), p[i1])。 } bestPossibleEditDistance = (bestPossibleEditDistance, d[i])。 }。
阅读剩余 0%
本站所有文章资讯、展示的图片素材等内容均为注册用户上传(部分报媒/平媒内容转载自网络合作媒体),仅供学习参考。 用户通过本站上传、发布的任何内容的知识产权归属用户或原始著作权人所有。如有侵犯您的版权,请联系我们反馈本站将在三个工作日内改正。