KickJava   Java API By Example, From Geeks To Geeks.

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


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
21 import org.apache.lucene.index.Term;
22 import org.apache.lucene.util.PriorityQueue;
23
24 /** Implements parallel search over a set of <code>Searchables</code>.
25  *
26  * <p>Applications usually need only call the inherited {@link #search(Query)}
27  * or {@link #search(Query,Filter)} methods.
28  */

29 public class ParallelMultiSearcher extends MultiSearcher {
30
31   private Searchable[] searchables;
32   private int[] starts;
33     
34   /** Creates a searcher which searches <i>searchables</i>. */
35   public ParallelMultiSearcher(Searchable[] searchables) throws IOException JavaDoc {
36     super(searchables);
37     this.searchables=searchables;
38     this.starts=getStarts();
39   }
40
41   /**
42    * TODO: parallelize this one too
43    */

44   public int docFreq(Term term) throws IOException JavaDoc {
45     return super.docFreq(term);
46   }
47
48   /**
49    * A search implementation which spans a new thread for each
50    * Searchable, waits for each search to complete and merge
51    * the results back together.
52    */

53   public TopDocs search(Weight weight, Filter filter, int nDocs)
54     throws IOException JavaDoc {
55     HitQueue hq = new HitQueue(nDocs);
56     int totalHits = 0;
57     MultiSearcherThread[] msta =
58       new MultiSearcherThread[searchables.length];
59     for (int i = 0; i < searchables.length; i++) { // search each searcher
60
// Assume not too many searchables and cost of creating a thread is by far inferior to a search
61
msta[i] =
62         new MultiSearcherThread(
63                                 searchables[i],
64                                 weight,
65                                 filter,
66                                 nDocs,
67                                 hq,
68                                 i,
69                                 starts,
70                                 "MultiSearcher thread #" + (i + 1));
71       msta[i].start();
72     }
73
74     for (int i = 0; i < searchables.length; i++) {
75       try {
76         msta[i].join();
77       } catch (InterruptedException JavaDoc ie) {
78         ; // TODO: what should we do with this???
79
}
80       IOException JavaDoc ioe = msta[i].getIOException();
81       if (ioe == null) {
82         totalHits += msta[i].hits();
83       } else {
84         // if one search produced an IOException, rethrow it
85
throw ioe;
86       }
87     }
88
89     ScoreDoc[] scoreDocs = new ScoreDoc[hq.size()];
90     for (int i = hq.size() - 1; i >= 0; i--) // put docs in array
91
scoreDocs[i] = (ScoreDoc) hq.pop();
92
93     float maxScore = (totalHits==0) ? Float.NEGATIVE_INFINITY : scoreDocs[0].score;
94     
95     return new TopDocs(totalHits, scoreDocs, maxScore);
96   }
97
98   /**
99    * A search implementation allowing sorting which spans a new thread for each
100    * Searchable, waits for each search to complete and merges
101    * the results back together.
102    */

103   public TopFieldDocs search(Weight weight, Filter filter, int nDocs, Sort sort)
104     throws IOException JavaDoc {
105     // don't specify the fields - we'll wait to do this until we get results
106
FieldDocSortedHitQueue hq = new FieldDocSortedHitQueue (null, nDocs);
107     int totalHits = 0;
108     MultiSearcherThread[] msta = new MultiSearcherThread[searchables.length];
109     for (int i = 0; i < searchables.length; i++) { // search each searcher
110
// Assume not too many searchables and cost of creating a thread is by far inferior to a search
111
msta[i] =
112         new MultiSearcherThread(
113                                 searchables[i],
114                                 weight,
115                                 filter,
116                                 nDocs,
117                                 hq,
118                                 sort,
119                                 i,
120                                 starts,
121                                 "MultiSearcher thread #" + (i + 1));
122       msta[i].start();
123     }
124
125     float maxScore=Float.NEGATIVE_INFINITY;
126     
127     for (int i = 0; i < searchables.length; i++) {
128       try {
129         msta[i].join();
130       } catch (InterruptedException JavaDoc ie) {
131         ; // TODO: what should we do with this???
132
}
133       IOException JavaDoc ioe = msta[i].getIOException();
134       if (ioe == null) {
135         totalHits += msta[i].hits();
136         maxScore=Math.max(maxScore, msta[i].getMaxScore());
137       } else {
138         // if one search produced an IOException, rethrow it
139
throw ioe;
140       }
141     }
142
143     ScoreDoc[] scoreDocs = new ScoreDoc[hq.size()];
144     for (int i = hq.size() - 1; i >= 0; i--) // put docs in array
145
scoreDocs[i] = (ScoreDoc) hq.pop();
146
147     return new TopFieldDocs(totalHits, scoreDocs, hq.getFields(), maxScore);
148   }
149
150   /** Lower-level search API.
151    *
152    * <p>{@link HitCollector#collect(int,float)} is called for every non-zero
153    * scoring document.
154    *
155    * <p>Applications should only use this if they need <i>all</i> of the
156    * matching documents. The high-level search API ({@link
157    * Searcher#search(Query)}) is usually more efficient, as it skips
158    * non-high-scoring hits.
159    *
160    * @param weight to match documents
161    * @param filter if non-null, a bitset used to eliminate some documents
162    * @param results to receive hits
163    *
164    * @todo parallelize this one too
165    */

166   public void search(Weight weight, Filter filter, final HitCollector results)
167     throws IOException JavaDoc {
168     for (int i = 0; i < searchables.length; i++) {
169
170       final int start = starts[i];
171
172       searchables[i].search(weight, filter, new HitCollector() {
173           public void collect(int doc, float score) {
174             results.collect(doc + start, score);
175           }
176         });
177
178     }
179   }
180
181   /*
182    * TODO: this one could be parallelized too
183    * @see org.apache.lucene.search.Searchable#rewrite(org.apache.lucene.search.Query)
184    */

185   public Query rewrite(Query original) throws IOException JavaDoc {
186     return super.rewrite(original);
187   }
188
189 }
190
191 /**
192  * A thread subclass for searching a single searchable
193  */

194 class MultiSearcherThread extends Thread JavaDoc {
195
196   private Searchable searchable;
197   private Weight weight;
198   private Filter filter;
199   private int nDocs;
200   private TopDocs docs;
201   private int i;
202   private PriorityQueue hq;
203   private int[] starts;
204   private IOException JavaDoc ioe;
205   private Sort sort;
206
207   public MultiSearcherThread(
208                              Searchable searchable,
209                              Weight weight,
210                              Filter filter,
211                              int nDocs,
212                              HitQueue hq,
213                              int i,
214                              int[] starts,
215                              String JavaDoc name) {
216     super(name);
217     this.searchable = searchable;
218     this.weight = weight;
219     this.filter = filter;
220     this.nDocs = nDocs;
221     this.hq = hq;
222     this.i = i;
223     this.starts = starts;
224   }
225
226   public MultiSearcherThread(
227                              Searchable searchable,
228                              Weight weight,
229                              Filter filter,
230                              int nDocs,
231                              FieldDocSortedHitQueue hq,
232                              Sort sort,
233                              int i,
234                              int[] starts,
235                              String JavaDoc name) {
236     super(name);
237     this.searchable = searchable;
238     this.weight = weight;
239     this.filter = filter;
240     this.nDocs = nDocs;
241     this.hq = hq;
242     this.i = i;
243     this.starts = starts;
244     this.sort = sort;
245   }
246
247   public void run() {
248     try {
249       docs = (sort == null) ? searchable.search (weight, filter, nDocs)
250         : searchable.search (weight, filter, nDocs, sort);
251     }
252     // Store the IOException for later use by the caller of this thread
253
catch (IOException JavaDoc ioe) {
254       this.ioe = ioe;
255     }
256     if (ioe == null) {
257       // if we are sorting by fields, we need to tell the field sorted hit queue
258
// the actual type of fields, in case the original list contained AUTO.
259
// if the searchable returns null for fields, we'll have problems.
260
if (sort != null) {
261         ((FieldDocSortedHitQueue)hq).setFields (((TopFieldDocs)docs).fields);
262       }
263       ScoreDoc[] scoreDocs = docs.scoreDocs;
264       for (int j = 0;
265            j < scoreDocs.length;
266            j++) { // merge scoreDocs into hq
267
ScoreDoc scoreDoc = scoreDocs[j];
268         scoreDoc.doc += starts[i]; // convert doc
269
//it would be so nice if we had a thread-safe insert
270
synchronized (hq) {
271           if (!hq.insert(scoreDoc))
272             break;
273         } // no more scores > minScore
274
}
275     }
276   }
277
278   public int hits() {
279     return docs.totalHits;
280   }
281
282   public float getMaxScore() {
283       return docs.getMaxScore();
284   }
285   
286   public IOException JavaDoc getIOException() {
287     return ioe;
288   }
289
290 }
291
Popular Tags