SpanQuery就是用来查询不仅仅是含有term,并且存在的各个term的位置符合一定条件的doc,从源码上讲他最大的改变就是有了getSpans(IndexReader reader)方法,该方法返回的是Spans,在SpanQuery中使用Spans这个类来召回doc(在普通的termQuery中是使用termDocs进行召回),我们先看看Spans这个类。
在Spans的javadoc中有这样的说明:Spans用于枚举term出现的位置,如果是在一个document中则枚举在当前的doc中出现的各个位置,枚举完了当前的doc的所有的位置,则会读取下一个doc,这正是他的next()方法的意义,多次调用这个next方法可能会修改当前的docid(使用doc方法)也可能不会,因为当前的term在当前的doc中可能出现了多次。Spans还有一个方法start()用于获得当前的位置的开始位置(也就是在创建索引时的位置增量),还有end()方法,用于获得当前的位置的结束位置。getPayload()方法,该方法用于获得当前位置的payload,当然可能在建立索引的时候就没有保存词频和位置信息,所以还有一个开关——isPayloadAvailable()方法,他表示当前的位置能否读取payload。注意这里返回的是Collection<byte[]>类型的payload,这是因为可能有的Spans的子类(比如后面说的SpanNearQuery生成的Span,包含多个子Spans)会返回多个payload,所以用一个集合Collection,一个paylaod用byte[]表示。一句话总结下Spans:用于按照顺序枚举一个term在所有包含他的doc中的位置,可以读取payload。
我们看一个最简单的SpanQuery——SpanTermQuery。
SpanTermQuery其实本质上没有任何用处,他的作用也是按照term进行查找doc(和TermQuery是一个意思),只要一个doc含有指定的term就会被召回,没有任何其他的限制(和普通的termQuery的召回逻辑一样),我觉得它存在的意义仅仅是让我们接触一下SpanQuery。他有了区别于普通的termQuery的地方——使用termPositions而不是termDocs进行查找(体现在使用Spans而没有直接在query中使用Term),打分方式也发生了变化——计算tf与termQuery完全不一样;第二个意义是在他的基础上有一个PayLoadTermQuery,这个类可以使用payload进行打分。我们看一下SpanTermQuery的源码。
先看一下他最关键的方法:getSpans方法:
@Override public Spans getSpans(final IndexReader reader) throws IOException { return new TermSpans(reader.termPositions(term), term);//返回的是一个TermSpans }
我们看一下TermSpans,尤其关注其next方法:
public TermSpans(TermPositions positions, Term term) throws IOException { this.positions = positions; this.term = term; doc = -1; }
在构造方法中会传入一个termPositions,这个类是TermDocs的子类,他有一个额外功能是能读取prx文件,也就是能得到每一个term在每一个doc中的出现的位置以及在该位置上的payload,当然他也能读取倒排表,也就是能召回doc。我们看一下termSpan的next方法:
/** * 如果当前的term在当前的doc中的所有的出现位置读取完了(count==freq)则继续读取下一个doc,然后读取下一个位置,增加count++; * 如果没有读取完,则仅仅读取下一个位置。 * */ @Override public boolean next() throws IOException {当前的doc的所有的位置都读取完了。
if (count == freq) {// if (!positions.next()) { doc = Integer.MAX_VALUE; return false; } doc = positions.doc(); freq = positions.freq(); count = 0; } //读取下一个位置,此时一定返回true,因为当前的doc没有读取完。 position = positions.nextPosition(); count++; return true; }
这里的count表示在当前的doc上所有的出现的次数(用freq表示)中已经读取了多少次,如果已经读取完了当前的doc的所有的次数,则读取下一个doc,即进入if判断,否则继续读取当前的doc。
SpanTermQuery的weight以及scorer
SpanTermQuery并没有改写createWeight方法,他会生成一个SpanWeight,这个类没有什么特殊的,他会继续生成一个SpanScorer用来回收doc和打分,重点看一下SpanScorer的nextDoc方法,因为这个方法用于回收doc,这个方法会调用setFreqCurrentDoc方法,
/** * 设置当前doc的freq,他是通过读取当前doc的多个位置来实现的。 */ protected boolean setFreqCurrentDoc() throws IOException { if (!more) { return false; } doc = spans.doc();//通过Spans获得当前的doc(当然spans是根据其封装的termPosition来实现的这个功能) freq = 0.0f; do { int matchLength = spans.end() - spans.start(); freq += getSimilarity().sloppyFreq(matchLength); more = spans.next(); } while (more && (doc == spans.doc()));//直到读取完当前doc上所有的position,所以尽管spans的next方法只会读取一个位置,但是在scorer里面试读取了一个完整的doc,并且每个位置都读取了, return true; }
scorer利用spans了读取了一个完整的doc,并且根据出现的次数得出了freq的值,在score方法中就会使用这个值对当前的doc进行打分。
/**得分唯一不同的是计算tf发生了变化*/ @Override public float score() throws IOException { float raw = getSimilarity().tf(freq) * value; // raw score return norms == null ? raw : raw * Similarity.decodeNorm(norms[doc]); // normalize }
这样SpanTermQuery就完了,他也是根据term进行召回doc,只不过他是将倒排表(termDocs,在SpanQuery中是使用了TermPositions)封装在了Spans里面,使用spans来一个一个位置的读取,并且得分的计算方式发生了变化。
相关推荐
盘古分词 lucene3.0.3 使用 示例 可以方便地整合到项目中使用,.net 4.0的。有分页功能。新加根据分类索引功能。
lucene3.0.3搜索的使用示例lucene3.0.3搜索的使用示例lucene3.0.3搜索的使用示例
本文档详细讲解了各种SpanQuery的用法,以及它跟PhraseQuery的区别
盘古分词 lucene3.0.3 使用 示例 可以方便地整合到项目中使用,.net 4.0的。
盘古分词 lucene3.0.3 使用 示例 可以方便地整合到项目中使用,.net 4.0的。新加分页功能。
lucene3.0.3.core.jar文件,不用到apache官方网站下载17M的包,直接下载这个core就可以了。
Lucene 3.0.3 API Lucene 3.0.3 Lucene
Lucene3.0.3+盘古分词的实现用到的dll文件,带词库文件。已证实可用,可指定使用自己维护后的词库文件。
Lucene是一个基于Java的全文索引工具包。
整理开发Lucene+盘古分词 开发搜索引擎用到的所有必备资源 亲测可用
Lucene3.0分词系统.doc
这是Lucene.NET v3.0.3 DEMO范例程序(含PanGu分词),用C#语言编写的,同时对PanGu分词进行了整合,可以直接下载运行。 项目中还整理了一个后台任务线程监听范例,可以用作增量索引创建,但这个需要你自行加入相关...
lucene-3.0.3.zip 官方版
Apache Lucene.Net 3.0.3 just passed a vote for release - our first official release since graduating from the incubator in August. A lot of work was put into porting and testing the code. We've ...
lucene-smartcn-3.0.3.jar
lucene3.0.3源码和教程
Lucene SpellChecker for Lucene 3.0.2
Lucene.net是Lucene的.net移植版本,是一个开源的全文检索引擎开发包,即它不是一个完整的全文检索引擎,而是一个全文检索引擎的架构,提供了完整的查询引擎和索引引擎。开发人员可以基于Lucene.net实现全文检索的...
传统上,人们将信息检索系统返回结果的排序称为"相关排序" (relevance ranking) ,隐含其中各条目的顺序反映结果和查询的相关程度。