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
FieldValueHitQueue.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 Lucene.Net.Util;
20 
21 namespace Lucene.Net.Search
22 {
23 
24  /// <summary> Expert: A hit queue for sorting by hits by terms in more than one field.
25  /// Uses <c>FieldCache.DEFAULT</c> for maintaining
26  /// internal term lookup tables.
27  ///
28  /// <b>NOTE:</b> This API is experimental and might change in
29  /// incompatible ways in the next release.
30  ///
31  /// </summary>
32  /// <seealso cref="Searcher.Search(Query,Filter,int,Sort)"></seealso>
33  /// <seealso cref="FieldCache"></seealso>
34  public abstract class FieldValueHitQueue : PriorityQueue<FieldValueHitQueue.Entry>
35  {
36  // had to change from internal to public, due to public accessability of FieldValueHitQueue
37  public /*internal*/ sealed class Entry : ScoreDoc
38  {
39  internal int slot;
40 
41  internal Entry(int slot, int doc, float score)
42  : base(doc, score)
43  {
44 
45  this.slot = slot;
46  }
47 
48  public override System.String ToString()
49  {
50  return "slot:" + slot + " " + base.ToString();
51  }
52  }
53 
54  /// <summary> An implementation of <see cref="FieldValueHitQueue" /> which is optimized in case
55  /// there is just one comparator.
56  /// </summary>
57  private sealed class OneComparatorFieldValueHitQueue : FieldValueHitQueue
58  {
59 
60  private FieldComparator comparator;
61  private int oneReverseMul;
62 
63  public OneComparatorFieldValueHitQueue(SortField[] fields, int size):base(fields)
64  {
65  if (fields.Length == 0)
66  {
67  throw new System.ArgumentException("Sort must contain at least one field");
68  }
69 
70  SortField field = fields[0];
71  comparator = field.GetComparator(size, 0);
72  oneReverseMul = field.reverse?- 1:1;
73 
74  comparators[0] = comparator;
75  reverseMul[0] = oneReverseMul;
76 
77  Initialize(size);
78  }
79 
80  /// <summary> Returns whether <c>a</c> is less relevant than <c>b</c>.</summary>
81  /// <param name="hitA">ScoreDoc</param>
82  /// <param name="hitB">ScoreDoc</param>
83  /// <returns><c>true</c> if document <c>a</c> should be sorted after document <c>b</c>.</returns>
84  public override bool LessThan(Entry hitA, Entry hitB)
85  {
86  System.Diagnostics.Debug.Assert(hitA != hitB);
87  System.Diagnostics.Debug.Assert(hitA.slot != hitB.slot);
88 
89  int c = oneReverseMul * comparator.Compare(hitA.slot, hitB.slot);
90  if (c != 0)
91  {
92  return c > 0;
93  }
94 
95  // avoid random sort order that could lead to duplicates (bug #31241):
96  return hitA.Doc > hitB.Doc;
97  }
98  }
99 
100  /// <summary> An implementation of <see cref="FieldValueHitQueue" /> which is optimized in case
101  /// there is more than one comparator.
102  /// </summary>
103  private sealed class MultiComparatorsFieldValueHitQueue : FieldValueHitQueue
104  {
105 
106  public MultiComparatorsFieldValueHitQueue(SortField[] fields, int size):base(fields)
107  {
108 
109  int numComparators = comparators.Length;
110  for (int i = 0; i < numComparators; ++i)
111  {
112  SortField field = fields[i];
113 
114  reverseMul[i] = field.reverse?- 1:1;
115  comparators[i] = field.GetComparator(size, i);
116  }
117 
118  Initialize(size);
119  }
120 
121  public override bool LessThan(Entry hitA, Entry hitB)
122  {
123  System.Diagnostics.Debug.Assert(hitA != hitB);
124  System.Diagnostics.Debug.Assert(hitA.slot != hitB.slot);
125 
126  int numComparators = comparators.Length;
127  for (int i = 0; i < numComparators; ++i)
128  {
129  int c = reverseMul[i] * comparators[i].Compare(hitA.slot, hitB.slot);
130  if (c != 0)
131  {
132  // Short circuit
133  return c > 0;
134  }
135  }
136 
137  // avoid random sort order that could lead to duplicates (bug #31241):
138  return hitA.Doc > hitB.Doc;
139  }
140  }
141 
142  // prevent instantiation and extension.
143  private FieldValueHitQueue(SortField[] fields)
144  {
145  // When we get here, fields.length is guaranteed to be > 0, therefore no
146  // need to check it again.
147 
148  // All these are required by this class's API - need to return arrays.
149  // Therefore even in the case of a single comparator, create an array
150  // anyway.
151  this.fields = fields;
152  int numComparators = fields.Length;
153  comparators = new FieldComparator[numComparators];
154  reverseMul = new int[numComparators];
155  }
156 
157  /// <summary> Creates a hit queue sorted by the given list of fields.
158  ///
159  /// <p/><b>NOTE</b>: The instances returned by this method
160  /// pre-allocate a full array of length <c>numHits</c>.
161  ///
162  /// </summary>
163  /// <param name="fields">SortField array we are sorting by in priority order (highest
164  /// priority first); cannot be <c>null</c> or empty
165  /// </param>
166  /// <param name="size">The number of hits to retain. Must be greater than zero.
167  /// </param>
168  /// <throws> IOException </throws>
169  public static FieldValueHitQueue Create(SortField[] fields, int size)
170  {
171 
172  if (fields.Length == 0)
173  {
174  throw new System.ArgumentException("Sort must contain at least one field");
175  }
176 
177  if (fields.Length == 1)
178  {
179  return new OneComparatorFieldValueHitQueue(fields, size);
180  }
181  else
182  {
183  return new MultiComparatorsFieldValueHitQueue(fields, size);
184  }
185  }
186 
187  internal virtual FieldComparator[] GetComparators()
188  {
189  return comparators;
190  }
191 
192  internal virtual int[] GetReverseMul()
193  {
194  return reverseMul;
195  }
196 
197  /// <summary>Stores the sort criteria being used. </summary>
198  protected internal SortField[] fields;
199  protected internal FieldComparator[] comparators;
200  protected internal int[] reverseMul;
201 
202  public abstract override bool LessThan(Entry a, Entry b);
203 
204  /// <summary> Given a queue Entry, creates a corresponding FieldDoc
205  /// that contains the values used to sort the given document.
206  /// These values are not the raw values out of the index, but the internal
207  /// representation of them. This is so the given search hit can be collated by
208  /// a MultiSearcher with other search hits.
209  ///
210  /// </summary>
211  /// <param name="entry">The Entry used to create a FieldDoc
212  /// </param>
213  /// <returns> The newly created FieldDoc
214  /// </returns>
215  /// <seealso cref="Searchable.Search(Weight,Filter,int,Sort)">
216  /// </seealso>
217  internal virtual FieldDoc FillFields(Entry entry)
218  {
219  int n = comparators.Length;
220  System.IComparable[] fields = new System.IComparable[n];
221  for (int i = 0; i < n; ++i)
222  {
223  fields[i] = comparators[i][entry.slot];
224  }
225  //if (maxscore > 1.0f) doc.score /= maxscore; // normalize scores
226  return new FieldDoc(entry.Doc, entry.Score, fields);
227  }
228 
229  /// <summary>Returns the SortFields being used by this hit queue. </summary>
230  internal virtual SortField[] GetFields()
231  {
232  return fields;
233  }
234  }
235 }