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 using Term
= Lucene
.Net
.Index
.Term
;
19 namespace Lucene
.Net
.Search
22 /// <summary>Implements search over a set of <code>Searchables</code>.
24 /// <p>Applications usually need only call the inherited {@link #Search(Query)}
25 /// or {@link #Search(Query,Filter)} methods.
27 public class MultiSearcher
: Searcher
29 private class AnonymousClassHitCollector
: HitCollector
31 public AnonymousClassHitCollector(Lucene
.Net
.Search
.HitCollector results
, int start
, MultiSearcher enclosingInstance
)
33 InitBlock(results
, start
, enclosingInstance
);
35 private void InitBlock(Lucene
.Net
.Search
.HitCollector results
, int start
, MultiSearcher enclosingInstance
)
37 this.results
= results
;
39 this.enclosingInstance
= enclosingInstance
;
41 private Lucene
.Net
.Search
.HitCollector results
;
43 private MultiSearcher enclosingInstance
;
44 public MultiSearcher Enclosing_Instance
48 return enclosingInstance
;
52 public override void Collect(int doc
, float score
)
54 results
.Collect(doc
+ start
, score
);
57 private Lucene
.Net
.Search
.Searchable
[] searchables
;
59 private int maxDoc
= 0;
61 /// <summary>Creates a searcher which searches <i>searchables</i>. </summary>
62 public MultiSearcher(Lucene
.Net
.Search
.Searchable
[] searchables
)
64 this.searchables
= searchables
;
66 starts
= new int[searchables
.Length
+ 1]; // build starts array
67 for (int i
= 0; i
< searchables
.Length
; i
++)
70 maxDoc
+= searchables
[i
].MaxDoc(); // compute maxDocs
72 starts
[searchables
.Length
] = maxDoc
;
75 protected internal virtual int[] GetStarts()
81 public override void Close()
83 for (int i
= 0; i
< searchables
.Length
; i
++)
84 searchables
[i
].Close();
87 public override int DocFreq(Term term
)
90 for (int i
= 0; i
< searchables
.Length
; i
++)
91 docFreq
+= searchables
[i
].DocFreq(term
);
96 public override Document
Doc(int n
)
98 int i
= SubSearcher(n
); // find searcher index
99 return searchables
[i
].Doc(n
- starts
[i
]); // dispatch to searcher
102 /// <summary>Call {@link #subSearcher} instead.</summary>
105 public virtual int SearcherIndex(int n
)
107 return SubSearcher(n
);
110 /// <summary>Returns index of the searcher for document <code>n</code> in the array
111 /// used to construct this searcher.
113 public virtual int SubSearcher(int n
)
115 // find searcher for doc n:
116 // replace w/ call to Arrays.binarySearch in Java 1.2
117 int lo
= 0; // search starts array
118 int hi
= searchables
.Length
- 1; // for first element less
119 // than n, return its index
122 int mid
= (lo
+ hi
) >> 1;
123 int midValue
= starts
[mid
];
126 else if (n
> midValue
)
131 while (mid
+ 1 < searchables
.Length
&& starts
[mid
+ 1] == midValue
)
133 mid
++; // scan to last match
141 /// <summary>Returns the document number of document <code>n</code> within its
144 public virtual int SubDoc(int n
)
146 return n
- starts
[SubSearcher(n
)];
149 public override int MaxDoc()
154 public override TopDocs
Search(Query query
, Filter filter
, int nDocs
)
156 HitQueue hq
= new HitQueue(nDocs
);
159 for (int i
= 0; i
< searchables
.Length
; i
++)
161 // search each searcher
162 TopDocs docs
= searchables
[i
].Search(query
, filter
, nDocs
);
163 totalHits
+= docs
.totalHits
; // update totalHits
164 ScoreDoc
[] scoreDocs
= docs
.scoreDocs
;
165 for (int j
= 0; j
< scoreDocs
.Length
; j
++)
167 // merge scoreDocs into hq
168 ScoreDoc scoreDoc
= scoreDocs
[j
];
169 scoreDoc
.doc
+= starts
[i
]; // convert doc
170 if (!hq
.Insert(scoreDoc
))
171 break; // no more scores > minScore
175 ScoreDoc
[] scoreDocs2
= new ScoreDoc
[hq
.Size()];
176 for (int i
= hq
.Size() - 1; i
>= 0; i
--)
178 scoreDocs2
[i
] = (ScoreDoc
) hq
.Pop();
180 return new TopDocs(totalHits
, scoreDocs2
);
184 public override TopFieldDocs
Search(Query query
, Filter filter
, int n
, Sort sort
)
186 FieldDocSortedHitQueue hq
= null;
189 for (int i
= 0; i
< searchables
.Length
; i
++)
191 // search each searcher
192 TopFieldDocs docs
= searchables
[i
].Search(query
, filter
, n
, sort
);
194 hq
= new FieldDocSortedHitQueue(docs
.fields
, n
);
195 totalHits
+= docs
.totalHits
; // update totalHits
196 ScoreDoc
[] scoreDocs
= docs
.scoreDocs
;
197 for (int j
= 0; j
< scoreDocs
.Length
; j
++)
199 // merge scoreDocs into hq
200 ScoreDoc scoreDoc
= scoreDocs
[j
];
201 scoreDoc
.doc
+= starts
[i
]; // convert doc
202 if (!hq
.Insert(scoreDoc
))
203 break; // no more scores > minScore
207 ScoreDoc
[] scoreDocs2
= new ScoreDoc
[hq
.Size()];
208 for (int i
= hq
.Size() - 1; i
>= 0; i
--)
210 scoreDocs2
[i
] = (ScoreDoc
) hq
.Pop();
212 return new TopFieldDocs(totalHits
, scoreDocs2
, hq
.GetFields());
217 public override void Search(Query query
, Filter filter
, HitCollector results
)
219 for (int i
= 0; i
< searchables
.Length
; i
++)
222 int start
= starts
[i
];
224 searchables
[i
].Search(query
, filter
, new AnonymousClassHitCollector(results
, start
, this));
228 public override Query
Rewrite(Query original
)
230 Query
[] queries
= new Query
[searchables
.Length
];
231 for (int i
= 0; i
< searchables
.Length
; i
++)
233 queries
[i
] = searchables
[i
].Rewrite(original
);
235 return original
.Combine(queries
);
238 public override Explanation
Explain(Query query
, int doc
)
240 int i
= SubSearcher(doc
); // find searcher index
241 return searchables
[i
].Explain(query
, doc
- starts
[i
]); // dispatch to searcher