pylucene 3.5.0-3
[pylucene.git] / lucene-java-3.5.0 / lucene / src / java / org / apache / lucene / search / FieldDocSortedHitQueue.java
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.util.PriorityQueue;
21 import java.io.IOException;
22 import java.text.Collator;
23 import java.util.Locale;
24
25 /**
26  * Expert: Collects sorted results from Searchable's and collates them.
27  * The elements put into this queue must be of type FieldDoc.
28  *
29  * <p>Created: Feb 11, 2004 2:04:21 PM
30  *
31  * @since   lucene 1.4
32  */
33 class FieldDocSortedHitQueue extends PriorityQueue<FieldDoc> {
34
35   volatile SortField[] fields = null;
36
37   // used in the case where the fields are sorted by locale
38   // based strings
39   volatile Collator[] collators = null;
40
41   volatile FieldComparator[] comparators = null;
42
43
44   /**
45    * Creates a hit queue sorted by the given list of fields.
46    * @param fields Fieldable names, in priority order (highest priority first).
47    * @param size  The number of hits to retain.  Must be greater than zero.
48    */
49   FieldDocSortedHitQueue (int size) {
50     initialize (size);
51   }
52
53
54   /**
55    * Allows redefinition of sort fields if they are <code>null</code>.
56    * This is to handle the case using ParallelMultiSearcher where the
57    * original list contains AUTO and we don't know the actual sort
58    * type until the values come back.  The fields can only be set once.
59    * This method should be synchronized external like all other PQ methods.
60    * @param fields
61    */
62   void setFields (SortField[] fields) throws IOException {
63     this.fields = fields;
64     this.collators = hasCollators (fields);
65     comparators = new FieldComparator[fields.length];
66     for(int fieldIDX=0;fieldIDX<fields.length;fieldIDX++) {
67       comparators[fieldIDX] = fields[fieldIDX].getComparator(1, fieldIDX);
68     }
69   }
70
71
72   /** Returns the fields being used to sort. */
73   SortField[] getFields() {
74     return fields;
75   }
76
77
78   /** Returns an array of collators, possibly <code>null</code>.  The collators
79    * correspond to any SortFields which were given a specific locale.
80    * @param fields Array of sort fields.
81    * @return Array, possibly <code>null</code>.
82    */
83   private Collator[] hasCollators (final SortField[] fields) {
84     if (fields == null) return null;
85     Collator[] ret = new Collator[fields.length];
86     for (int i=0; i<fields.length; ++i) {
87       Locale locale = fields[i].getLocale();
88       if (locale != null)
89         ret[i] = Collator.getInstance (locale);
90     }
91     return ret;
92   }
93
94
95   /**
96    * Returns whether <code>a</code> is less relevant than <code>b</code>.
97    * @param a ScoreDoc
98    * @param b ScoreDoc
99    * @return <code>true</code> if document <code>a</code> should be sorted after document <code>b</code>.
100    */
101   @SuppressWarnings("unchecked") @Override
102   protected final boolean lessThan(final FieldDoc docA, final FieldDoc docB) {
103     final int n = fields.length;
104     int c = 0;
105     for (int i=0; i<n && c==0; ++i) {
106       final int type = fields[i].getType();
107       if (type == SortField.STRING) {
108         final String s1 = (String) docA.fields[i];
109         final String s2 = (String) docB.fields[i];
110         // null values need to be sorted first, because of how FieldCache.getStringIndex()
111         // works - in that routine, any documents without a value in the given field are
112         // put first.  If both are null, the next SortField is used
113         if (s1 == null) {
114           c = (s2 == null) ? 0 : -1;
115         } else if (s2 == null) {
116           c = 1;
117         } else if (fields[i].getLocale() == null) {
118           c = s1.compareTo(s2);
119         } else {
120           c = collators[i].compare(s1, s2);
121         }
122       } else {
123         c = comparators[i].compareValues(docA.fields[i], docB.fields[i]);
124       }
125       // reverse sort
126       if (fields[i].getReverse()) {
127         c = -c;
128       }
129     }
130
131     // avoid random sort order that could lead to duplicates (bug #31241):
132     if (c == 0)
133       return docA.doc > docB.doc;
134
135     return c > 0;
136   }
137 }