blob: 8ce6a94b70164a2651cd46d974ffb93ad2770325 [file] [log] [blame]
/**
* 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.
*/
package org.apache.solr.search;
import org.apache.lucene.search.*;
import org.apache.lucene.index.IndexReader;
import java.io.IOException;
public class MissingStringLastComparatorSource extends FieldComparatorSource {
public static final String bigString="\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffffNULL_VAL";
private final String missingValueProxy;
public MissingStringLastComparatorSource() {
this(bigString);
}
/** Creates a {@link FieldComparatorSource} that uses <tt>missingValueProxy</tt> as the value to return from ScoreDocComparator.sortValue()
* which is only used my multisearchers to determine how to collate results from their searchers.
*
* @param missingValueProxy The value returned when sortValue() is called for a document missing the sort field.
* This value is *not* normally used for sorting, but used to create
*/
public MissingStringLastComparatorSource(String missingValueProxy) {
this.missingValueProxy=missingValueProxy;
}
@Override
public FieldComparator newComparator(String fieldname, int numHits, int sortPos, boolean reversed) throws IOException {
return new MissingLastOrdComparator(numHits, fieldname, sortPos, reversed, missingValueProxy);
}
}
// Copied from Lucene and modified since the Lucene version couldn't
// be extended or have it's values accessed.
class MissingLastOrdComparator extends FieldComparator<String> {
private static final int NULL_ORD = Integer.MAX_VALUE;
private final String nullVal;
private final int[] ords;
private final String[] values;
private final int[] readerGen;
private int currentReaderGen = -1;
private String[] lookup;
private int[] order;
private final String field;
private int bottomSlot = -1;
private int bottomOrd;
private String bottomValue;
private final boolean reversed;
private final int sortPos;
public MissingLastOrdComparator(int numHits, String field, int sortPos, boolean reversed, String nullVal) {
ords = new int[numHits];
values = new String[numHits];
readerGen = new int[numHits];
this.sortPos = sortPos;
this.reversed = reversed;
this.field = field;
this.nullVal = nullVal;
}
@Override
public int compare(int slot1, int slot2) {
if (readerGen[slot1] == readerGen[slot2]) {
int cmp = ords[slot1] - ords[slot2];
if (cmp != 0) {
return cmp;
}
}
final String val1 = values[slot1];
final String val2 = values[slot2];
if (val1 == null) {
if (val2 == null) {
return 0;
}
return 1;
} else if (val2 == null) {
return -1;
}
return val1.compareTo(val2);
}
@Override
public int compareValues(String first, String second) {
if (first == null) {
if (second == null) {
return 0;
} else {
return 1;
}
} else if (second == null) {
return -1;
} else {
return first.compareTo(second);
}
}
@Override
public int compareBottom(int doc) {
assert bottomSlot != -1;
int order = this.order[doc];
int ord = (order == 0) ? NULL_ORD : order;
final int cmp = bottomOrd - ord;
if (cmp != 0) {
return cmp;
}
final String val2 = lookup[order];
// take care of the case where both vals are null
if (bottomValue == val2) return 0;
return bottomValue.compareTo(val2);
}
private void convert(int slot) {
readerGen[slot] = currentReaderGen;
int index = 0;
String value = values[slot];
if (value == null) {
// should already be done
// ords[slot] = NULL_ORD;
return;
}
if (sortPos == 0 && bottomSlot != -1 && bottomSlot != slot) {
// Since we are the primary sort, the entries in the
// queue are bounded by bottomOrd:
assert bottomOrd < lookup.length;
if (reversed) {
index = binarySearch(lookup, value, bottomOrd, lookup.length-1);
} else {
index = binarySearch(lookup, value, 0, bottomOrd);
}
} else {
// Full binary search
index = binarySearch(lookup, value);
}
if (index < 0) {
index = -index - 2;
}
ords[slot] = index;
}
@Override
public void copy(int slot, int doc) {
final int ord = order[doc];
ords[slot] = ord == 0 ? NULL_ORD : ord;
assert ord >= 0;
values[slot] = lookup[ord];
readerGen[slot] = currentReaderGen;
}
@Override
public void setNextReader(IndexReader reader, int docBase) throws IOException {
FieldCache.StringIndex currentReaderValues = FieldCache.DEFAULT.getStringIndex(reader, field);
currentReaderGen++;
order = currentReaderValues.order;
lookup = currentReaderValues.lookup;
assert lookup.length > 0;
if (bottomSlot != -1) {
convert(bottomSlot);
bottomOrd = ords[bottomSlot];
}
}
@Override
public void setBottom(final int bottom) {
bottomSlot = bottom;
if (readerGen[bottom] != currentReaderGen) {
convert(bottomSlot);
}
bottomOrd = ords[bottom];
assert bottomOrd >= 0;
// assert bottomOrd < lookup.length;
bottomValue = values[bottom];
}
@Override
public String value(int slot) {
String v = values[slot];
return v==null ? nullVal : v;
}
public String[] getValues() {
return values;
}
public int getBottomSlot() {
return bottomSlot;
}
public String getField() {
return field;
}
}