- 浏览: 412664 次
- 性别:
- 来自: 北京
最新评论
-
springdata_spring:
apache lucene开源框架demo使用实例教程源代码下 ...
有关Lucene的问题(6):Lucene的事务性 -
jaychang:
必须要感谢作者的分享,对理解Lucene的工作原理帮助很大
Lucene学习总结之一:全文检索的基本原理 -
yin_kaihua:
...
Lucene学习总结之三:Lucene的索引文件格式 (1) -
djh122:
...
Lucene 原理与代码分析完整版 -
wayne0830:
多谢楼主分享!
Lucene 原理与代码分析完整版
2.4、搜索查询对象
2.4.2、创建Scorer及SumScorer对象树
当创建完Weight对象树的时候,调用IndexSearcher.search(Weight, Filter, int),代码如下:
//(a)创建文档号收集器 TopScoreDocCollector collector = TopScoreDocCollector.create(nDocs, !weight.scoresDocsOutOfOrder()); search(weight, filter, collector); //(b)返回搜索结果 return collector.topDocs(); |
public void search(Weight weight, Filter filter, Collector collector) throws IOException { if (filter == null) { for (int i = 0; i < subReaders.length; i++) { collector.setNextReader(subReaders[i], docStarts[i]); //(c)创建Scorer对象树,以及SumScorer树用来合并倒排表 Scorer scorer = weight.scorer(subReaders[i], !collector.acceptsDocsOutOfOrder(), true); if (scorer != null) { //(d)合并倒排表,(e)收集文档号 scorer.score(collector); } } } else { for (int i = 0; i < subReaders.length; i++) { collector.setNextReader(subReaders[i], docStarts[i]); searchWithFilter(subReaders[i], weight, filter, collector); } } } |
在本节中,重点分析(c)创建Scorer对象树,以及SumScorer树用来合并倒排表,在2.4.3节中,分析 (d)合并倒排表,在2.4.4节中,分析文档结果收集器的创建(a),结果文档的收集(e),以及文档的返回(b)。
BooleanQuery$BooleanWeight.scorer(IndexReader, boolean, boolean) 代码如下:
public Scorer scorer(IndexReader reader, boolean scoreDocsInOrder, boolean topScorer){ //存放对应于MUST语句的Scorer List<Scorer> required = new ArrayList<Scorer>(); //存放对应于MUST_NOT语句的Scorer List<Scorer> prohibited = new ArrayList<Scorer>(); //存放对应于SHOULD语句的Scorer List<Scorer> optional = new ArrayList<Scorer>(); //遍历每一个子语句,生成子Scorer对象,并加入相应的集合,这是一个递归的过程。 Iterator<BooleanClause> cIter = clauses.iterator(); for (Weight w : weights) { BooleanClause c = cIter.next(); Scorer subScorer = w.scorer(reader, true, false); if (subScorer == null) { if (c.isRequired()) { return null; } } else if (c.isRequired()) { required.add(subScorer); } else if (c.isProhibited()) { prohibited.add(subScorer); } else { optional.add(subScorer); } } //此处在有关BooleanScorer及scoreDocsInOrder一节会详细描述 if (!scoreDocsInOrder && topScorer && required.size() == 0 && prohibited.size() < 32) { //生成Scorer对象树,同时生成SumScorer对象树 return new BooleanScorer2(similarity, minNrShouldMatch, required, prohibited, optional); } |
对其叶子节点TermWeight来说,TermQuery$TermWeight.scorer(IndexReader, boolean, boolean) 代码如下:
public Scorer scorer(IndexReader reader, boolean scoreDocsInOrder, boolean topScorer) throws IOException { //此Term的倒排表 TermDocs termDocs = reader.termDocs(term); if (termDocs == null) return null; return new TermScorer(this, termDocs, similarity, reader.norms(term.field())); } |
TermScorer(Weight weight, TermDocs td, Similarity similarity, byte[] norms) { super(similarity); this.weight = weight; this.termDocs = td; //得到标准化因子 this.norms = norms; //得到原来计算得的打分:queryNorm*idf^2*t.getBoost() this.weightValue = weight.getValue(); for (int i = 0; i < SCORE_CACHE_SIZE; i++) scoreCache[i] = getSimilarity().tf(i) * weightValue; } |
对其叶子节点ConstantWeight来说,ConstantScoreQuery$ConstantWeight.scorer(IndexReader, boolean, boolean) 代码如下:
public ConstantScorer(Similarity similarity, IndexReader reader, Weight w) { super(similarity); theScore = w.getValue(); //得到所有的文档号,形成统一的倒排表,参与倒排表合并。 DocIdSet docIdSet = filter.getDocIdSet(reader); DocIdSetIterator docIdSetIterator = docIdSet.iterator(); } |
对于BooleanWeight,最后要产生的是BooleanScorer2,其构造函数代码如下:
public BooleanScorer2(Similarity similarity, int minNrShouldMatch, List<Scorer> required, List<Scorer> prohibited, List<Scorer> optional) { super(similarity); //为了计算打分公式中的coord项做统计 coordinator = new Coordinator(); this.minNrShouldMatch = minNrShouldMatch; //SHOULD的部分 optionalScorers = optional; coordinator.maxCoord += optional.size(); //MUST的部分 requiredScorers = required; coordinator.maxCoord += required.size(); //MUST_NOT的部分 prohibitedScorers = prohibited; //事先计算好各种情况的coord值 coordinator.init(); //创建SumScorer为倒排表合并做准备 countingSumScorer = makeCountingSumScorer(); } |
Coordinator.init() { coordFactors = new float[maxCoord + 1]; Similarity sim = getSimilarity(); for (int i = 0; i <= maxCoord; i++) { //计算总的子语句的个数和一个文档满足的子语句的个数之间的关系,自然是一篇文档满足的子语句个个数越多,打分越高。 coordFactors[i] = sim.coord(i, maxCoord); } } |
在生成Scorer对象树之外,还会生成SumScorer对象树,来表示各个语句之间的关系,为合并倒排表做准备。
在解析BooleanScorer2.makeCountingSumScorer() 之前,我们先来看不同的语句之间都存在什么样的关系,又将如何影响倒排表合并呢?
语句主要分三类:MUST,SHOULD,MUST_NOT
语句之间的组合主要有以下几种情况:
- 多个MUST,如"(+apple +boy +dog)",则会生成ConjunctionScorer(Conjunction 交集),也即倒排表取交集
- MUST和SHOULD,如"(+apple boy)",则会生成ReqOptSumScorer(required optional),也即MUST的倒排表返回,如果文档包括SHOULD的部分,则增加打分。
- MUST和MUST_NOT,如"(+apple –boy)",则会生成ReqExclScorer(required exclusive),也即返回MUST的倒排表,但扣除MUST_NOT的倒排表中的文档。
- 多个SHOULD,如"(apple boy dog)",则会生成DisjunctionSumScorer(Disjunction 并集),也即倒排表去并集
- SHOULD和MUST_NOT,如"(apple –boy)",则SHOULD被认为成MUST,会生成ReqExclScorer
- MUST,SHOULD,MUST_NOT同时出现,则MUST首先和MUST_NOT组合成ReqExclScorer,SHOULD单独成为SingleMatchScorer,然后两者组合成ReqOptSumScorer。
下面分析生成SumScorer的过程:
BooleanScorer2.makeCountingSumScorer() 分两种情况:
- 当有MUST的语句的时候,则调用makeCountingSumScorerSomeReq()
- 当没有MUST的语句的时候,则调用makeCountingSumScorerNoReq()
首先来看makeCountingSumScorerSomeReq代码如下:
private Scorer makeCountingSumScorerSomeReq() { if (optionalScorers.size() == minNrShouldMatch) { //如果optional的语句个数恰好等于最少需满足的optional的个数,则所有的optional都变成required。于是首先所有的optional生成ConjunctionScorer(交集),然后再通过addProhibitedScorers将prohibited加入,生成ReqExclScorer(required exclusive) ArrayList<Scorer> allReq = new ArrayList<Scorer>(requiredScorers); allReq.addAll(optionalScorers); return addProhibitedScorers(countingConjunctionSumScorer(allReq)); } else { //首先所有的required的语句生成ConjunctionScorer(交集) Scorer requiredCountingSumScorer = requiredScorers.size() == 1 ? new SingleMatchScorer(requiredScorers.get(0)) : countingConjunctionSumScorer(requiredScorers); if (minNrShouldMatch > 0) { //如果最少需满足的optional的个数有一定的限制,则意味着optional中有一部分要相当于required,会影响倒排表的合并。因而required生成的ConjunctionScorer(交集)和optional生成的DisjunctionSumScorer(并集)共同组合成一个ConjunctionScorer(交集),然后再加入prohibited,生成ReqExclScorer return addProhibitedScorers( dualConjunctionSumScorer( requiredCountingSumScorer, countingDisjunctionSumScorer( optionalScorers, minNrShouldMatch))); } else { // minNrShouldMatch == 0 //如果最少需满足的optional的个数没有一定的限制,则optional并不影响倒排表的合并,仅仅在文档包含optional部分的时候增加打分。所以required和prohibited首先生成ReqExclScorer,然后再加入optional,生成ReqOptSumScorer(required optional) return new ReqOptSumScorer( addProhibitedScorers(requiredCountingSumScorer), optionalScorers.size() == 1 ? new SingleMatchScorer(optionalScorers.get(0)) : countingDisjunctionSumScorer(optionalScorers, 1)); } } } |
然后我们来看makeCountingSumScorerNoReq代码如下:
private Scorer makeCountingSumScorerNoReq() { // minNrShouldMatch optional scorers are required, but at least 1 int nrOptRequired = (minNrShouldMatch < 1) ? 1 : minNrShouldMatch; Scorer requiredCountingSumScorer; if (optionalScorers.size() > nrOptRequired) //如果optional的语句个数多于最少需满足的optional的个数,则optional中一部分相当required,影响倒排表的合并,所以生成DisjunctionSumScorer requiredCountingSumScorer = countingDisjunctionSumScorer(optionalScorers, nrOptRequired); else if (optionalScorers.size() == 1) //如果optional的语句只有一个,则返回SingleMatchScorer,不存在倒排表合并的问题。 requiredCountingSumScorer = new SingleMatchScorer(optionalScorers.get(0)); else //如果optional的语句个数少于等于最少需满足的optional的个数,则所有的optional都算required,所以生成ConjunctionScorer requiredCountingSumScorer = countingConjunctionSumScorer(optionalScorers); //将prohibited加入,生成ReqExclScorer return addProhibitedScorers(requiredCountingSumScorer); } |
经过此步骤,生成的Scorer对象树如下:
scorer BooleanScorer2 (id=50) | | | //ConstantScore(contents:cat*) | | //weight(contents:dog) | | | | | //weight(contents:eat) | | | | //weight(contents:cat^0.33333325) | | //weight(contents:foods) | //weight(contents:boy) //ConstantScore(contents:apple*) |
生成的SumScorer对象树如下:
scorer BooleanScorer2 (id=50) | | //ConstantScore(contents:cat*) | //weight(contents:dog) | | | //weight(contents:eat) | | //weight(contents:cat^0.33333325) | //weight(contents:foods) | //weight(contents:boy) //ConstantScore(contents:apple*) |
发表评论
-
Lucene应用开发揭秘
2011-09-25 22:13 5352Lucene应用开发揭秘 ... -
Lucene应用开发揭秘上线了
2011-09-09 23:54 114Lucene应用开发揭秘 华章培训网地址:http:/ ... -
LinkedIn公司实现的实时搜索引擎Zoie
2010-11-29 21:19 8488一、总体架构 Zoie是linkedin公司基于Luce ... -
Lucene 原理与代码分析完整版
2010-06-13 01:30 34952Lucene 原理与代码分析系列文章已经基本告一段落, ... -
Lucene学习总结之十:Lucene的分词器Analyzer
2010-06-06 22:13 71401、抽象类Analyzer 其主要包含两个接口,用于生 ... -
Lucene学习总结之九:Lucene的查询对象
2010-05-19 02:39 2799Lucene学习总结之九:Lucene的查询对象(1) ... -
Lucene学习总结之九:Lucene的查询对象(3)
2010-05-19 02:37 29636、FilteredQuery FilteredQu ... -
Lucene学习总结之九:Lucene的查询对象(2)
2010-05-19 02:36 26035、SpanQuery 所谓SpanQ ... -
Lucene学习总结之九:Lucene的查询对象(1)
2010-05-19 02:34 6325Lucene除了支持查询语法以外,还可以自己构造查询对象 ... -
Lucene学习总结之八:Lucene的查询语法,JavaCC及QueryParser
2010-05-08 13:41 2388Lucene学习总结之八:Lucene的查询语法,Java ... -
Lucene学习总结之八:Lucene的查询语法,JavaCC及QueryParser(2)
2010-05-08 00:25 5538三、解析QueryParser.jj 3.1、声明Qu ... -
Lucene学习总结之八:Lucene的查询语法,JavaCC及QueryParser(1)
2010-05-08 00:20 8377一、Lucene的查询语法 Lucene所支持的查询语 ... -
Lucene学习总结之七:Lucene搜索过程解析
2010-04-05 14:52 2950本系列文章将详细描述几乎最新版本的Lucene的基本原理 ... -
Lucene学习总结之七:Lucene搜索过程解析
2010-04-04 22:54 2642本系列文章将详细描述几乎最新版本的Lucene的基本原理 ... -
Lucene学习总结之七:Lucene搜索过程解析(8)
2010-04-04 22:43 76562.4、搜索查询对象 2.4.4、收集文档结果集 ... -
Lucene学习总结之七:Lucene搜索过程解析(7)
2010-04-04 22:39 43612.4、搜索查询对象 2.4.3.2、并集Di ... -
Lucene学习总结之七:Lucene搜索过程解析(6)
2010-04-04 22:20 36172.4、搜索查询对象 2.4.3、进行倒排表合并 在 ... -
Lucene学习总结之七:Lucene搜索过程解析(4)
2010-04-04 20:46 44492.4、搜索查询对象 2.4.1.2、创建Weight ... -
Lucene学习总结之七:Lucene搜索过程解析(3)
2010-04-04 20:19 42992.3、QueryParser解析查询语句生成查询对象 代码 ... -
Lucene学习总结之七:Lucene搜索过程解析(2)
2010-04-04 20:10 4863二、Lucene搜索详细过程 为了解析Lucene对索引文件 ...
相关推荐
1.16 Lucene学习总结之七:Lucene搜索过程解析(5) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .255 1.17 Lucene学习总结之七:Lucene搜索过程解析(6) . . . . . . . . . . . . ....
官网的lucene全文检索引擎工具包,下载后直接解压缩即可使用
由于林良益先生在2012之后未对IKAnalyzer进行更新,后续lucene分词接口发生变化,导致不可使用,所以此jar包支持lucene6.0以上版本
Lucene查询解析器 Lucene查询字符串解析器,用作Web api查询或过滤器字符串。 基本代码来自 使用这种语言的示例查询: name: apple price: > 100 price: > 100 AND active: = 1 product.price: > 100 AND ...
lucene-搜索过程源码解析-Score树
lucene搜索端uml时序图,lucene源码解析 图比较大,看不清,可以下载【sd-search.svg】后再用浏览器打开 使用starUML画图,可以下载【lucene.mdj】后打开,编辑 前提 只考虑最简单的查询,比如只对一个字段,用一个...
本文并给出一个经典的lucene全文收索例子代码。该例子功能是从磁盘文档建立索引,搜索该文档中的哪个TXT文件包含所搜索内容。最后再大致介绍Lucene的结构模块,应用流程希望对网友能有帮助。
----使用iText解析PDF 文档代码 PDFBoxHello.java ----------- --PDFBox测试代码 PDFBoxLuceneIndex.java ------ --PDFBox创建PDF文件的Lucene索引 PDFBoxPathIndex.java ------- --PDFBox创建指定目录PDF文档...
Lucene搜索过程的核心类 IndexSearcher:用于搜索IndexWriter创建的索引 Term:用于搜索的一个基本单元包括了一对字符串元素,与Field相对应 Query :抽象的查询类 TermQuery:最基本的查询类型,用来匹配特定Field...
Lucene搜索引擎开发权威经典 光盘 于天恩 著 中国铁道出版社出版 2008-10 这本书基于Lucene的当前最新版本(2.1)精解了Lucene搜索引擎的相关知识,从基础知识到应用开发,精练简洁,恰到好处。 本书共包括16章,...
lucene-搜索过程源码解析-1-Weight生成.txt
详细分析lucene搜索的实现过程,通过代码解析,会对lucene的搜索实现过程有一个更加深刻的认识
Eclipse工程/ch7:原书第七章和第九章的Eclipse工程文件 使用PDFBox解析PDF文件 使用xpdf解析中文PDF文件 使用POI解析WORD和Excel文件 使用Jacob解析WORD文件 Google的Search API的使用 安装:直接在Eclipse中...
描述了Lucene中如何使用FST算法构建term的内存索引,使用了很多图,直观的展现了FST图的构建流程,能够对想了解lucene内部实现机制原理的同学有帮助。
Eclipse工程/ch7:原书第七章和第九章的Eclipse工程文件 使用PDFBox解析PDF文件 使用xpdf解析中文PDF文件 使用POI解析WORD和Excel文件 使用Jacob解析WORD文件 Google的Search API的使用 安装:直接在Eclipse中...
Lucene 是一个开源、高度可扩展的搜索引擎库,可以从 Apache Software Foundation 获取。您可以将 Lucene 用于商业和开源应用程序。Lucene 强大的 API 主要关注文本索引和搜索。它可以用于为各种应用程序构建搜索...
开源全文搜索工具包Lucene2.9.1的使用。 1. 搭建Lucene的开发环境:在classpath中添加lucene-core-2.9.1.jar包 2. 全文搜索的两个工作: 建立索引文件,搜索索引. 3. Lucene的索引文件逻辑结构 1) 索引(Index)由...
这是一篇公司的内部培训教材,其中中的内容涵盖LUCENE的方方面面,从源代码角度深入剖析LUCENE,如果要对LUCENE有更加深入的了解(专家级别),这篇技术文档必不可少。 前提:对LUCENE有一定程度的了解,否则会让你云...
FileReaderAll函数用来从文件中读取字符串,默认编码为“GBK”。在创建完最重要的IndexWriter之后,就开始遍历需要索引的文件,构造对应的Document和Filed类,最终通过IndexWriter的addDocument函数开始索引。...
Lucene的功能请打,方法众多。主要介绍了Lucene的功能模块及其调用代码,实际使用中可以具体修改。最后还有一个常见的Lucene实例与解析。