您的位置:首页 > 产品设计 > UI/UE

关于QueryParser类前后修改

2013-11-26 21:31 239 查看
转载请注明出处:/article/2606839.html

这几天在公司做一个项目,就是去将以前的老项目的lucene版本切换成4.3版本,并将以前的索引架构修改为实时索引(公司以前的那个项目是好几年前的了),为了和以前的版本兼容,第一步就是只是把lucene版本修改下,同时支持实时索引,至于所有的接口,都要和以前一样。在这中间就遇到了一个很大的问题,就是在出搜索结果的时候,修改后的版本要比以前的版本多很多搜索结果(上面要求要和原来的接口出的数据完全一样),函数也是用的以前的,为什么就出现不同的结果呢?

最后通过读源代码,发现是QueryParser类在作怪,下面先看一下QueryParser在前后3.1前后两个版本中的效果:

/**  
 *@Description:     
 */ 
package cn.lulei.test;  

import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.queryparser.classic.ParseException;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.Query;
import org.apache.lucene.util.Version;
  
public class TestQueryParser {

	public static Query getOneFieldQuery43(String key, String field) throws ParseException{
		QueryParser parse = new QueryParser(Version.LUCENE_43, field, new StandardAnalyzer(Version.LUCENE_43));
		Query query = null;
		query = parse.parse(key);
		return query;
	}
	
	@SuppressWarnings("deprecation")
	public static Query getOneFieldQuery30(String key, String field) throws ParseException{
		QueryParser parse = new QueryParser(Version.LUCENE_30, field, new StandardAnalyzer(Version.LUCENE_43));
		Query query = null;
		query = parse.parse(key);
		return query;
	}
	
	public static void main(String[] args) throws ParseException {
		String key = "斗破苍穹";
		System.out.println(key + "30版本结果:" + TestQueryParser.getOneFieldQuery30(key, "key").toString());
		System.out.println(key + "43版本结果:" + TestQueryParser.getOneFieldQuery43(key, "key").toString());
	}
}


上面这个测试用例的结果为:

斗破苍穹30版本结果:key:"斗 破 苍 穹"

斗破苍穹43版本结果:key:斗 key:破 key:苍 key:穹

得出两个完全不同的Query对象,这也就是为什么会多出这么多的搜索结果的原因,下面就从源代码中探究其原因,下面的源代码均是通过反编译软件实现的。

先看下QueryParse的构造方法:

public QueryParser(Version matchVersion, String f, Analyzer a)
  {
    this(new FastCharStream(new StringReader("")));
    init(matchVersion, f, a);
  }
在以前的版本中是没有Version这个参数的,具体从那个版本开始加的,我也不是很清楚,自己也是最近才刚开始接触lucene的。

在进一步追一下,看起父类QueryParserBase是如何实现的init(Version matchVersion, String f, Analyzer a)方法

public void init(Version matchVersion, String f, Analyzer a)
  {
    this.analyzer = a;
    this.field = f;
    if (matchVersion.onOrAfter(Version.LUCENE_31))
      setAutoGeneratePhraseQueries(false);
    else
      setAutoGeneratePhraseQueries(true);
  }
其中setAutoGeneratePhraseQueries(boolean)方法修改的是类属性allowLeadingWildcard的值,这样allowLeadingWildcard的值对parse(String)的实现就有决定性的作用。

public Query parse(String query) throws ParseException
  {
    ReInit(new FastCharStream(new StringReader(query)));
    ParseException e;
    try {
      Query res = TopLevelQuery(this.field);
      return res != null ? res : newBooleanQuery(false);
    }
    catch (ParseException tme)
    {
      ParseException e = new ParseException(new StringBuilder().append("Cannot parse '").append(query).append("': ").append(tme.getMessage()).toString());
      e.initCause(tme);
      throw e;
    }
    catch (TokenMgrError tme) {
      ParseException e = new ParseException(new StringBuilder().append("Cannot parse '").append(query).append("': ").append(tme.getMessage()).toString());
      e.initCause(tme);
      throw e;
    }
    catch (BooleanQuery.TooManyClauses tmc) {
      e = new ParseException(new StringBuilder().append("Cannot parse '").append(query).append("': too many boolean clauses").toString());
      e.initCause(tmc);
    }throw e;
  }
也正事因为属性allowLeadingWildcard的值,决定了了第一个测试实例的结果,从源代码中也可以看出来,3.1(包括)之前的版本和之后的版本出来两种完全不同的结果,为什么会做这样的修改,我猜测可能是因为下面的原因:

key:"斗 破 苍 穹" 这种结果是能够准确的定位到用户搜索到的结果,而且也十分准确,但是如果用户某一个词输入错误,或者是错别字,那得到的就不是用户想要的结果,甚至就搜索不出来任何的东西。

key:斗 key:破 key:苍 key:穹 这种结果虽然出现的结果会有很多,但是根据lucene的打分机制,“斗破苍穹”这条记录也出出现在第一条,即使用户输出了其中的某一个字,一还是可以搜索到用户想要的结果的。

至于这两种,那个效果比较好,自己还需大量的数据去测试,不能就根据自己的意愿去认为
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: