001: /**
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */package org.apache.solr.search;
017:
018: import org.apache.lucene.search.*;
019: import org.apache.lucene.index.IndexReader;
020:
021: import java.io.IOException;
022:
023: /**
024: * A {@link SortComparatorSource} for strings that orders null values after non-null values.
025: * Based on FieldSortedHitQueue.comparatorString
026: * <p>
027: *
028: * @author Chris Hostetter
029: * @author yonik
030: * @version $Id: MissingStringLastComparatorSource.java 472574 2006-11-08 18:25:52Z yonik $
031: *
032: */
033:
034: // move to apache package and make public if it is accepted as a patch
035: class MissingStringLastComparatorSource implements SortComparatorSource {
036:
037: public static final String bigString = "\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffffNULL_VAL";
038:
039: private final String missingValueProxy;
040:
041: public MissingStringLastComparatorSource() {
042: this (bigString);
043: }
044:
045: /**
046: * Returns the value used to sort the given document. The
047: * object returned must implement the java.io.Serializable
048: * interface. This is used by multisearchers to determine how to collate results from their searchers.
049: * @see FieldDoc
050: * @param i Document
051: * @return Serializable object
052: */
053:
054: /** Creates a {@link SortComparatorSource} that uses <tt>missingValueProxy</tt> as the value to return from ScoreDocComparator.sortValue()
055: * which is only used my multisearchers to determine how to collate results from their searchers.
056: *
057: * @param missingValueProxy The value returned when sortValue() is called for a document missing the sort field.
058: * This value is *not* normally used for sorting, but used to create
059: */
060: public MissingStringLastComparatorSource(String missingValueProxy) {
061: this .missingValueProxy = missingValueProxy;
062: }
063:
064: public ScoreDocComparator newComparator(final IndexReader reader,
065: final String fieldname) throws IOException {
066:
067: final String field = fieldname.intern();
068: final FieldCache.StringIndex index = FieldCache.DEFAULT
069: .getStringIndex(reader, field);
070:
071: // :HACK:
072: // final String lastString =
073: // (index.lookup[index.lookup.length-1]+"X").intern();
074: //
075: // Note: basing lastStringValue on the StringIndex won't work
076: // with a multisearcher.
077:
078: return new ScoreDocComparator() {
079:
080: public final int compare(final ScoreDoc i, final ScoreDoc j) {
081: final int fi = index.order[i.doc];
082: final int fj = index.order[j.doc];
083:
084: // 0 is the magic position of null
085:
086: /**** alternate logic
087: if (fi < fj && fi != 0) return -1;
088: if (fj < fi && fj != 0) return 1;
089: if (fi==fj) return 0;
090: return fi==0 ? 1 : -1;
091: ****/
092:
093: if (fi == fj)
094: return 0;
095: if (fi == 0)
096: return 1;
097: if (fj == 0)
098: return -1;
099: return fi < fj ? -1 : 1;
100:
101: }
102:
103: public Comparable sortValue(final ScoreDoc i) {
104: int f = index.order[i.doc];
105: return (0 == f) ? missingValueProxy : index.lookup[f];
106: }
107:
108: public int sortType() {
109: return SortField.CUSTOM;
110: }
111: };
112:
113: }
114: }
|