实现得分的PrefixQuery

标签: 得分 prefixquery | 发表时间:2017-03-16 19:38 | 作者:suichangkele
出处:http://www.iteye.com

(先声明一下,我使用的lucene的版本是lucene4.7.2)

在lucene中,有一种类型的query叫做MultiTermQuery,故名思议,他是要涉及到很多个term的query,比如我们常用的WildcardQuery、FuzzyQuery、PrefixQuery、TermRangeQuery、NumericRangeQuery等,他们都是需要由一个term来按照一定的逻辑找到跟这个term有指定的关系的term,然后再重写由找到的这些term形成的TermQuery进入一个新的Query(比如BooleanQuery),但是有个一指的注意的地方是:有些MultiTermQuery是不得分的,也就是在返回的时候不会按照得分排序,比如PrefixQuery,这个由每个MultiTermQuery使用的rewriteMethod指定,也就是由重写规则指定。本文的目的不在于讨论重写规则,而是想实现一个可以得分的PrefixQuery(业务场景是我们要做搜索框中提示词的排序,所以必须实现得分)。

 

实现原理很简单,在指定重写规则的时候将重写规则指定为得分的规则(当然这里涉及到重写规则的实现,这里本文不讨论),在org.apache.lucene.search.MultiTermQuery类中含有SCORING_BOOLEAN_QUERY_REWRITE这个重写规则从他的名字中就可以理解是封装为一个BooleanQuery,并且计算分数。他的逻辑很简单,将搜索到的多个termQuery封装成一个booleanQuery,每一个termQuery都是optional的,也就是对多个termQuery取并集。但是Booleanquery有个需要注意的地方,他不能有太多的clause,不然会报错,默认是1024个,所以我们需要修改这个值,做到这里就算是完成了。我的代码如下:

/**
 * 由于solr自带的PrefixQuery是不得分的,不能满足提示词的排序要求,所以重写这个query.
 */
public class ScoredPrefixQuery extends PrefixQuery {

	//从词典表中得到的term的限制,用于做测试的,实际中不用
	private int limit = -1; 
	
	static{
		BooleanQuery.setMaxClauseCount(Integer.MAX_VALUE);//设置BooleanQuery的最多的子query的个数为Integer.MAX_VALUE。
	}
	
	public ScoredPrefixQuery(Term prefix) {
		super(prefix);
		//重置重写规则,使用得分的booleanQuery,此处存在的问题是可能会发生BooleanQuery.TooManyClauses,所以要在得到term的时候需要做限制
		setRewriteMethod(org.apache.lucene.search.MultiTermQuery.SCORING_BOOLEAN_QUERY_REWRITE);
	}
	/**
         * 从词典表中得到前缀匹配的term的方法
         */
	@Override
	public TermsEnum getTermsEnum(Terms terms, AttributeSource atts) throws IOException {
		 TermsEnum tenum = terms.iterator(null);
		 if (getPrefix().bytes().length == 0) {
		      // no prefix -- match all terms for this field:
		     return tenum;
		 }
		 return new PrefixTermsEnum(tenum, getPrefix().bytes()) {
			 int already = 0;
			 final int termLimit =  limit==-1?BooleanQuery.getMaxClauseCount():limit;//设置limit只是用于做测试的。
			 
			 @Override
			public BytesRef next() throws IOException {
				
				BytesRef ref = super.next();//先调用父类方法,即从词典表中读取,
				if(ref == null){//如果真的读完了,就返回null。
					return null;
				}else{//没有读取完,则判断是否已经读取了太多的term
					//最多的BooleanClause的个数
					if(already++ < termLimit){//一个前缀最多从词典表中得到booleanquery的MaxClause个,这样就不会报错了。
						return ref;
					}
					return null;
				}
			}
		 };
	}
	
	public int getLimit() {
		return limit;
	}
	
	//做测试用的
	public void setLimit(int limit) {
		this.limit = limit;
	}
	
//这个测试的前提是我们在索引中仅仅保存了只有id域的100个document,id为从0-99,省略了建立索引的代码。
	public static void main(String[] args) throws IOException {
		
		IndexReader reader = DirectoryReader.open(getDirectory());
		
		IndexSearcher search = new IndexSearcher(reader);
		ScoredPrefixQuery q = new ScoredPrefixQuery(new Term("id","1"));//这一行和下面的PrefixQuery q 这一行是区分的,如果使用这一行则只会搜到3个,并且得分不是1.0f,也就是是得分的。
		q.setLimit(3);//设置最多为3个。
		
//		PrefixQuery q = new PrefixQuery(new Term("id", "1"));//如果使用lucene中默认使用的PrefixQuery则会搜到11个,并且得分都是1.0f,也就是没有得分。
		
		TopDocs td = search.search(q, 100);
		for(ScoreDoc sd:td.scoreDocs){
			System.out.println(sd.score);
		}
		System.out.println(td.scoreDocs.length);
		
	}	
}

 

这样就完成了得分的前缀匹配的query,如果要在solr中使用,还需要自己定义queryparser的插件,这个留在以后再写博客。

 

 

 



已有 0 人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



相关 [得分 prefixquery] 推荐:

实现得分的PrefixQuery

- - 开源软件 - ITeye博客
(先声明一下,我使用的lucene的版本是lucene4.7.2). 本文的目的不在于讨论重写规则,而是想实现一个可以得分的PrefixQuery(业务场景是我们要做搜索框中提示词的排序,所以必须实现得分). 实现原理很简单,在指定重写规则的时候将重写规则指定为得分的规则(当然这里涉及到重写规则的实现,这里本文不讨论),在org.apache.lucene.search.MultiTermQuery类中含有SCORING_BOOLEAN_QUERY_REWRITE这个重写规则从他的名字中就可以理解是封装为一个BooleanQuery,并且计算分数.

NBA得分后卫评选

- yefei - 译言-每日精品译文推荐
来源Shooting guard ratings - ESPN. 在NBA的后乔丹时代,对于联盟中谁是最好的得分后卫一直都没有定论. Kobe Bryant's got the rings and an MVP, but Dwyane Wade is beloved by the stats geeks (and has one blinged-out finger himself).

近期手机网页项目一些杂碎心得分享

- - 张鑫旭-鑫空间-鑫生活
本文地址: http://www.zhangxinxu.com/wordpress/?p=2576. 其实上上周就可以出此文了,只是,就跟谈恋爱一样的,要讲求时机以及心情. 这会儿,看完了海贼王情报,处理了邮件,文章评论以及部分同行靠谱的提问,加上好几天没有动“笔头子”了,于是,很有兴致,分享些杂碎的知识点.

关于工作效率的心得分享

- - 博客园_知识库
  这是去年11月底在小组里分享过的工作效率心得,在这里也跟大家分享一下工作“快”感哈哈. 我相信大家应该都有过工作效率的些许烦恼. 而这个效率啊伴随我很长时间的痛苦. 每每到PDI的时候领导必提效率有木有. 自认为快是不算的,必须领导和客户方说了算,对于当年校招进来的毛驴,是一件泪崩漫长的提升过程.

Putty的噩梦——渗透工具PuttyRider使用心得分享

- - 行业应用 - ITeye博客
近日,我们的360监控平台,检测到一个叫PuttyRider渗透工具,小编立马下回来研究,整理一篇工具的使用心得分享给大家. 我们在入侵到一台主机的时候,经常会看到管理员的桌面会放着putty.exe,这说明有很大的可能性管理员是使用putty远程管理主机的. 该工具主要是针对SSH客户端putty的利用,采用DLL注入的方式,来实现各种猥琐的利用姿势.

Elasticsearch自定义文档得分并排序

- - JenkinWang's Blog
大多数情况下,我们需要对查询结果排序,比方说按最新时间降序、按金额降序等. 我们只需要对相应的字段 sort 即可. 但有时候也会出现一些复杂的情况,比方说有A、B、C、D、E类数据,他想让你给这类数据重新定义优先级,按照B、E、D、A、C的顺序展示,并且每类数据内部按时间降序. 然而最近我们也提出了一个类似这样的需求,查阅相关文档后,发现Elasticsearch里的 function_socre函数可以实现这一功能, 遂将此学习内容做一个记录.

Google 的面试流程是怎样的?有什么面试心得分享?

- - 知乎每日精选
如果是你投简历到 Google 的话,据说先需要经过算法筛选,通过的才能到 HR 筛选;通不过的话,你的简历没被人肉眼看到就直接被拒绝了. 因此,听说也有人是专门提供简历优化服务的,类似 SEO,让你的简历能通过算法这一关. 如果 HR 挑选到你的话,会主动联系你. 最基本的,要确认你不是个捏造简历来浑水摸鱼的人,为此 HR 会了解一下你的经验,看看你是否真的是个工程师.

玩游戏的儿童在大脑功能测试中得分更高

- - 奇客Solidot–传递最新科技情报
根据发表在《JAMA Netw Open》期刊上的 一项研究,玩游戏的青少年比不玩的人 有更好的记忆力和更好的运动控制技巧. 研究只是展现了某种相关性,并不能从中得出因果联系,但研究为治疗认知问题的游戏开发提供了依据. 该研究利用了来自 青少年大脑认知发展(ABCD)的数据,跟踪了成千上万儿童成长过程中的大脑发育,参与者会定期参加评估,包括大脑成像、认知任务、心理健康筛查、身体健康检查等测试.

飛利浦 Philips Airfryer 炸東西不用油的空氣油炸鍋 使用心得分享

- chris - 486的 大丈夫週記
記得好像是年初,飛利浦一個主管看到我因在減肥而不吃炸雞腿、炸排骨,就跟我說他們國外有種炸雞腿不用油的油鍋,問我說如果他們引進來台灣,不知道有沒有市場. 我聽了差點動手毆打他,X的咧,有這好東西你不引進,你要引進什麼啦~~~. 對方聽了,就默默去做引進的動作,而我也在癡癡的等待這東西引進,這一等就從春天等到了秋天結束......

互联网社交产品的运营人员有哪些心得值得分享?

- - 知乎每日精选
1.不要用真钱吸引用户,因为产品如果不能满足用户的长远利益,怎么都留不住他们;. 2.不要盲目地与一些成熟网站合作,因为巨人不会真正蹲下来让你骑上肩膀;. 3.不要让拍脑袋想出来的活动打乱产品的步调,否则会因小失大,乃至两败俱伤;. 4.不要每天盯着全球排名,因为一个“小孩”在没有趋于成熟之前是非常不稳定的,还没有达到常态化发展;.