2 * Copyright 2004 The Apache Software Foundation
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 using Document
= Lucene
.Net
.Documents
.Document
;
18 namespace Lucene
.Net
.Search
21 /// <summary>A ranked list of documents, used to hold search results. </summary>
22 public sealed class Hits
25 private Searcher searcher
;
26 private Filter filter
= null;
27 private Sort sort
= null;
29 private int length
; // the total number of hits
30 private System
.Collections
.ArrayList hitDocs
= System
.Collections
.ArrayList
.Synchronized(new System
.Collections
.ArrayList(10)); // cache of hits retrieved
32 private HitDoc first
; // head of LRU cache
33 private HitDoc last
; // tail of LRU cache
34 private int numDocs
= 0; // number cached
35 private int maxDocs
= 200; // max to cache
37 internal Hits(Searcher s
, Query q
, Filter f
)
42 GetMoreDocs(50); // retrieve 100 initially
45 internal Hits(Searcher s
, Query q
, Filter f
, Sort o
)
51 GetMoreDocs(50); // retrieve 100 initially
54 /// <summary> Tries to add new documents to hitDocs.
55 /// Ensures that the hit numbered <code>min</code> has been retrieved.
57 private void GetMoreDocs(int min
)
59 if (hitDocs
.Count
> min
)
64 int n
= min
* 2; // double # retrieved
65 TopDocs topDocs
= (sort
== null) ? searcher
.Search(query
, filter
, n
) : searcher
.Search(query
, filter
, n
, sort
);
66 length
= topDocs
.totalHits
;
67 ScoreDoc
[] scoreDocs
= topDocs
.scoreDocs
;
69 float scoreNorm
= 1.0f
;
70 if (length
> 0 && scoreDocs
[0].score
> 1.0f
)
72 scoreNorm
= 1.0f
/ scoreDocs
[0].score
;
75 int end
= scoreDocs
.Length
< length
?scoreDocs
.Length
:length
;
76 for (int i
= hitDocs
.Count
; i
< end
; i
++)
78 hitDocs
.Add(new HitDoc(scoreDocs
[i
].score
* scoreNorm
, scoreDocs
[i
].doc
));
82 /// <summary>Returns the total number of hits available in this set. </summary>
88 /// <summary>Returns the stored fields of the n<sup>th</sup> document in this set.
89 /// <p>Documents are cached, so that repeated requests for the same element may
90 /// return the same Document object.
92 public Document
Doc(int n
)
94 HitDoc hitDoc
= HitDoc(n
);
96 // Update LRU cache of documents
97 Remove(hitDoc
); // remove from list, if there
98 AddToFront(hitDoc
); // add to front of list
99 if (numDocs
> maxDocs
)
102 HitDoc oldLast
= last
;
103 Remove(last
); // flush last
104 oldLast
.doc
= null; // let doc get gc'd
107 if (hitDoc
.doc
== null)
109 hitDoc
.doc
= searcher
.Doc(hitDoc
.id
); // cache miss: read document
115 /// <summary>Returns the score for the nth document in this set. </summary>
116 public float Score(int n
)
118 return HitDoc(n
).score
;
121 /// <summary>Returns the id for the nth document in this set. </summary>
128 private HitDoc
HitDoc(int n
)
132 throw new System
.IndexOutOfRangeException("Not a valid hit number: " + n
);
135 if (n
>= hitDocs
.Count
)
140 return (HitDoc
) hitDocs
[n
];
143 private void AddToFront(HitDoc hitDoc
)
145 // insert at front of cache
162 private void Remove(HitDoc hitDoc
)
165 if (hitDoc
.doc
== null)
167 // it's not in the list
171 if (hitDoc
.next
== null)
177 hitDoc
.next
.prev
= hitDoc
.prev
;
180 if (hitDoc
.prev
== null)
186 hitDoc
.prev
.next
= hitDoc
.next
;
195 internal float score
;
197 internal Document doc
= null;
199 internal HitDoc next
; // in doubly-linked cache
200 internal HitDoc prev
; // in doubly-linked cache
202 internal HitDoc(float s
, int i
)