1 package org.apache.lucene.search;
2
3 /**
4 * Licensed to the Apache Software Foundation (ASF) under one or more
5 * contributor license agreements. See the NOTICE file distributed with
6 * this work for additional information regarding copyright ownership.
7 * The ASF licenses this file to You under the Apache License, Version 2.0
8 * (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19
20 import org.apache.lucene.document.Document;
21 import org.apache.lucene.document.FieldSelector;
22 import org.apache.lucene.index.CorruptIndexException;
23 import org.apache.lucene.index.IndexReader;
24 import org.apache.lucene.index.Term;
25 import org.apache.lucene.store.Directory;
26
27 import java.io.IOException;
28
29 /** Implements search over a single IndexReader.
30 *
31 * <p>Applications usually need only call the inherited {@link #search(Query)}
32 * or {@link #search(Query,Filter)} methods. For performance reasons it is
33 * recommended to open only one IndexSearcher and use it for all of your searches.
34 *
35 * <p>Note that you can only access Hits from an IndexSearcher as long as it is
36 * not yet closed, otherwise an IOException will be thrown.
37 */
38 public class IndexSearcher extends Searcher {
39 IndexReader reader;
40 private boolean closeReader;
41
42 /** Creates a searcher searching the index in the named directory.
43 * @throws CorruptIndexException if the index is corrupt
44 * @throws IOException if there is a low-level IO error
45 */
46 public IndexSearcher(String path) throws CorruptIndexException, IOException {
47 this(IndexReader.open(path), true);
48 }
49
50 /** Creates a searcher searching the index in the provided directory.
51 * @throws CorruptIndexException if the index is corrupt
52 * @throws IOException if there is a low-level IO error
53 */
54 public IndexSearcher(Directory directory) throws CorruptIndexException, IOException {
55 this(IndexReader.open(directory), true);
56 }
57
58 /** Creates a searcher searching the provided index. */
59 public IndexSearcher(IndexReader r) {
60 this(r, false);
61 }
62
63 private IndexSearcher(IndexReader r, boolean closeReader) {
64 reader = r;
65 this.closeReader = closeReader;
66 }
67
68 /** Return the {@link IndexReader} this searches. */
69 public IndexReader getIndexReader() {
70 return reader;
71 }
72
73 /**
74 * Note that the underlying IndexReader is not closed, if
75 * IndexSearcher was constructed with IndexSearcher(IndexReader r).
76 * If the IndexReader was supplied implicitly by specifying a directory, then
77 * the IndexReader gets closed.
78 */
79 public void close() throws IOException {
80 if(closeReader)
81 reader.close();
82 }
83
84 // inherit javadoc
85 public int docFreq(Term term) throws IOException {
86 return reader.docFreq(term);
87 }
88
89 // inherit javadoc
90 public Document doc(int i) throws CorruptIndexException, IOException {
91 return reader.document(i);
92 }
93
94 // inherit javadoc
95 public Document doc(int i, FieldSelector fieldSelector) throws CorruptIndexException, IOException {
96 return reader.document(i, fieldSelector);
97 }
98
99 // inherit javadoc
100 public int maxDoc() throws IOException {
101 return reader.maxDoc();
102 }
103
104 // inherit javadoc
105 public TopDocs search(Weight weight, Filter filter, final int nDocs)
106 throws IOException {
107
108 if (nDocs <= 0) // null might be returned from hq.top() below.
109 throw new IllegalArgumentException("nDocs must be > 0");
110
111 TopDocCollector collector = new TopDocCollector(nDocs);
112 search(weight, filter, collector);
113 return collector.topDocs();
114 }
115
116 // inherit javadoc
117 public TopFieldDocs search(Weight weight, Filter filter, final int nDocs,
118 Sort sort)
119 throws IOException {
120
121 TopFieldDocCollector collector =
122 new TopFieldDocCollector(reader, sort, nDocs);
123 search(weight, filter, collector);
124 return (TopFieldDocs)collector.topDocs();
125 }
126
127 // inherit javadoc
128 public void search(Weight weight, Filter filter,
129 final HitCollector results) throws IOException {
130
131 Scorer scorer = weight.scorer(reader);
132 if (scorer == null)
133 return;
134
135 if (filter == null) {
136 scorer.score(results);
137 return;
138 }
139
140 DocIdSetIterator filterDocIdIterator = filter.getDocIdSet(reader).iterator(); // CHECKME: use ConjunctionScorer here?
141
142 boolean more = filterDocIdIterator.next() && scorer.skipTo(filterDocIdIterator.doc());
143
144 while (more) {
145 int filterDocId = filterDocIdIterator.doc();
146 if (filterDocId > scorer.doc() && !scorer.skipTo(filterDocId)) {
147 more = false;
148 } else {
149 int scorerDocId = scorer.doc();
150 if (scorerDocId == filterDocId) { // permitted by filter
151 results.collect(scorerDocId, scorer.score());
152 more = filterDocIdIterator.next();
153 } else {
154 more = filterDocIdIterator.skipTo(scorerDocId);
155 }
156 }
157 }
158 }
159
160 public Query rewrite(Query original) throws IOException {
161 Query query = original;
162 for (Query rewrittenQuery = query.rewrite(reader); rewrittenQuery != query;
163 rewrittenQuery = query.rewrite(reader)) {
164 query = rewrittenQuery;
165 }
166 return query;
167 }
168
169 public Explanation explain(Weight weight, int doc) throws IOException {
170 return weight.explain(reader, doc);
171 }
172 }