Save This Page
Home » lucene-3.0.1-src » org.apache » lucene » search » [javadoc | source]
    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 java.io.IOException;
   21   import java.util.ArrayList;
   22   import java.util.List;
   23   
   24   import org.apache.lucene.document.Document;
   25   import org.apache.lucene.document.FieldSelector;
   26   import org.apache.lucene.index.CorruptIndexException;
   27   import org.apache.lucene.index.IndexReader;
   28   import org.apache.lucene.index.Term;
   29   import org.apache.lucene.store.Directory;
   30   import org.apache.lucene.util.ReaderUtil;
   31   
   32   /** Implements search over a single IndexReader.
   33    *
   34    * <p>Applications usually need only call the inherited
   35    * {@link #search(Query,int)}
   36    * or {@link #search(Query,Filter,int)} methods. For performance reasons it is 
   37    * recommended to open only one IndexSearcher and use it for all of your searches.
   38    * 
   39    * <a name="thread-safety"></a><p><b>NOTE</b>: {@link
   40    * <code>IndexSearcher</code>} instances are completely
   41    * thread safe, meaning multiple threads can call any of its
   42    * methods, concurrently.  If your application requires
   43    * external synchronization, you should <b>not</b>
   44    * synchronize on the <code>IndexSearcher</code> instance;
   45    * use your own (non-Lucene) objects instead.</p>
   46    */
   47   public class IndexSearcher extends Searcher {
   48     IndexReader reader;
   49     private boolean closeReader;
   50     
   51     // NOTE: these members might change in incompatible ways
   52     // in the next release
   53     protected IndexReader[] subReaders;
   54     protected int[] docStarts;
   55   
   56     /** Creates a searcher searching the index in the named
   57      *  directory, with readOnly=true
   58      * @throws CorruptIndexException if the index is corrupt
   59      * @throws IOException if there is a low-level IO error
   60      * @param path directory where IndexReader will be opened
   61      */
   62     public IndexSearcher(Directory path) throws CorruptIndexException, IOException {
   63       this(IndexReader.open(path, true), true);
   64     }
   65   
   66     /** Creates a searcher searching the index in the named
   67      *  directory.  You should pass readOnly=true, since it
   68      *  gives much better concurrent performance, unless you
   69      *  intend to do write operations (delete documents or
   70      *  change norms) with the underlying IndexReader.
   71      * @throws CorruptIndexException if the index is corrupt
   72      * @throws IOException if there is a low-level IO error
   73      * @param path directory where IndexReader will be opened
   74      * @param readOnly if true, the underlying IndexReader
   75      * will be opened readOnly
   76      */
   77     public IndexSearcher(Directory path, boolean readOnly) throws CorruptIndexException, IOException {
   78       this(IndexReader.open(path, readOnly), true);
   79     }
   80   
   81     /** Creates a searcher searching the provided index. */
   82     public IndexSearcher(IndexReader r) {
   83       this(r, false);
   84     }
   85   
   86     /** Expert: directly specify the reader, subReaders and
   87      *  their docID starts.
   88      * 
   89      * <p><b>NOTE:</b> This API is experimental and
   90      * might change in incompatible ways in the next
   91      * release.</font></p> */
   92     public IndexSearcher(IndexReader reader, IndexReader[] subReaders, int[] docStarts) {
   93       this.reader = reader;
   94       this.subReaders = subReaders;
   95       this.docStarts = docStarts;
   96       closeReader = false;
   97     }
   98     
   99     private IndexSearcher(IndexReader r, boolean closeReader) {
  100       reader = r;
  101       this.closeReader = closeReader;
  102   
  103       List<IndexReader> subReadersList = new ArrayList<IndexReader>();
  104       gatherSubReaders(subReadersList, reader);
  105       subReaders = subReadersList.toArray(new IndexReader[subReadersList.size()]);
  106       docStarts = new int[subReaders.length];
  107       int maxDoc = 0;
  108       for (int i = 0; i < subReaders.length; i++) {
  109         docStarts[i] = maxDoc;
  110         maxDoc += subReaders[i].maxDoc();
  111       }
  112     }
  113   
  114     protected void gatherSubReaders(List<IndexReader> allSubReaders, IndexReader r) {
  115       ReaderUtil.gatherSubReaders(allSubReaders, r);
  116     }
  117   
  118     /** Return the {@link IndexReader} this searches. */
  119     public IndexReader getIndexReader() {
  120       return reader;
  121     }
  122   
  123     /**
  124      * Note that the underlying IndexReader is not closed, if
  125      * IndexSearcher was constructed with IndexSearcher(IndexReader r).
  126      * If the IndexReader was supplied implicitly by specifying a directory, then
  127      * the IndexReader gets closed.
  128      */
  129     @Override
  130     public void close() throws IOException {
  131       if(closeReader)
  132         reader.close();
  133     }
  134   
  135     // inherit javadoc
  136     @Override
  137     public int docFreq(Term term) throws IOException {
  138       return reader.docFreq(term);
  139     }
  140   
  141     // inherit javadoc
  142     @Override
  143     public Document doc(int i) throws CorruptIndexException, IOException {
  144       return reader.document(i);
  145     }
  146     
  147     // inherit javadoc
  148     @Override
  149     public Document doc(int i, FieldSelector fieldSelector) throws CorruptIndexException, IOException {
  150   	    return reader.document(i, fieldSelector);
  151     }
  152     
  153     // inherit javadoc
  154     @Override
  155     public int maxDoc() throws IOException {
  156       return reader.maxDoc();
  157     }
  158   
  159     // inherit javadoc
  160     @Override
  161     public TopDocs search(Weight weight, Filter filter, final int nDocs) throws IOException {
  162   
  163       if (nDocs <= 0) {
  164         throw new IllegalArgumentException("nDocs must be > 0");
  165       }
  166   
  167       TopScoreDocCollector collector = TopScoreDocCollector.create(nDocs, !weight.scoresDocsOutOfOrder());
  168       search(weight, filter, collector);
  169       return collector.topDocs();
  170     }
  171   
  172     @Override
  173     public TopFieldDocs search(Weight weight, Filter filter,
  174         final int nDocs, Sort sort) throws IOException {
  175       return search(weight, filter, nDocs, sort, true);
  176     }
  177   
  178     /**
  179      * Just like {@link #search(Weight, Filter, int, Sort)}, but you choose
  180      * whether or not the fields in the returned {@link FieldDoc} instances should
  181      * be set by specifying fillFields.
  182      *
  183      * <p>NOTE: this does not compute scores by default.  If you
  184      * need scores, create a {@link TopFieldCollector}
  185      * instance by calling {@link TopFieldCollector#create} and
  186      * then pass that to {@link #search(Weight, Filter,
  187      * Collector)}.</p>
  188      */
  189     public TopFieldDocs search(Weight weight, Filter filter, final int nDocs,
  190                                Sort sort, boolean fillFields)
  191         throws IOException {
  192       TopFieldCollector collector = TopFieldCollector.create(sort, nDocs,
  193           fillFields, fieldSortDoTrackScores, fieldSortDoMaxScore, !weight.scoresDocsOutOfOrder());
  194       search(weight, filter, collector);
  195       return (TopFieldDocs) collector.topDocs();
  196     }
  197   
  198     @Override
  199     public void search(Weight weight, Filter filter, Collector collector)
  200         throws IOException {
  201       
  202       if (filter == null) {
  203         for (int i = 0; i < subReaders.length; i++) { // search each subreader
  204           collector.setNextReader(subReaders[i], docStarts[i]);
  205           Scorer scorer = weight.scorer(subReaders[i], !collector.acceptsDocsOutOfOrder(), true);
  206           if (scorer != null) {
  207             scorer.score(collector);
  208           }
  209         }
  210       } else {
  211         for (int i = 0; i < subReaders.length; i++) { // search each subreader
  212           collector.setNextReader(subReaders[i], docStarts[i]);
  213           searchWithFilter(subReaders[i], weight, filter, collector);
  214         }
  215       }
  216     }
  217   
  218     private void searchWithFilter(IndexReader reader, Weight weight,
  219         final Filter filter, final Collector collector) throws IOException {
  220   
  221       assert filter != null;
  222       
  223       Scorer scorer = weight.scorer(reader, true, false);
  224       if (scorer == null) {
  225         return;
  226       }
  227   
  228       int docID = scorer.docID();
  229       assert docID == -1 || docID == DocIdSetIterator.NO_MORE_DOCS;
  230   
  231       // CHECKME: use ConjunctionScorer here?
  232       DocIdSet filterDocIdSet = filter.getDocIdSet(reader);
  233       if (filterDocIdSet == null) {
  234         // this means the filter does not accept any documents.
  235         return;
  236       }
  237       
  238       DocIdSetIterator filterIter = filterDocIdSet.iterator();
  239       if (filterIter == null) {
  240         // this means the filter does not accept any documents.
  241         return;
  242       }
  243       int filterDoc = filterIter.nextDoc();
  244       int scorerDoc = scorer.advance(filterDoc);
  245       
  246       collector.setScorer(scorer);
  247       while (true) {
  248         if (scorerDoc == filterDoc) {
  249           // Check if scorer has exhausted, only before collecting.
  250           if (scorerDoc == DocIdSetIterator.NO_MORE_DOCS) {
  251             break;
  252           }
  253           collector.collect(scorerDoc);
  254           filterDoc = filterIter.nextDoc();
  255           scorerDoc = scorer.advance(filterDoc);
  256         } else if (scorerDoc > filterDoc) {
  257           filterDoc = filterIter.advance(scorerDoc);
  258         } else {
  259           scorerDoc = scorer.advance(filterDoc);
  260         }
  261       }
  262     }
  263   
  264     @Override
  265     public Query rewrite(Query original) throws IOException {
  266       Query query = original;
  267       for (Query rewrittenQuery = query.rewrite(reader); rewrittenQuery != query;
  268            rewrittenQuery = query.rewrite(reader)) {
  269         query = rewrittenQuery;
  270       }
  271       return query;
  272     }
  273   
  274     @Override
  275     public Explanation explain(Weight weight, int doc) throws IOException {
  276       int n = ReaderUtil.subIndex(doc, docStarts);
  277       int deBasedDoc = doc - docStarts[n];
  278       
  279       return weight.explain(subReaders[n], deBasedDoc);
  280     }
  281   
  282     private boolean fieldSortDoTrackScores;
  283     private boolean fieldSortDoMaxScore;
  284   
  285     /** By default, no scores are computed when sorting by
  286      *  field (using {@link #search(Query,Filter,int,Sort)}).
  287      *  You can change that, per IndexSearcher instance, by
  288      *  calling this method.  Note that this will incur a CPU
  289      *  cost.
  290      * 
  291      *  @param doTrackScores If true, then scores are
  292      *  returned for every matching document in {@link
  293      *  TopFieldDocs}.
  294      *
  295      *  @param doMaxScore If true, then the max score for all
  296      *  matching docs is computed. */
  297     public void setDefaultFieldSortScoring(boolean doTrackScores, boolean doMaxScore) {
  298       fieldSortDoTrackScores = doTrackScores;
  299       fieldSortDoMaxScore = doMaxScore;
  300     }
  301   }

Save This Page
Home » lucene-3.0.1-src » org.apache » lucene » search » [javadoc | source]