KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > lucene > search > Hits


1 package org.apache.lucene.search;
2
3 /**
4  * Copyright 2004 The Apache Software Foundation
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */

18
19 import java.io.IOException JavaDoc;
20 import java.util.Vector JavaDoc;
21 import java.util.Iterator JavaDoc;
22
23 import org.apache.lucene.document.Document;
24
25 /** A ranked list of documents, used to hold search results. */
26 public final class Hits {
27   private Weight weight;
28   private Searcher searcher;
29   private Filter filter = null;
30   private Sort sort = null;
31
32   private int length; // the total number of hits
33
private Vector JavaDoc hitDocs = new Vector JavaDoc(); // cache of hits retrieved
34

35   private HitDoc first; // head of LRU cache
36
private HitDoc last; // tail of LRU cache
37
private int numDocs = 0; // number cached
38
private int maxDocs = 200; // max to cache
39

40   Hits(Searcher s, Query q, Filter f) throws IOException JavaDoc {
41     weight = q.weight(s);
42     searcher = s;
43     filter = f;
44     getMoreDocs(50); // retrieve 100 initially
45
}
46
47   Hits(Searcher s, Query q, Filter f, Sort o) throws IOException JavaDoc {
48     weight = q.weight(s);
49     searcher = s;
50     filter = f;
51     sort = o;
52     getMoreDocs(50); // retrieve 100 initially
53
}
54
55   /**
56    * Tries to add new documents to hitDocs.
57    * Ensures that the hit numbered <code>min</code> has been retrieved.
58    */

59   private final void getMoreDocs(int min) throws IOException JavaDoc {
60     if (hitDocs.size() > min) {
61       min = hitDocs.size();
62     }
63
64     int n = min * 2; // double # retrieved
65
TopDocs topDocs = (sort == null) ? searcher.search(weight, filter, n) : searcher.search(weight, filter, n, sort);
66     length = topDocs.totalHits;
67     ScoreDoc[] scoreDocs = topDocs.scoreDocs;
68
69     float scoreNorm = 1.0f;
70     
71     if (length > 0 && topDocs.getMaxScore() > 1.0f) {
72       scoreNorm = 1.0f / topDocs.getMaxScore();
73     }
74
75     int end = scoreDocs.length < length ? scoreDocs.length : length;
76     for (int i = hitDocs.size(); i < end; i++) {
77       hitDocs.addElement(new HitDoc(scoreDocs[i].score * scoreNorm,
78                                     scoreDocs[i].doc));
79     }
80   }
81
82   /** Returns the total number of hits available in this set. */
83   public final int length() {
84     return length;
85   }
86
87   /** Returns the stored fields of the n<sup>th</sup> document in this set.
88    <p>Documents are cached, so that repeated requests for the same element may
89    return the same Document object. */

90   public final Document doc(int n) throws IOException JavaDoc {
91     HitDoc hitDoc = hitDoc(n);
92
93     // Update LRU cache of documents
94
remove(hitDoc); // remove from list, if there
95
addToFront(hitDoc); // add to front of list
96
if (numDocs > maxDocs) { // if cache is full
97
HitDoc oldLast = last;
98       remove(last); // flush last
99
oldLast.doc = null; // let doc get gc'd
100
}
101
102     if (hitDoc.doc == null) {
103       hitDoc.doc = searcher.doc(hitDoc.id); // cache miss: read document
104
}
105
106     return hitDoc.doc;
107   }
108
109   /** Returns the score for the nth document in this set. */
110   public final float score(int n) throws IOException JavaDoc {
111     return hitDoc(n).score;
112   }
113
114   /** Returns the id for the nth document in this set. */
115   public final int id(int n) throws IOException JavaDoc {
116     return hitDoc(n).id;
117   }
118
119   /**
120    * Returns a {@link HitIterator} to navigate the Hits. Each item returned
121    * from {@link Iterator#next()} is a {@link Hit}.
122    * <p>
123    * <b>Caution:</b> Iterate only over the hits needed. Iterating over all
124    * hits is generally not desirable and may be the source of
125    * performance issues.
126    * </p>
127    */

128   public Iterator JavaDoc iterator() {
129     return new HitIterator(this);
130   }
131
132   private final HitDoc hitDoc(int n) throws IOException JavaDoc {
133     if (n >= length) {
134       throw new IndexOutOfBoundsException JavaDoc("Not a valid hit number: " + n);
135     }
136
137     if (n >= hitDocs.size()) {
138       getMoreDocs(n);
139     }
140
141     return (HitDoc) hitDocs.elementAt(n);
142   }
143
144   private final void addToFront(HitDoc hitDoc) { // insert at front of cache
145
if (first == null) {
146       last = hitDoc;
147     } else {
148       first.prev = hitDoc;
149     }
150
151     hitDoc.next = first;
152     first = hitDoc;
153     hitDoc.prev = null;
154
155     numDocs++;
156   }
157
158   private final void remove(HitDoc hitDoc) { // remove from cache
159
if (hitDoc.doc == null) { // it's not in the list
160
return; // abort
161
}
162
163     if (hitDoc.next == null) {
164       last = hitDoc.prev;
165     } else {
166       hitDoc.next.prev = hitDoc.prev;
167     }
168
169     if (hitDoc.prev == null) {
170       first = hitDoc.next;
171     } else {
172       hitDoc.prev.next = hitDoc.next;
173     }
174
175     numDocs--;
176   }
177 }
178
179 final class HitDoc {
180   float score;
181   int id;
182   Document doc = null;
183
184   HitDoc next; // in doubly-linked cache
185
HitDoc prev; // in doubly-linked cache
186

187   HitDoc(float s, int i) {
188     score = s;
189     id = i;
190   }
191 }
192
Popular Tags