`
anna_zr
  • 浏览: 200555 次
  • 性别: Icon_minigender_2
  • 来自: 北京
社区版块
存档分类
最新评论

lucene的hit类

阅读更多
本文转自:
http://daihaixiang.blog.163.com/blog/static/3830134200862394745683/


关于Hits类。
这个Hits类可是非常的重要,因为Lucene使用了缓存机制,关于缓存的实现就是在这个Hits类中。Hits工作过程中,使用了LRU算法,即通过一个HitDoc结构来实现一个双向链表,使用LRU置换算法,记录用户最近访问过的Document。
开门见山,直接拿出Hits类的实现代码来说话。
package org.apache.lucene.search;
import java.io.IOException;
import java.util.Vector;
import java.util.Iterator;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.CorruptIndexException;
public final class Hits {
private Weight weight;   
private Searcher searcher;
private Filter filter = null;
private Sort sort = null;
private int length;                // Hits的长度,即满足查询的结果数量
private Vector hitDocs = new Vector();    // 用作缓存检索结果的(Hit)
private HitDoc first;         // head of LRU cache
private HitDoc last;          // tail of LRU cache
private int numDocs = 0;      // number cached
private int maxDocs = 200;    // max to cache
Hits(Searcher s, Query q, Filter f) throws IOException {
    weight = q.weight(s);
    searcher = s;
    filter = f;
    getMoreDocs(50); // retrieve 100 initially | 从缓存中取出检索结果,如果缓存为null,则需要查询,查询后将结果加入缓存中
}
Hits(Searcher s, Query q, Filter f, Sort o) throws IOException {
    weight = q.weight(s);
    searcher = s;
    filter = f;
    sort = o;
    getMoreDocs(50); // retrieve 100 initially | 从缓存中取出检索结果,如果缓存为null,则需要查询,查询后将结果加入缓存中
   
}
/**
   * 将满足检索结果的Document加入到缓存hitDocs中
   */
private final void getMoreDocs(int min) throws IOException {
    /////////////////////////////////////////////////////////////////////////////////////////////
    System.out.println("■■■■■■■■■■■■■■■■■■■■■■■■进入getMoreDocs()方法中时,hitDocs.size="+hitDocs.size());
    ///////////////////////////////////////////////////////////////////////////////////////////
    if (hitDocs.size() > min) {
      min = hitDocs.size();
    }
    int n = min * 2;    // 扩充缓存容量为默认的2倍(默认最小情况下,也要扩充缓存。即使检索结果为1条记录,缓存的长度也扩充为100)
    TopDocs topDocs = (sort == null) ? searcher.search(weight, filter, n) : searcher.search(weight, filter, n, sort);
    length = topDocs.totalHits;
    ScoreDoc[] scoreDocs = topDocs.scoreDocs;
    float scoreNorm = 1.0f;
   
    if (length > 0 && topDocs.getMaxScore() > 1.0f) {
      scoreNorm = 1.0f / topDocs.getMaxScore();
    }
    int end = scoreDocs.length  maxDocs) {      // if cache is full
      HitDoc oldLast = last;
      remove(last);             // flush last
      oldLast.doc = null;       // let doc get gc'd
    }
    if (hitDoc.doc == null) {
      hitDoc.doc = searcher.doc(hitDoc.id); // cache miss: read document
    }
    return hitDoc.doc;
}
// 得到第n个Document的得分
public final float score(int n) throws IOException {
    return hitDoc(n).score;
}
// 得到第n个Document的编号
public final int id(int n) throws IOException {
    return hitDoc(n).id;
}
public Iterator iterator() {
    return new HitIterator(this);
}
private final HitDoc hitDoc(int n) throws IOException {
    if (n >= length) {
      throw new IndexOutOfBoundsException("Not a valid hit number: " + n);
    }
    if (n >= hitDocs.size()) {
      getMoreDocs(n);
    }
    return (HitDoc) hitDocs.elementAt(n);
}
private final void addToFront(HitDoc hitDoc) { // insert at front of cache
    if (first == null) {
      last = hitDoc;
    } else {
      first.prev = hitDoc;
    }
    hitDoc.next = first;
    first = hitDoc;
    hitDoc.prev = null;
    numDocs++;
}
private final void remove(HitDoc hitDoc) {    // remove from cache
    if (hitDoc.doc == null) {     // it's not in the list
      return;                    // abort
    }
    if (hitDoc.next == null) {
      last = hitDoc.prev;
    } else {
      hitDoc.next.prev = hitDoc.prev;
    }
    if (hitDoc.prev == null) {
      first = hitDoc.next;
    } else {
      hitDoc.prev.next = hitDoc.next;
    }
    numDocs--;
}
}
final class HitDoc {
float score;
int id;
Document doc = null;
HitDoc next; // in doubly-linked cache
HitDoc prev; // in doubly-linked cache
HitDoc(float s, int i) {
    score = s;
    id = i;
}
}
上面代码中,红色标注的部分为后面测试之用。
一次查询时,需要构造一个Query实例。从Hits类的成员变量来看,在检索的过程中,一个Query实例并不是只使用一次,那么多次使用进行查询就需要记录这个Query实例的状态。
为了更加直观,写了一个测试类,来观察缓存长度的分配情况:
package org.shirdrn.lucene.learn.test;
import java.io.IOException;
import java.util.Date;
import java.util.Iterator;
import org.apache.lucene.analysis.cjk.CJKAnalyzer;
import org.apache.lucene.document.DateTools;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.Term;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.search.Hit;
import org.apache.lucene.search.Hits;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.store.LockObtainFailedException;
public class MyHitsTest {
   
    public void create() throws CorruptIndexException, LockObtainFailedException, IOException{
        String indexPath = "H:\\index";
        IndexWriter writer = new IndexWriter(indexPath,new CJKAnalyzer(),true);
        for(int i=0;i min = 50不成立,接着n = min*2 = 50*2 = 100,因此离开getMoreDocs()方法时hitDocs.size() = 100;
第二次进入getMoreDocs()方法时,hitDocs.size() = 100 > min = 50成立,从而设置min = hitDocs.size() = 100,接着n = min*2 = 100*2 = 200, 因此离开getMoreDocs()方法时hitDocs.size() = 200;
第三次进入getMoreDocs()方法时,hitDocs.size() = 200 > min = 100成立,从而设置min = hitDocs.size() = 200,接着n = min*2 = 200*2 = 400, 因此离开getMoreDocs()方法时hitDocs.size() = 400;
如果满足查询的检索结果的Document数量足够大的话,应该继续是:
第四次进入getMoreDocs()方法时,hitDocs.size() = 400,离开getMoreDocs()方法时hitDocs.size() = 800;
第五次进入getMoreDocs()方法时,hitDocs.size() = 800,离开getMoreDocs()方法时hitDocs.size() = 1600;
……
根据上面,最后一次(第四次)进入getMoreDocs()方法的时候,hitDocs.size() = 400 > min = 400不成立,接着n = min*2 = 400*2 = 800,此时虽然缓存扩充了,但是执行searcher.search(weight, filter, n) 的时候取到了100条满足条件的Document,故而缓存的实际大小为hitDocs.size() = 500, 因此离开getMoreDocs()方法时hitDocs.size() = 500,其实此次如果满足查询的Document数量足够,可以达到hitDocs.size() = 800。

分享到:
评论
1 楼 yyang1986321 2009-07-20  
   

相关推荐

    Lucene的原理完整版pdf

    4. **结果集(Hit)**:搜索返回一个`TopDocs`对象,包含匹配文档的总数和最高评分的文档集合。 ### 三、Lucene高级特性 1. **多字段搜索**:可以在多个字段上同时进行查询,通过`BooleanQuery`或`...

    Lucene.2.0.API

    3. **搜索模块**:包含`Hits`和`Hit`类,用于存储搜索结果。`Hits`是一个包含所有匹配文档的结果集,而`Hit`代表单个匹配文档的详细信息。 4. **分词模块**:Lucene内置了多个分词器,如StandardAnalyzer、...

    Lucene.Net.dll

    - **索引构建**:使用IndexWriter类创建和更新索引,将数据源(如数据库、文件系统等)中的内容导入Lucene索引。 - **查询执行**:通过QueryParser或直接构建Query对象来构造查询,然后使用IndexSearcher类执行查询...

    luceneDemo

    - `WEB-INF`: 这个目录在 Java Web 应用中存放配置文件、类文件等,可能包含了 Lucene 相关的类和配置。 - `META-INF`: 存放元数据,如应用的 MANIFEST.MF 文件,可能与 Lucene 索引的存储位置或元数据有关。 **...

    Lucene2.4.1

    此包中的类是实现Lucene核心功能的基础,例如: - `IndexReader`:读取已建立的索引。 - `IndexWriter`:用于创建新索引或更新现有索引。 - `Term`:代表索引中的一个唯一词汇。 - `Query`:表示用户要搜索的...

    lucene3.0.3搜索的使用示例

    4. **Document** 和 **Field** 类:Document是Lucene中的基本数据结构,代表一个要被索引的完整文档。每个文档包含多个Field,每个Field对应文档的一个属性或部分。 5. **IndexWriter**:用于创建或更新索引。你...

    Lucene 索引的简单使用

    6. **解析文档**:通过`indexSearcher.doc(hit.doc)`获取匹配的Document,并从中获取字段信息。 7. **关闭资源**:别忘了关闭IndexSearcher和IndexReader以释放资源。 ### 4. 高级特性 - **多字段索引**:一个...

    lucene详细使用教程

    3. **命中(Hit)与文档(Document)**:搜索结果以 Hit 形式返回,每个 Hit 包含文档的评分和文档 ID。通过文档 ID,我们可以从索引中获取 Document 对象,提取存储的字段内容。 **高级特性** 1. **多字段搜索**...

    lucene实例lucene实例

    3. 结果处理(Hit Processing):遍历搜索结果,获取匹配的文档,并可进一步获取字段信息。 ```java for (ScoreDoc sd : hits.scoreDocs) { Document doc = searcher.doc(sd.doc); System.out.println("Document ...

    lucene2.0.0

    Lucene 2.0.0的主要API包括以下几个关键类: 1. **IndexWriter**:用于创建和更新索引,管理索引段的合并。 2. **Directory**:表示存储索引的物理位置,如FSDirectory用于文件系统,RAMDirectory用于内存。 3. *...

    最新版linux lucene-8.6.1.tgz

    - **Hit**(命中):表示查询结果中的一个匹配项,包含文档ID和相关度分数。 在Lucene 8.6.1中,可能包含了一些新特性、性能改进和bug修复,例如: - **性能提升**:可能对搜索速度、内存占用等方面进行了优化。 - ...

    lucene 3.6

    5. **Searcher**:执行搜索操作的类,如 IndexSearcher,它使用查询解析器(QueryParser)将用户输入的查询转化为 Lucene 可理解的 Query 对象,然后在索引中执行搜索。 6. **Query**:Lucene 提供了多种查询类型,...

    Lucene搜索实例

    **Lucene 搜索实例** Apache Lucene 是一个高性能、全文本搜索引擎库,它为开发者提供了在各种应用程序中实现全文检索的工具集。Lucene 并不是一个完整的应用,而是一个 Java 类库,可以被其他 Java 应用程序所使用...

    lucene3.6.jar

    接着,当用户输入查询时,使用Analyzer解析查询字符串,生成Query对象,再用Searcher进行搜索操作,最后通过Hit集合获取高相关性的结果。 在实际应用中,开发者可能还需要关注以下几点: 1. 索引优化:为了提高...

    lucene-6.5.1

    - **手动集成**: 对于非Maven项目,则需要手动将Lucene的相关JAR包添加到项目的类路径中。 ### 使用示例 为了更好地理解Lucene的应用场景,下面提供一个简单的例子: ```java import org.apache.lucene.analysis....

    lucene-7.4.0jar包

    - **命中集(Hit Set)**:搜索结果的集合,包含每个文档的相关信息。 3. **Lucene 7.4.0新特性与改进** - **性能优化**:该版本提升了索引和搜索的速度,降低了内存消耗。 - **新API**:可能引入了新的编程接口...

    自己写的一个lucene知识点集合

    - **Hit**:TopDocs 包含了匹配文档的信息,通过 ScoreDoc 可以获取文档的得分和编号。 - **文档详情**:使用 Document 对象的 get() 方法获取命中文档的字段内容。 4. **高级特性** - **分面搜索**:使用 Facet...

    lucene-1.4.3

    在Lucene 1.4.3中,你可以使用标准搜索器(StandardSearcher)进行全文检索,或者使用Hit集合来获取匹配结果。 5. 查询解析器(QueryParser):Lucene 1.4.3中的QueryParser将用户输入的查询字符串转换为内部表示,...

    lucene.net 2.9.2 实现索引生成,修改,查询,删除实例

    在Lucene.NET中,我们通常会定义一个文档类,包含需要索引的字段。例如: ```csharp public class DocumentModel { [Field(Store = Store.YES, Analyze = true)] public string Title { get; set; } [Field...

Global site tag (gtag.js) - Google Analytics