/* * 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 IndexReader = Lucene.Net.Index.IndexReader; using PriorityQueue = Lucene.Net.Util.PriorityQueue; namespace Lucene.Net.Search { /// Expert: A hit queue for sorting by hits by terms in more than one field. /// Uses FieldCache.DEFAULT for maintaining internal term lookup tables. /// ///

Created: Dec 8, 2003 12:56:03 PM /// ///

/// Tim Jones (Nacimiento Software) /// /// lucene 1.4 /// /// $Id: FieldSortedHitQueue.java 477084 2006-11-20 07:10:04Z otis $ /// /// /// /// /// public class FieldSortedHitQueue : PriorityQueue { internal class AnonymousClassCache : FieldCacheImpl.Cache { protected internal override System.Object CreateValue(IndexReader reader, System.Object entryKey) { FieldCacheImpl.Entry entry = (FieldCacheImpl.Entry) entryKey; System.String fieldname = entry.field; int type = entry.type; System.Globalization.CultureInfo locale = entry.locale; SortComparatorSource factory = (SortComparatorSource) entry.custom; ScoreDocComparator comparator; switch (type) { case SortField.AUTO: comparator = Lucene.Net.Search.FieldSortedHitQueue.ComparatorAuto(reader, fieldname); break; case SortField.INT: comparator = Lucene.Net.Search.FieldSortedHitQueue.comparatorInt(reader, fieldname); break; case SortField.FLOAT: comparator = Lucene.Net.Search.FieldSortedHitQueue.comparatorFloat(reader, fieldname); break; case SortField.STRING: if (locale != null) comparator = Lucene.Net.Search.FieldSortedHitQueue.comparatorStringLocale(reader, fieldname, locale); else comparator = Lucene.Net.Search.FieldSortedHitQueue.comparatorString(reader, fieldname); break; case SortField.CUSTOM: comparator = factory.NewComparator(reader, fieldname); break; default: throw new System.SystemException("unknown field type: " + type); } return comparator; } } private class AnonymousClassScoreDocComparator : ScoreDocComparator { public AnonymousClassScoreDocComparator(int[] fieldOrder) { InitBlock(fieldOrder); } private void InitBlock(int[] fieldOrder) { this.fieldOrder = fieldOrder; } private int[] fieldOrder; public int Compare(ScoreDoc i, ScoreDoc j) { int fi = fieldOrder[i.doc]; int fj = fieldOrder[j.doc]; if (fi < fj) return - 1; if (fi > fj) return 1; return 0; } public virtual System.IComparable SortValue(ScoreDoc i) { return (System.Int32) fieldOrder[i.doc]; } public virtual int SortType() { return SortField.INT; } } private class AnonymousClassScoreDocComparator1 : ScoreDocComparator { public AnonymousClassScoreDocComparator1(float[] fieldOrder) { InitBlock(fieldOrder); } private void InitBlock(float[] fieldOrder) { this.fieldOrder = fieldOrder; } private float[] fieldOrder; public int Compare(ScoreDoc i, ScoreDoc j) { float fi = fieldOrder[i.doc]; float fj = fieldOrder[j.doc]; if (fi < fj) return - 1; if (fi > fj) return 1; return 0; } public virtual System.IComparable SortValue(ScoreDoc i) { return (float) fieldOrder[i.doc]; } public virtual int SortType() { return SortField.FLOAT; } } private class AnonymousClassScoreDocComparator2 : ScoreDocComparator { public AnonymousClassScoreDocComparator2(Lucene.Net.Search.StringIndex index) { InitBlock(index); } private void InitBlock(Lucene.Net.Search.StringIndex index) { this.index = index; } private Lucene.Net.Search.StringIndex index; public int Compare(ScoreDoc i, ScoreDoc j) { int fi = index.order[i.doc]; int fj = index.order[j.doc]; if (fi < fj) return - 1; if (fi > fj) return 1; return 0; } public virtual System.IComparable SortValue(ScoreDoc i) { return index.lookup[index.order[i.doc]]; } public virtual int SortType() { return SortField.STRING; } } private class AnonymousClassScoreDocComparator3 : ScoreDocComparator { public AnonymousClassScoreDocComparator3(System.String[] index, System.Globalization.CompareInfo collator) { InitBlock(index, collator); } private void InitBlock(System.String[] index, System.Globalization.CompareInfo collator) { this.index = index; this.collator = collator; } private System.String[] index; private System.Globalization.CompareInfo collator; public int Compare(ScoreDoc i, ScoreDoc j) { System.String is_Renamed = index[i.doc]; System.String js = index[j.doc]; if ((System.Object) is_Renamed == (System.Object) js) { return 0; } else if (is_Renamed == null) { return - 1; } else if (js == null) { return 1; } else { return collator.Compare(is_Renamed.ToString(), js.ToString()); } } public virtual System.IComparable SortValue(ScoreDoc i) { return index[i.doc]; } public virtual int SortType() { return SortField.STRING; } } /// Creates a hit queue sorted by the given list of fields. /// Index to use. /// /// Fieldable names, in priority order (highest priority first). Cannot be null or empty. /// /// The number of hits to retain. Must be greater than zero. /// /// IOException public FieldSortedHitQueue(IndexReader reader, SortField[] fields, int size) { int n = fields.Length; comparators = new ScoreDocComparator[n]; this.fields = new SortField[n]; for (int i = 0; i < n; ++i) { System.String fieldname = fields[i].GetField(); comparators[i] = GetCachedComparator(reader, fieldname, fields[i].GetType(), fields[i].GetLocale(), fields[i].GetFactory()); if (comparators[i].SortType() == SortField.STRING) { this.fields[i] = new SortField(fieldname, fields[i].GetLocale(), fields[i].GetReverse()); } else { this.fields[i] = new SortField(fieldname, comparators[i].SortType(), fields[i].GetReverse()); } } Initialize(size); } /// Stores a comparator corresponding to each field being sorted by protected internal ScoreDocComparator[] comparators; /// Stores the sort criteria being used. protected internal SortField[] fields; /// Stores the maximum score value encountered, needed for normalizing. protected internal float maxscore = System.Single.NegativeInfinity; /// returns the maximum score encountered by elements inserted via insert() public virtual float GetMaxScore() { return maxscore; } // The signature of this method takes a FieldDoc in order to avoid // the unneeded cast to retrieve the score. // inherit javadoc public virtual bool Insert(FieldDoc fdoc) { maxscore = System.Math.Max(maxscore, fdoc.score); return base.Insert(fdoc); } // This overrides PriorityQueue.insert() so that insert(FieldDoc) that // keeps track of the score isn't accidentally bypassed. // inherit javadoc public override bool Insert(System.Object fdoc) { return Insert((FieldDoc) fdoc); } /// 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) { ScoreDoc docA = (ScoreDoc) a; ScoreDoc docB = (ScoreDoc) b; // run comparators int n = comparators.Length; int c = 0; for (int i = 0; i < n && c == 0; ++i) { c = (fields[i].reverse)?comparators[i].Compare(docB, docA):comparators[i].Compare(docA, docB); } // avoid random sort order that could lead to duplicates (bug #31241): if (c == 0) return docA.doc > docB.doc; return c > 0; } /// Given a FieldDoc object, stores the values used /// to sort the given document. These values are not the raw /// values out of the index, but the internal representation /// of them. This is so the given search hit can be collated /// by a MultiSearcher with other search hits. /// /// The FieldDoc to store sort values into. /// /// The same FieldDoc passed in. /// /// /// internal virtual FieldDoc FillFields(FieldDoc doc) { int n = comparators.Length; System.IComparable[] fields = new System.IComparable[n]; for (int i = 0; i < n; ++i) fields[i] = comparators[i].SortValue(doc); doc.fields = fields; //if (maxscore > 1.0f) doc.score /= maxscore; // normalize scores return doc; } /// Returns the SortFields being used by this hit queue. internal virtual SortField[] GetFields() { return fields; } internal static ScoreDocComparator GetCachedComparator(IndexReader reader, System.String field, int type, System.Globalization.CultureInfo locale, SortComparatorSource factory) { if (type == SortField.DOC) return Lucene.Net.Search.ScoreDocComparator_Fields.INDEXORDER; if (type == SortField.SCORE) return Lucene.Net.Search.ScoreDocComparator_Fields.RELEVANCE; FieldCacheImpl.Entry entry = (factory != null) ? new FieldCacheImpl.Entry(field, factory) : new FieldCacheImpl.Entry(field, type, locale); return (ScoreDocComparator) Comparators.Get(reader, entry); } /// Internal cache of comparators. Similar to FieldCache, only /// caches comparators instead of term values. /// internal static readonly FieldCacheImpl.Cache Comparators; /// Returns a comparator for sorting hits according to a field containing integers. /// Index to use. /// /// Fieldable containg integer values. /// /// Comparator for sorting hits. /// /// IOException If an error occurs reading the index. internal static ScoreDocComparator comparatorInt(IndexReader reader, System.String fieldname) { System.String field = String.Intern(fieldname); int[] fieldOrder = Lucene.Net.Search.FieldCache_Fields.DEFAULT.GetInts(reader, field); return new AnonymousClassScoreDocComparator(fieldOrder); } /// Returns a comparator for sorting hits according to a field containing floats. /// Index to use. /// /// Fieldable containg float values. /// /// Comparator for sorting hits. /// /// IOException If an error occurs reading the index. internal static ScoreDocComparator comparatorFloat(IndexReader reader, System.String fieldname) { System.String field = String.Intern(fieldname); float[] fieldOrder = Lucene.Net.Search.FieldCache_Fields.DEFAULT.GetFloats(reader, field); return new AnonymousClassScoreDocComparator1(fieldOrder); } /// Returns a comparator for sorting hits according to a field containing strings. /// Index to use. /// /// Fieldable containg string values. /// /// Comparator for sorting hits. /// /// IOException If an error occurs reading the index. internal static ScoreDocComparator comparatorString(IndexReader reader, System.String fieldname) { System.String field = String.Intern(fieldname); Lucene.Net.Search.StringIndex index = Lucene.Net.Search.FieldCache_Fields.DEFAULT.GetStringIndex(reader, field); return new AnonymousClassScoreDocComparator2(index); } /// Returns a comparator for sorting hits according to a field containing strings. /// Index to use. /// /// Fieldable containg string values. /// /// Comparator for sorting hits. /// /// IOException If an error occurs reading the index. internal static ScoreDocComparator comparatorStringLocale(IndexReader reader, System.String fieldname, System.Globalization.CultureInfo locale) { System.Globalization.CompareInfo collator = locale.CompareInfo; System.String field = String.Intern(fieldname); System.String[] index = Lucene.Net.Search.FieldCache_Fields.DEFAULT.GetStrings(reader, field); return new AnonymousClassScoreDocComparator3(index, collator); } /// Returns a comparator for sorting hits according to values in the given field. /// The terms in the field are looked at to determine whether they contain integers, /// floats or strings. Once the type is determined, one of the other static methods /// in this class is called to get the comparator. /// /// Index to use. /// /// Fieldable containg values. /// /// Comparator for sorting hits. /// /// IOException If an error occurs reading the index. internal static ScoreDocComparator ComparatorAuto(IndexReader reader, System.String fieldname) { System.String field = String.Intern(fieldname); System.Object lookupArray = Lucene.Net.Search.FieldCache_Fields.DEFAULT.GetAuto(reader, field); if (lookupArray is Lucene.Net.Search.StringIndex) { return comparatorString(reader, field); } else if (lookupArray is int[]) { return comparatorInt(reader, field); } else if (lookupArray is float[]) { return comparatorFloat(reader, field); } else if (lookupArray is System.String[]) { return comparatorString(reader, field); } else { throw new System.SystemException("unknown data type in field '" + field + "'"); } } static FieldSortedHitQueue() { Comparators = new AnonymousClassCache(); } } }