Lucene.Net  3.0.3
Lucene.Net is a port of the Lucene search engine library, written in C# and targeted at .NET runtime users.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Properties Pages
IndexSearcher.cs
Go to the documentation of this file.
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 using System;
19 using System.Linq;
20 using Lucene.Net.Index;
21 using Document = Lucene.Net.Documents.Document;
22 using FieldSelector = Lucene.Net.Documents.FieldSelector;
24 using IndexReader = Lucene.Net.Index.IndexReader;
25 using Term = Lucene.Net.Index.Term;
26 using Directory = Lucene.Net.Store.Directory;
27 using ReaderUtil = Lucene.Net.Util.ReaderUtil;
28 
29 namespace Lucene.Net.Search
30 {
31 
32  /// <summary>Implements search over a single IndexReader.
33  ///
34  /// <p/>Applications usually need only call the inherited <see cref="Searcher.Search(Query,int)" />
35  /// or <see cref="Searcher.Search(Query,Filter,int)" /> methods. For performance reasons it is
36  /// recommended to open only one IndexSearcher and use it for all of your searches.
37  ///
38  /// <a name="thread-safety"></a><p/><b>NOTE</b>:
39  /// <see cref="IndexSearcher" /> instances are completely
40  /// thread safe, meaning multiple threads can call any of its
41  /// methods, concurrently. If your application requires
42  /// external synchronization, you should <b>not</b>
43  /// synchronize on the <c>IndexSearcher</c> instance;
44  /// use your own (non-Lucene) objects instead.<p/>
45  /// </summary>
46  [Serializable]
47  public class IndexSearcher : Searcher
48  {
49  internal IndexReader reader;
50  private bool closeReader;
51  private bool isDisposed;
52 
53  // NOTE: these members might change in incompatible ways
54  // in the next release
55  private IndexReader[] subReaders;
56  private int[] docStarts;
57 
58  /// <summary>Creates a searcher searching the index in the named
59  /// directory, with readOnly=true</summary>
60  /// <throws>CorruptIndexException if the index is corrupt</throws>
61  /// <throws>IOException if there is a low-level IO error</throws>
62  public IndexSearcher(Directory path)
63  : this(IndexReader.Open(path, true), true)
64  {
65  }
66 
67  /// <summary>Creates a searcher searching the index in the named
68  /// directory. You should pass readOnly=true, since it
69  /// gives much better concurrent performance, unless you
70  /// intend to do write operations (delete documents or
71  /// change norms) with the underlying IndexReader.
72  /// </summary>
73  /// <throws> CorruptIndexException if the index is corrupt </throws>
74  /// <throws> IOException if there is a low-level IO error </throws>
75  /// <param name="path">directory where IndexReader will be opened
76  /// </param>
77  /// <param name="readOnly">if true, the underlying IndexReader
78  /// will be opened readOnly
79  /// </param>
80  public IndexSearcher(Directory path, bool readOnly):this(IndexReader.Open(path, readOnly), true)
81  {
82  }
83 
84  /// <summary>Creates a searcher searching the provided index
85  /// <para>
86  /// Note that the underlying IndexReader is not closed, if
87  /// IndexSearcher was constructed with IndexSearcher(IndexReader r).
88  /// If the IndexReader was supplied implicitly by specifying a directory, then
89  /// the IndexReader gets closed.
90  /// </para>
91  /// </summary>
92  public IndexSearcher(IndexReader r):this(r, false)
93  {
94  }
95 
96  /// <summary>
97  /// Expert: directly specify the reader, subReaders and their
98  /// DocID starts
99  /// <p/>
100  /// <b>NOTE:</b> This API is experimental and
101  /// might change in incompatible ways in the next
102  /// release<p/>
103  /// </summary>
104  public IndexSearcher(IndexReader reader, IndexReader[] subReaders, int[] docStarts)
105  {
106  this.reader = reader;
107  this.subReaders = subReaders;
108  this.docStarts = docStarts;
109  this.closeReader = false;
110  }
111 
112  private IndexSearcher(IndexReader r, bool closeReader)
113  {
114  reader = r;
115  this.closeReader = closeReader;
116 
117  System.Collections.Generic.IList<IndexReader> subReadersList = new System.Collections.Generic.List<IndexReader>();
118  GatherSubReaders(subReadersList, reader);
119  subReaders = subReadersList.ToArray();
120  docStarts = new int[subReaders.Length];
121  int maxDoc = 0;
122  for (int i = 0; i < subReaders.Length; i++)
123  {
124  docStarts[i] = maxDoc;
125  maxDoc += subReaders[i].MaxDoc;
126  }
127  }
128 
129  protected internal virtual void GatherSubReaders(System.Collections.Generic.IList<IndexReader> allSubReaders, IndexReader r)
130  {
131  ReaderUtil.GatherSubReaders(allSubReaders, r);
132  }
133 
134  /// <summary>Return the <see cref="Index.IndexReader" /> this searches. </summary>
135  public virtual IndexReader IndexReader
136  {
137  get { return reader; }
138  }
139 
140  protected override void Dispose(bool disposing)
141  {
142  if (isDisposed) return;
143 
144  if (disposing)
145  {
146  if (closeReader)
147  reader.Close();
148  }
149 
150  isDisposed = true;
151  }
152 
153  // inherit javadoc
154  public override int DocFreq(Term term)
155  {
156  return reader.DocFreq(term);
157  }
158 
159  // inherit javadoc
160  public override Document Doc(int i)
161  {
162  return reader.Document(i);
163  }
164 
165  // inherit javadoc
166  public override Document Doc(int i, FieldSelector fieldSelector)
167  {
168  return reader.Document(i, fieldSelector);
169  }
170 
171  // inherit javadoc
172  public override int MaxDoc
173  {
174  get { return reader.MaxDoc; }
175  }
176 
177  // inherit javadoc
178  public override TopDocs Search(Weight weight, Filter filter, int nDocs)
179  {
180 
181  if (nDocs <= 0)
182  {
183  throw new System.ArgumentException("nDocs must be > 0");
184  }
185  nDocs = Math.Min(nDocs, reader.MaxDoc);
186 
188  Search(weight, filter, collector);
189  return collector.TopDocs();
190  }
191 
192  public override TopFieldDocs Search(Weight weight, Filter filter, int nDocs, Sort sort)
193  {
194  return Search(weight, filter, nDocs, sort, true);
195  }
196 
197  /// <summary> Just like <see cref="Search(Weight, Filter, int, Sort)" />, but you choose
198  /// whether or not the fields in the returned <see cref="FieldDoc" /> instances
199  /// should be set by specifying fillFields.
200  /// <p/>
201  /// NOTE: this does not compute scores by default. If you need scores, create
202  /// a <see cref="TopFieldCollector" /> instance by calling
203  /// <see cref="TopFieldCollector.Create" /> and then pass that to
204  /// <see cref="Search(Weight, Filter, Collector)" />.
205  /// <p/>
206  /// </summary>
207  public virtual TopFieldDocs Search(Weight weight, Filter filter, int nDocs, Sort sort, bool fillFields)
208  {
209  nDocs = Math.Min(nDocs, reader.MaxDoc);
210 
211  TopFieldCollector collector2 = TopFieldCollector.Create(sort, nDocs, fillFields, fieldSortDoTrackScores, fieldSortDoMaxScore, !weight.GetScoresDocsOutOfOrder());
212  Search(weight, filter, collector2);
213  return (TopFieldDocs) collector2.TopDocs();
214  }
215 
216  public override void Search(Weight weight, Filter filter, Collector collector)
217  {
218 
219  if (filter == null)
220  {
221  for (int i = 0; i < subReaders.Length; i++)
222  {
223  // search each subreader
224  collector.SetNextReader(subReaders[i], docStarts[i]);
225  Scorer scorer = weight.Scorer(subReaders[i], !collector.AcceptsDocsOutOfOrder, true);
226  if (scorer != null)
227  {
228  scorer.Score(collector);
229  }
230  }
231  }
232  else
233  {
234  for (int i = 0; i < subReaders.Length; i++)
235  {
236  // search each subreader
237  collector.SetNextReader(subReaders[i], docStarts[i]);
238  SearchWithFilter(subReaders[i], weight, filter, collector);
239  }
240  }
241  }
242 
243  private void SearchWithFilter(IndexReader reader, Weight weight, Filter filter, Collector collector)
244  {
245 
246  System.Diagnostics.Debug.Assert(filter != null);
247 
248  Scorer scorer = weight.Scorer(reader, true, false);
249  if (scorer == null)
250  {
251  return ;
252  }
253 
254  int docID = scorer.DocID();
255  System.Diagnostics.Debug.Assert(docID == - 1 || docID == DocIdSetIterator.NO_MORE_DOCS);
256 
257  // CHECKME: use ConjunctionScorer here?
258  DocIdSet filterDocIdSet = filter.GetDocIdSet(reader);
259  if (filterDocIdSet == null)
260  {
261  // this means the filter does not accept any documents.
262  return ;
263  }
264 
265  DocIdSetIterator filterIter = filterDocIdSet.Iterator();
266  if (filterIter == null)
267  {
268  // this means the filter does not accept any documents.
269  return ;
270  }
271  int filterDoc = filterIter.NextDoc();
272  int scorerDoc = scorer.Advance(filterDoc);
273 
274  collector.SetScorer(scorer);
275  while (true)
276  {
277  if (scorerDoc == filterDoc)
278  {
279  // Check if scorer has exhausted, only before collecting.
280  if (scorerDoc == DocIdSetIterator.NO_MORE_DOCS)
281  {
282  break;
283  }
284  collector.Collect(scorerDoc);
285  filterDoc = filterIter.NextDoc();
286  scorerDoc = scorer.Advance(filterDoc);
287  }
288  else if (scorerDoc > filterDoc)
289  {
290  filterDoc = filterIter.Advance(scorerDoc);
291  }
292  else
293  {
294  scorerDoc = scorer.Advance(filterDoc);
295  }
296  }
297  }
298 
299  public override Query Rewrite(Query original)
300  {
301  Query query = original;
302  for (Query rewrittenQuery = query.Rewrite(reader); rewrittenQuery != query; rewrittenQuery = query.Rewrite(reader))
303  {
304  query = rewrittenQuery;
305  }
306  return query;
307  }
308 
309  public override Explanation Explain(Weight weight, int doc)
310  {
311  int n = ReaderUtil.SubIndex(doc, docStarts);
312  int deBasedDoc = doc - docStarts[n];
313 
314  return weight.Explain(subReaders[n], deBasedDoc);
315  }
316 
317  private bool fieldSortDoTrackScores;
318  private bool fieldSortDoMaxScore;
319 
320  /// <summary> By default, no scores are computed when sorting by field (using
321  /// <see cref="Searcher.Search(Query,Filter,int,Sort)" />). You can change that, per
322  /// IndexSearcher instance, by calling this method. Note that this will incur
323  /// a CPU cost.
324  ///
325  /// </summary>
326  /// <param name="doTrackScores">If true, then scores are returned for every matching document
327  /// in <see cref="TopFieldDocs" />.
328  ///
329  /// </param>
330  /// <param name="doMaxScore">If true, then the max score for all matching docs is computed.
331  /// </param>
332  public virtual void SetDefaultFieldSortScoring(bool doTrackScores, bool doMaxScore)
333  {
334  fieldSortDoTrackScores = doTrackScores;
335  fieldSortDoMaxScore = doMaxScore;
336  }
337 
338  public IndexReader reader_ForNUnit
339  {
340  get { return reader; }
341  }
342  }
343 }