/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using PriorityQueue = Lucene.Net.Util.PriorityQueue; namespace Lucene.Net.Search { /// Expert: Collects sorted results from Searchable's and collates them. /// The elements put into this queue must be of type FieldDoc. /// ///

Created: Feb 11, 2004 2:04:21 PM /// ///

/// lucene 1.4 /// /// $Id: FieldDocSortedHitQueue.java 695514 2008-09-15 15:42:11Z otis $ /// class FieldDocSortedHitQueue:PriorityQueue { // this cannot contain AUTO fields - any AUTO fields should // have been resolved by the time this class is used. internal volatile SortField[] fields; // used in the case where the fields are sorted by locale // based strings internal volatile System.Globalization.CompareInfo[] collators; /// Creates a hit queue sorted by the given list of fields. /// Fieldable names, in priority order (highest priority first). /// /// The number of hits to retain. Must be greater than zero. /// internal FieldDocSortedHitQueue(SortField[] fields, int size) { this.fields = fields; this.collators = HasCollators(fields); Initialize(size); } /// Allows redefinition of sort fields if they are null. /// This is to handle the case using ParallelMultiSearcher where the /// original list contains AUTO and we don't know the actual sort /// type until the values come back. The fields can only be set once. /// This method is thread safe. /// /// /// internal virtual void SetFields(SortField[] fields) { lock (this) { if (this.fields == null) { this.fields = fields; this.collators = HasCollators(fields); } } } /// Returns the fields being used to sort. internal virtual SortField[] GetFields() { return fields; } /// Returns an array of collators, possibly null. The collators /// correspond to any SortFields which were given a specific locale. /// /// Array of sort fields. /// /// Array, possibly null. /// private System.Globalization.CompareInfo[] HasCollators(SortField[] fields) { if (fields == null) return null; System.Globalization.CompareInfo[] ret = new System.Globalization.CompareInfo[fields.Length]; for (int i = 0; i < fields.Length; ++i) { System.Globalization.CultureInfo locale = fields[i].GetLocale(); if (locale != null) ret[i] = locale.CompareInfo; } return ret; } /// Returns whether a is less relevant than b. /// ScoreDoc /// /// ScoreDoc /// /// true if document a should be sorted after document b. /// public override bool LessThan(System.Object a, System.Object b) { FieldDoc docA = (FieldDoc) a; FieldDoc docB = (FieldDoc) b; int n = fields.Length; int c = 0; for (int i = 0; i < n && c == 0; ++i) { int type = fields[i].GetType(); switch (type) { case SortField.SCORE: { float r1 = (float) ((System.Single) docA.fields[i]); float r2 = (float) ((System.Single) docB.fields[i]); if (r1 > r2) c = - 1; if (r1 < r2) c = 1; break; } case SortField.DOC: case SortField.INT: { int i1 = ((System.Int32) docA.fields[i]); int i2 = ((System.Int32) docB.fields[i]); if (i1 < i2) c = - 1; if (i1 > i2) c = 1; break; } case SortField.LONG: { long l1 = (long) ((System.Int64) docA.fields[i]); long l2 = (long) ((System.Int64) docB.fields[i]); if (l1 < l2) c = - 1; if (l1 > l2) c = 1; break; } case SortField.STRING: { System.String s1 = (System.String) docA.fields[i]; System.String s2 = (System.String) docB.fields[i]; // null values need to be sorted first, because of how FieldCache.getStringIndex() // works - in that routine, any documents without a value in the given field are // put first. If both are null, the next SortField is used if (s1 == null) c = (s2 == null)?0:- 1; else if (s2 == null) c = 1; // else if (fields[i].GetLocale() == null) { c = String.CompareOrdinal(s1, s2); } else { c = collators[i].Compare(s1.ToString(), s2.ToString()); } break; } case SortField.FLOAT: { float f1 = (float) ((System.Single) docA.fields[i]); float f2 = (float) ((System.Single) docB.fields[i]); if (f1 < f2) c = - 1; if (f1 > f2) c = 1; break; } case SortField.DOUBLE: { double d1 = ((System.Double) docA.fields[i]); double d2 = ((System.Double) docB.fields[i]); if (d1 < d2) c = - 1; if (d1 > d2) c = 1; break; } case SortField.BYTE: { int i1 = (sbyte) ((System.SByte) docA.fields[i]); int i2 = (sbyte) ((System.SByte) docB.fields[i]); if (i1 < i2) c = - 1; if (i1 > i2) c = 1; break; } case SortField.SHORT: { int i1 = (short) ((System.Int16) docA.fields[i]); int i2 = (short) ((System.Int16) docB.fields[i]); if (i1 < i2) c = - 1; if (i1 > i2) c = 1; break; } case SortField.CUSTOM: { c = docA.fields[i].CompareTo(docB.fields[i]); break; } case SortField.AUTO: { // we cannot handle this - even if we determine the type of object (Float or // Integer), we don't necessarily know how to compare them (both SCORE and // FLOAT contain floats, but are sorted opposite of each other). Before // we get here, each AUTO should have been replaced with its actual value. throw new System.SystemException("FieldDocSortedHitQueue cannot use an AUTO SortField"); } default: { throw new System.SystemException("invalid SortField type: " + type); } } if (fields[i].GetReverse()) { c = - c; } } // avoid random sort order that could lead to duplicates (bug #31241): if (c == 0) return docA.doc > docB.doc; return c > 0; } } }