Index: C:/workspace/lucene-trunk/src/test/org/apache/lucene/search/SampleComparable.java =================================================================== --- C:/workspace/lucene-trunk/src/test/org/apache/lucene/search/SampleComparable.java (revision 616520) +++ C:/workspace/lucene-trunk/src/test/org/apache/lucene/search/SampleComparable.java (working copy) @@ -24,6 +24,7 @@ import java.io.IOException; import java.io.Serializable; +import java.util.Locale; /** * An example Comparable for use with the custom sort tests. @@ -67,8 +68,8 @@ public static SortComparatorSource getComparatorSource () { return new SortComparatorSource () { - public ScoreDocComparator newComparator (final IndexReader reader, String fieldname) - throws IOException { + public ScoreDocComparator newComparator(final IndexReader reader, + String fieldname, Locale locale) throws IOException { final String field = fieldname.intern (); final TermEnum enumerator = reader.terms (new Term (fieldname, "")); try { Index: C:/workspace/lucene-trunk/src/java/org/apache/lucene/search/IntComparatorSource.java =================================================================== --- C:/workspace/lucene-trunk/src/java/org/apache/lucene/search/IntComparatorSource.java (revision 0) +++ C:/workspace/lucene-trunk/src/java/org/apache/lucene/search/IntComparatorSource.java (revision 0) @@ -0,0 +1,68 @@ +package org.apache.lucene.search; + +/** + * 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. + */ + +import java.io.IOException; +import java.util.Locale; + +import org.apache.lucene.index.IndexReader; + +/** + * SortComparatorSource which sorts hits by a simple int comparison -- lowest + * values first. + */ +public final class IntComparatorSource implements SortComparatorSource { + private static final long serialVersionUID = 1L; + + /** + * Returns a comparator for sorting hits according to a field containing + * integers. + * + * @param reader Index to use. + * @param fieldname Fieldable containing integer values. + * @param locale locale to use for sorting, if required + * @return Comparator for sorting hits. + * @throws IOException If an error occurs reading the index. + */ + public ScoreDocComparator newComparator(IndexReader reader, String fieldname, + Locale locale) throws IOException { + final String field = fieldname.intern(); + final int[] fieldOrder = FieldCache.DEFAULT.getInts(reader, field); + return new ScoreDocComparator() { + + public final int compare(final ScoreDoc i, final ScoreDoc j) { + final int fi = fieldOrder[i.doc]; + final int fj = fieldOrder[j.doc]; + if (fi < fj) + return -1; + if (fi > fj) + return 1; + return 0; + } + + public Comparable sortValue(final ScoreDoc i) { + return new Integer(fieldOrder[i.doc]); + } + + public int sortType() { + return SortField.INT; + } + }; + } + +} Index: C:/workspace/lucene-trunk/src/java/org/apache/lucene/search/LongComparatorSource.java =================================================================== --- C:/workspace/lucene-trunk/src/java/org/apache/lucene/search/LongComparatorSource.java (revision 0) +++ C:/workspace/lucene-trunk/src/java/org/apache/lucene/search/LongComparatorSource.java (revision 0) @@ -0,0 +1,68 @@ +package org.apache.lucene.search; + +/** + * 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. + */ + +import java.io.IOException; +import java.util.Locale; + +import org.apache.lucene.index.IndexReader; + +/** + * SortComparatorSource which sorts hits by a simple long comparison -- lowest + * values first. + */ +public final class LongComparatorSource implements SortComparatorSource { + private static final long serialVersionUID = 1L; + + /** + * Returns a comparator for sorting hits according to a field containing + * longs. + * + * @param reader Index to use. + * @param fieldname Fieldable containing long values. + * @param locale locale to use for sorting, if required + * @return Comparator for sorting hits. + * @throws IOException If an error occurs reading the index. + */ + public ScoreDocComparator newComparator(IndexReader reader, String fieldname, + Locale locale) throws IOException { + final String field = fieldname.intern(); + final long[] fieldOrder = ExtendedFieldCache.EXT_DEFAULT.getLongs(reader, + field); + return new ScoreDocComparator() { + public final int compare(final ScoreDoc i, final ScoreDoc j) { + final long li = fieldOrder[i.doc]; + final long lj = fieldOrder[j.doc]; + if (li < lj) + return -1; + if (li > lj) + return 1; + return 0; + } + + public Comparable sortValue(final ScoreDoc i) { + return new Long(fieldOrder[i.doc]); + } + + public int sortType() { + return SortField.LONG; + } + }; + } + +} Index: C:/workspace/lucene-trunk/src/java/org/apache/lucene/search/FloatComparatorSource.java =================================================================== --- C:/workspace/lucene-trunk/src/java/org/apache/lucene/search/FloatComparatorSource.java (revision 0) +++ C:/workspace/lucene-trunk/src/java/org/apache/lucene/search/FloatComparatorSource.java (revision 0) @@ -0,0 +1,67 @@ +package org.apache.lucene.search; + +/** + * 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. + */ + +import java.io.IOException; +import java.util.Locale; + +import org.apache.lucene.index.IndexReader; + +/** + * SortComparatorSource which sorts hits by a simple float comparison -- lowest + * values first. + */ +public final class FloatComparatorSource implements SortComparatorSource { + private static final long serialVersionUID = 1L; + + /** + * Returns a comparator for sorting hits according to a field containing + * floats. + * + * @param reader Index to use. + * @param fieldname Fieldable containing float values. + * @param locale locale to use for sorting (ignored by this class) + * @return Comparator for sorting hits. + * @throws IOException If an error occurs reading the index. + */ + public ScoreDocComparator newComparator(IndexReader reader, String fieldname, + Locale locale) throws IOException { + final String field = fieldname.intern(); + final float[] fieldOrder = FieldCache.DEFAULT.getFloats(reader, field); + return new ScoreDocComparator() { + + public final int compare(final ScoreDoc i, final ScoreDoc j) { + final float fi = fieldOrder[i.doc]; + final float fj = fieldOrder[j.doc]; + if (fi < fj) + return -1; + if (fi > fj) + return 1; + return 0; + } + + public Comparable sortValue(final ScoreDoc i) { + return new Float(fieldOrder[i.doc]); + } + + public int sortType() { + return SortField.FLOAT; + } + }; + } +} \ No newline at end of file Index: C:/workspace/lucene-trunk/src/java/org/apache/lucene/search/SortComparator.java =================================================================== --- C:/workspace/lucene-trunk/src/java/org/apache/lucene/search/SortComparator.java (revision 616520) +++ C:/workspace/lucene-trunk/src/java/org/apache/lucene/search/SortComparator.java (working copy) @@ -20,6 +20,7 @@ import org.apache.lucene.index.IndexReader; import java.io.IOException; +import java.util.Locale; /** * Abstract base class for sorting hits returned by a Query. @@ -43,8 +44,8 @@ implements SortComparatorSource { // inherit javadocs - public ScoreDocComparator newComparator (final IndexReader reader, final String fieldname) - throws IOException { + public ScoreDocComparator newComparator(final IndexReader reader, + final String fieldname, Locale locale) throws IOException { final String field = fieldname.intern(); final Comparable[] cachedValues = FieldCache.DEFAULT.getCustom (reader, field, SortComparator.this); Index: C:/workspace/lucene-trunk/src/java/org/apache/lucene/search/DoubleComparatorSource.java =================================================================== --- C:/workspace/lucene-trunk/src/java/org/apache/lucene/search/DoubleComparatorSource.java (revision 0) +++ C:/workspace/lucene-trunk/src/java/org/apache/lucene/search/DoubleComparatorSource.java (revision 0) @@ -0,0 +1,68 @@ +package org.apache.lucene.search; + +/** + * 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. + */ + +import java.io.IOException; +import java.util.Locale; + +import org.apache.lucene.index.IndexReader; + +/** + * SortComparatorSource which sorts hits by a simple double comparison -- lowest + * values first. + */ +public class DoubleComparatorSource implements SortComparatorSource { + private static final long serialVersionUID = 1L; + + /** + * Returns a comparator for sorting hits according to a field containing + * doubles. + * + * @param reader Index to use. + * @param fieldname Fieldable containing double values. + * @param locale locale to use for sorting (ignored by this class) + * @return Comparator for sorting hits. + * @throws IOException If an error occurs reading the index. + */ + public ScoreDocComparator newComparator(IndexReader reader, String fieldname, + Locale locale) throws IOException { + final String field = fieldname.intern(); + final double[] fieldOrder = ExtendedFieldCache.EXT_DEFAULT.getDoubles( + reader, field); + return new ScoreDocComparator() { + + public final int compare(final ScoreDoc i, final ScoreDoc j) { + final double di = fieldOrder[i.doc]; + final double dj = fieldOrder[j.doc]; + if (di < dj) + return -1; + if (di > dj) + return 1; + return 0; + } + + public Comparable sortValue(final ScoreDoc i) { + return new Double(fieldOrder[i.doc]); + } + + public int sortType() { + return SortField.DOUBLE; + } + }; + } +} Index: C:/workspace/lucene-trunk/src/java/org/apache/lucene/search/SortComparatorSource.java =================================================================== --- C:/workspace/lucene-trunk/src/java/org/apache/lucene/search/SortComparatorSource.java (revision 616520) +++ C:/workspace/lucene-trunk/src/java/org/apache/lucene/search/SortComparatorSource.java (working copy) @@ -20,6 +20,7 @@ import org.apache.lucene.index.IndexReader; import java.io.IOException; import java.io.Serializable; +import java.util.Locale; /** * Expert: returns a comparator for sorting ScoreDocs. @@ -37,9 +38,10 @@ * Creates a comparator for the field in the given index. * @param reader Index to create comparator for. * @param fieldname Name of the field to create comparator for. + * @param locale the Locale to use for sorting; may be null * @return Comparator of ScoreDoc objects. * @throws IOException If an error occurs reading the index. */ - ScoreDocComparator newComparator (IndexReader reader, String fieldname) - throws IOException; + ScoreDocComparator newComparator(IndexReader reader, String fieldname, + Locale locale) throws IOException; } Index: C:/workspace/lucene-trunk/src/java/org/apache/lucene/search/FieldSortedHitQueue.java =================================================================== --- C:/workspace/lucene-trunk/src/java/org/apache/lucene/search/FieldSortedHitQueue.java (revision 616520) +++ C:/workspace/lucene-trunk/src/java/org/apache/lucene/search/FieldSortedHitQueue.java (working copy) @@ -21,8 +21,9 @@ import org.apache.lucene.util.PriorityQueue; import java.io.IOException; -import java.text.Collator; +import java.util.HashMap; import java.util.Locale; +import java.util.Map; /** * Expert: A hit queue for sorting by hits by terms in more than one field. @@ -38,7 +39,6 @@ */ public class FieldSortedHitQueue extends PriorityQueue { - /** * Creates a hit queue sorted by the given list of fields. * @param reader Index to use. @@ -168,10 +168,40 @@ return (ScoreDocComparator)Comparators.get(reader, entry); } + private static final Map COMPARATOR_SOURCES = new HashMap(); + static { + COMPARATOR_SOURCES.put(new Integer(SortField.AUTO), new AutoComparatorSource(COMPARATOR_SOURCES)); + COMPARATOR_SOURCES.put(new Integer(SortField.INT), new IntComparatorSource()); + COMPARATOR_SOURCES.put(new Integer(SortField.FLOAT), new FloatComparatorSource()); + COMPARATOR_SOURCES.put(new Integer(SortField.LONG), new LongComparatorSource()); + COMPARATOR_SOURCES.put(new Integer(SortField.DOUBLE), new DoubleComparatorSource()); + COMPARATOR_SOURCES.put(new Integer(SortField.STRING), new StringComparatorSource()); + } + + public static SortComparatorSource getComparatorSource(int sortFieldType) { + return (SortComparatorSource) COMPARATOR_SOURCES.get(new Integer(sortFieldType)); + } + + /** + * Uses the provided SortComparatorSource for all fields of the given type + * where no custom comparator source is provided. + * + * @param sortFieldType the type of the sort field (one of the constant values + * from SortField) + * @param source the SortComparatorSource to use for obtaining comparators for + * this field type + */ + public static void registerComparatorSource(int sortFieldType, + SortComparatorSource source) { + if (source == null) { + throw new NullPointerException("May not register null comparator source"); + } + COMPARATOR_SOURCES.put(new Integer(sortFieldType), source); + } + /** Internal cache of comparators. Similar to FieldCache, only * caches comparators instead of term values. */ static final FieldCacheImpl.Cache Comparators = new FieldCacheImpl.Cache() { - protected Object createValue(IndexReader reader, Object entryKey) throws IOException { FieldCacheImpl.Entry entry = (FieldCacheImpl.Entry) entryKey; @@ -180,256 +210,16 @@ Locale locale = entry.locale; SortComparatorSource factory = (SortComparatorSource) entry.custom; ScoreDocComparator comparator; - switch (type) { - case SortField.AUTO: - comparator = comparatorAuto (reader, fieldname); - break; - case SortField.INT: - comparator = comparatorInt (reader, fieldname); - break; - case SortField.FLOAT: - comparator = comparatorFloat (reader, fieldname); - break; - case SortField.LONG: - comparator = comparatorLong(reader, fieldname); - break; - case SortField.DOUBLE: - comparator = comparatorDouble(reader, fieldname); - break; - case SortField.STRING: - if (locale != null) comparator = comparatorStringLocale (reader, fieldname, locale); - else comparator = comparatorString (reader, fieldname); - break; - case SortField.CUSTOM: - comparator = factory.newComparator (reader, fieldname); - break; - default: - throw new RuntimeException ("unknown field type: "+type); + if (type == SortField.CUSTOM) { + comparator = factory.newComparator(reader, fieldname, locale); + } else { + SortComparatorSource comparatorSource = getComparatorSource(type); + if (comparatorSource == null) { + throw new RuntimeException("unknown field type: " + type); + } + comparator = comparatorSource.newComparator(reader, fieldname, locale); } return comparator; } }; - - /** - * Returns a comparator for sorting hits according to a field containing integers. - * @param reader Index to use. - * @param fieldname Fieldable containg integer values. - * @return Comparator for sorting hits. - * @throws IOException If an error occurs reading the index. - */ - static ScoreDocComparator comparatorInt (final IndexReader reader, final String fieldname) - throws IOException { - final String field = fieldname.intern(); - final int[] fieldOrder = FieldCache.DEFAULT.getInts (reader, field); - return new ScoreDocComparator() { - - public final int compare (final ScoreDoc i, final ScoreDoc j) { - final int fi = fieldOrder[i.doc]; - final int fj = fieldOrder[j.doc]; - if (fi < fj) return -1; - if (fi > fj) return 1; - return 0; - } - - public Comparable sortValue (final ScoreDoc i) { - return new Integer (fieldOrder[i.doc]); - } - - public int sortType() { - return SortField.INT; - } - }; - } - - /** - * Returns a comparator for sorting hits according to a field containing integers. - * @param reader Index to use. - * @param fieldname Fieldable containg integer values. - * @return Comparator for sorting hits. - * @throws IOException If an error occurs reading the index. - */ - static ScoreDocComparator comparatorLong (final IndexReader reader, final String fieldname) - throws IOException { - final String field = fieldname.intern(); - final long[] fieldOrder = ExtendedFieldCache.EXT_DEFAULT.getLongs (reader, field); - return new ScoreDocComparator() { - - public final int compare (final ScoreDoc i, final ScoreDoc j) { - final long li = fieldOrder[i.doc]; - final long lj = fieldOrder[j.doc]; - if (li < lj) return -1; - if (li > lj) return 1; - return 0; - } - - public Comparable sortValue (final ScoreDoc i) { - return new Long(fieldOrder[i.doc]); - } - - public int sortType() { - return SortField.LONG; - } - }; - } - - - /** - * Returns a comparator for sorting hits according to a field containing floats. - * @param reader Index to use. - * @param fieldname Fieldable containg float values. - * @return Comparator for sorting hits. - * @throws IOException If an error occurs reading the index. - */ - static ScoreDocComparator comparatorFloat (final IndexReader reader, final String fieldname) - throws IOException { - final String field = fieldname.intern(); - final float[] fieldOrder = FieldCache.DEFAULT.getFloats (reader, field); - return new ScoreDocComparator () { - - public final int compare (final ScoreDoc i, final ScoreDoc j) { - final float fi = fieldOrder[i.doc]; - final float fj = fieldOrder[j.doc]; - if (fi < fj) return -1; - if (fi > fj) return 1; - return 0; - } - - public Comparable sortValue (final ScoreDoc i) { - return new Float (fieldOrder[i.doc]); - } - - public int sortType() { - return SortField.FLOAT; - } - }; - } - - /** - * Returns a comparator for sorting hits according to a field containing doubles. - * @param reader Index to use. - * @param fieldname Fieldable containg float values. - * @return Comparator for sorting hits. - * @throws IOException If an error occurs reading the index. - */ - static ScoreDocComparator comparatorDouble(final IndexReader reader, final String fieldname) - throws IOException { - final String field = fieldname.intern(); - final double[] fieldOrder = ExtendedFieldCache.EXT_DEFAULT.getDoubles (reader, field); - return new ScoreDocComparator () { - - public final int compare (final ScoreDoc i, final ScoreDoc j) { - final double di = fieldOrder[i.doc]; - final double dj = fieldOrder[j.doc]; - if (di < dj) return -1; - if (di > dj) return 1; - return 0; - } - - public Comparable sortValue (final ScoreDoc i) { - return new Double (fieldOrder[i.doc]); - } - - public int sortType() { - return SortField.DOUBLE; - } - }; - } - - /** - * Returns a comparator for sorting hits according to a field containing strings. - * @param reader Index to use. - * @param fieldname Fieldable containg string values. - * @return Comparator for sorting hits. - * @throws IOException If an error occurs reading the index. - */ - static ScoreDocComparator comparatorString (final IndexReader reader, final String fieldname) - throws IOException { - final String field = fieldname.intern(); - final FieldCache.StringIndex index = FieldCache.DEFAULT.getStringIndex (reader, field); - return new ScoreDocComparator () { - - public final int compare (final ScoreDoc i, final ScoreDoc j) { - final int fi = index.order[i.doc]; - final int fj = index.order[j.doc]; - if (fi < fj) return -1; - if (fi > fj) return 1; - return 0; - } - - public Comparable sortValue (final ScoreDoc i) { - return index.lookup[index.order[i.doc]]; - } - - public int sortType() { - return SortField.STRING; - } - }; - } - - /** - * Returns a comparator for sorting hits according to a field containing strings. - * @param reader Index to use. - * @param fieldname Fieldable containg string values. - * @return Comparator for sorting hits. - * @throws IOException If an error occurs reading the index. - */ - static ScoreDocComparator comparatorStringLocale (final IndexReader reader, final String fieldname, final Locale locale) - throws IOException { - final Collator collator = Collator.getInstance (locale); - final String field = fieldname.intern(); - final String[] index = FieldCache.DEFAULT.getStrings (reader, field); - return new ScoreDocComparator() { - - public final int compare(final ScoreDoc i, final ScoreDoc j) { - String is = index[i.doc]; - String js = index[j.doc]; - if (is == js) { - return 0; - } else if (is == null) { - return -1; - } else if (js == null) { - return 1; - } else { - return collator.compare(is, js); - } - } - - public Comparable sortValue (final ScoreDoc i) { - return index[i.doc]; - } - - public int sortType() { - return SortField.STRING; - } - }; - } - - /** - * 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. - * @param reader Index to use. - * @param fieldname Fieldable containg values. - * @return Comparator for sorting hits. - * @throws IOException If an error occurs reading the index. - */ - static ScoreDocComparator comparatorAuto (final IndexReader reader, final String fieldname) - throws IOException { - final String field = fieldname.intern(); - Object lookupArray = ExtendedFieldCache.EXT_DEFAULT.getAuto (reader, field); - if (lookupArray instanceof FieldCache.StringIndex) { - return comparatorString (reader, field); - } else if (lookupArray instanceof int[]) { - return comparatorInt (reader, field); - } else if (lookupArray instanceof long[]) { - return comparatorLong (reader, field); - } else if (lookupArray instanceof float[]) { - return comparatorFloat (reader, field); - } else if (lookupArray instanceof String[]) { - return comparatorString (reader, field); - } else { - throw new RuntimeException ("unknown data type in field '"+field+"'"); - } - } } Index: C:/workspace/lucene-trunk/src/java/org/apache/lucene/search/AutoComparatorSource.java =================================================================== --- C:/workspace/lucene-trunk/src/java/org/apache/lucene/search/AutoComparatorSource.java (revision 0) +++ C:/workspace/lucene-trunk/src/java/org/apache/lucene/search/AutoComparatorSource.java (revision 0) @@ -0,0 +1,88 @@ +package org.apache.lucene.search; + +/** + * 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. + */ + +import java.io.IOException; +import java.util.Locale; +import java.util.Map; + +import org.apache.lucene.index.IndexReader; + +/** + * SortComparatorSource which produces an appropriate comparator for sorting + * hits by examining the values in the given field and choosing another + * SortComparatorSource implementation accordingly. + */ +public class AutoComparatorSource implements SortComparatorSource { + private static final long serialVersionUID = 1L; + + /** + * Maps field types (constant Integer values from SortField) to appropriate + * SortComparatorSources + */ + private final Map comparatorSources; + + /** + * Builds an AutoComparatorSource, using the given Map as a source for + * comparators to delegate to. + * + * @param comparatorSources maps Integer field types (from SortField) to an + * appropriate SortComparatorSource + */ + public AutoComparatorSource(Map comparatorSources) { + this.comparatorSources = comparatorSources; + } + + /** + * 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 + * this class' other SourceComparatorSources is used to get the comparator. + * + * @param reader Index to use. + * @param fieldname Fieldable containing values + * @param locale locale to use for sorting, if required + * @return Comparator for sorting hits. + * @throws IOException If an error occurs reading the index. + */ + public ScoreDocComparator newComparator(IndexReader reader, String fieldname, + Locale locale) throws IOException { + final String field = fieldname.intern(); + Object lookupArray = ExtendedFieldCache.EXT_DEFAULT.getAuto(reader, field); + if (lookupArray instanceof FieldCache.StringIndex) { + return getComparator(SortField.STRING, reader, field, locale); + } else if (lookupArray instanceof int[]) { + return getComparator(SortField.INT, reader, field, locale); + } else if (lookupArray instanceof long[]) { + return getComparator(SortField.LONG, reader, field, locale); + } else if (lookupArray instanceof float[]) { + return getComparator(SortField.FLOAT, reader, field, locale); + } else if (lookupArray instanceof String[]) { + return getComparator(SortField.STRING, reader, field, locale); + } else { + throw new RuntimeException("unknown data type in field '" + field + "'"); + } + } + + private ScoreDocComparator getComparator(int fieldType, IndexReader reader, + String field, Locale locale) throws IOException { + SortComparatorSource source = (SortComparatorSource) comparatorSources + .get(new Integer(fieldType)); + return source.newComparator(reader, field, locale); + } +} Index: C:/workspace/lucene-trunk/src/java/org/apache/lucene/search/StringComparatorSource.java =================================================================== --- C:/workspace/lucene-trunk/src/java/org/apache/lucene/search/StringComparatorSource.java (revision 0) +++ C:/workspace/lucene-trunk/src/java/org/apache/lucene/search/StringComparatorSource.java (revision 0) @@ -0,0 +1,121 @@ +package org.apache.lucene.search; + +/** + * 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. + */ + +import java.io.IOException; +import java.text.Collator; +import java.util.Locale; + +import org.apache.lucene.index.IndexReader; + +/** + * SortComparatorSource which sorts hits by String comparison, either using a + * simple comparison or by a Locale-specific collator if a Locale-based sort is + * requested. + */ +public class StringComparatorSource implements SortComparatorSource { + private static final long serialVersionUID = 1L; + + /** + * Returns a comparator for sorting hits according to a field containing + * strings. + * + * @param reader Index to use. + * @param fieldname Fieldable containing string values. + * @param locale locale to use for sorting + * @return Comparator for sorting hits. + * @throws IOException If an error occurs reading the index. + */ + public ScoreDocComparator newComparator(IndexReader reader, String fieldname, + Locale locale) throws IOException { + final String field = fieldname.intern(); + if (locale == null) { + final FieldCache.StringIndex index = FieldCache.DEFAULT.getStringIndex( + reader, field); + return newLocaleInsensitiveComparator(index); + } else { + final String[] index = FieldCache.DEFAULT.getStrings(reader, field); + return newLocaleSensitiveComparator(index, locale); + } + } + + private ScoreDocComparator newLocaleSensitiveComparator( + final String[] index, Locale locale) { + final CollatorProvider collatorProvider = getCollatorProvider(locale); + + return new ScoreDocComparator() { + public final int compare(final ScoreDoc i, final ScoreDoc j) { + String is = index[i.doc]; + String js = index[j.doc]; + if (is == js) { + return 0; + } else if (is == null) { + return -1; + } else if (js == null) { + return 1; + } else { + return collatorProvider.getCollator().compare(is, js); + } + } + + public Comparable sortValue(final ScoreDoc i) { + return index[i.doc]; + } + + public int sortType() { + return SortField.STRING; + } + }; + } + + protected CollatorProvider getCollatorProvider(Locale locale) { + final Collator collator = Collator.getInstance(locale); + return new CollatorProvider() { + public Collator getCollator() { + return collator; + } + }; + } + + private ScoreDocComparator newLocaleInsensitiveComparator( + final FieldCache.StringIndex index) { + return new ScoreDocComparator() { + public final int compare(final ScoreDoc i, final ScoreDoc j) { + final int fi = index.order[i.doc]; + final int fj = index.order[j.doc]; + if (fi < fj) + return -1; + if (fi > fj) + return 1; + return 0; + } + + public Comparable sortValue(final ScoreDoc i) { + return index.lookup[index.order[i.doc]]; + } + + public int sortType() { + return SortField.STRING; + } + }; + } + + public static interface CollatorProvider { + public Collator getCollator(); + } +} \ No newline at end of file