/* * Copyright 2004 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using Document = Lucene.Net.Documents.Document; using Term = Lucene.Net.Index.Term; namespace Lucene.Net.Search { /// Implements search over a set of Searchables. /// ///

Applications usually need only call the inherited {@link #Search(Query)} /// or {@link #Search(Query,Filter)} methods. ///

public class MultiSearcher : Searcher { private class AnonymousClassHitCollector : HitCollector { public AnonymousClassHitCollector(Lucene.Net.Search.HitCollector results, int start, MultiSearcher enclosingInstance) { InitBlock(results, start, enclosingInstance); } private void InitBlock(Lucene.Net.Search.HitCollector results, int start, MultiSearcher enclosingInstance) { this.results = results; this.start = start; this.enclosingInstance = enclosingInstance; } private Lucene.Net.Search.HitCollector results; private int start; private MultiSearcher enclosingInstance; public MultiSearcher Enclosing_Instance { get { return enclosingInstance; } } public override void Collect(int doc, float score) { results.Collect(doc + start, score); } } private Lucene.Net.Search.Searchable[] searchables; private int[] starts; private int maxDoc = 0; /// Creates a searcher which searches searchables. public MultiSearcher(Lucene.Net.Search.Searchable[] searchables) { this.searchables = searchables; starts = new int[searchables.Length + 1]; // build starts array for (int i = 0; i < searchables.Length; i++) { starts[i] = maxDoc; maxDoc += searchables[i].MaxDoc(); // compute maxDocs } starts[searchables.Length] = maxDoc; } protected internal virtual int[] GetStarts() { return starts; } // inherit javadoc public override void Close() { for (int i = 0; i < searchables.Length; i++) searchables[i].Close(); } public override int DocFreq(Term term) { int docFreq = 0; for (int i = 0; i < searchables.Length; i++) docFreq += searchables[i].DocFreq(term); return docFreq; } // inherit javadoc public override Document Doc(int n) { int i = SubSearcher(n); // find searcher index return searchables[i].Doc(n - starts[i]); // dispatch to searcher } /// Call {@link #subSearcher} instead. /// /// public virtual int SearcherIndex(int n) { return SubSearcher(n); } /// Returns index of the searcher for document n in the array /// used to construct this searcher. /// public virtual int SubSearcher(int n) { // find searcher for doc n: // replace w/ call to Arrays.binarySearch in Java 1.2 int lo = 0; // search starts array int hi = searchables.Length - 1; // for first element less // than n, return its index while (hi >= lo) { int mid = (lo + hi) >> 1; int midValue = starts[mid]; if (n < midValue) hi = mid - 1; else if (n > midValue) lo = mid + 1; else { // found a match while (mid + 1 < searchables.Length && starts[mid + 1] == midValue) { mid++; // scan to last match } return mid; } } return hi; } /// Returns the document number of document n within its /// sub-index. /// public virtual int SubDoc(int n) { return n - starts[SubSearcher(n)]; } public override int MaxDoc() { return maxDoc; } public override TopDocs Search(Query query, Filter filter, int nDocs) { HitQueue hq = new HitQueue(nDocs); int totalHits = 0; for (int i = 0; i < searchables.Length; i++) { // search each searcher TopDocs docs = searchables[i].Search(query, filter, nDocs); totalHits += docs.totalHits; // update totalHits ScoreDoc[] scoreDocs = docs.scoreDocs; for (int j = 0; j < scoreDocs.Length; j++) { // merge scoreDocs into hq ScoreDoc scoreDoc = scoreDocs[j]; scoreDoc.doc += starts[i]; // convert doc if (!hq.Insert(scoreDoc)) break; // no more scores > minScore } } ScoreDoc[] scoreDocs2 = new ScoreDoc[hq.Size()]; for (int i = hq.Size() - 1; i >= 0; i--) // put docs in array scoreDocs2[i] = (ScoreDoc) hq.Pop(); return new TopDocs(totalHits, scoreDocs2); } public override TopFieldDocs Search(Query query, Filter filter, int n, Sort sort) { FieldDocSortedHitQueue hq = null; int totalHits = 0; for (int i = 0; i < searchables.Length; i++) { // search each searcher TopFieldDocs docs = searchables[i].Search(query, filter, n, sort); if (hq == null) hq = new FieldDocSortedHitQueue(docs.fields, n); totalHits += docs.totalHits; // update totalHits ScoreDoc[] scoreDocs = docs.scoreDocs; for (int j = 0; j < scoreDocs.Length; j++) { // merge scoreDocs into hq ScoreDoc scoreDoc = scoreDocs[j]; scoreDoc.doc += starts[i]; // convert doc if (!hq.Insert(scoreDoc)) break; // no more scores > minScore } } ScoreDoc[] scoreDocs2 = new ScoreDoc[hq.Size()]; for (int i = hq.Size() - 1; i >= 0; i--) // put docs in array scoreDocs2[i] = (ScoreDoc) hq.Pop(); return new TopFieldDocs(totalHits, scoreDocs2, hq.GetFields()); } // inherit javadoc public override void Search(Query query, Filter filter, HitCollector results) { for (int i = 0; i < searchables.Length; i++) { int start = starts[i]; searchables[i].Search(query, filter, new AnonymousClassHitCollector(results, start, this)); } } public override Query Rewrite(Query original) { Query[] queries = new Query[searchables.Length]; for (int i = 0; i < searchables.Length; i++) { queries[i] = searchables[i].Rewrite(original); } return original.Combine(queries); } public override Explanation Explain(Query query, int doc) { int i = SubSearcher(doc); // find searcher index return searchables[i].Explain(query, doc - starts[i]); // dispatch to searcher } } }